LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_aka.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 537 678 79.2 %
Date: 2016-10-02 Functions: 36 36 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
       3             :  * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "crypto/sha256.h"
      13             : #include "crypto/crypto.h"
      14             : #include "crypto/random.h"
      15             : #include "eap_common/eap_sim_common.h"
      16             : #include "eap_server/eap_i.h"
      17             : #include "eap_server/eap_sim_db.h"
      18             : 
      19             : 
      20             : struct eap_aka_data {
      21             :         u8 mk[EAP_SIM_MK_LEN];
      22             :         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
      23             :         u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
      24             :         u8 k_encr[EAP_SIM_K_ENCR_LEN];
      25             :         u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
      26             :         u8 msk[EAP_SIM_KEYING_DATA_LEN];
      27             :         u8 emsk[EAP_EMSK_LEN];
      28             :         u8 rand[EAP_AKA_RAND_LEN];
      29             :         u8 autn[EAP_AKA_AUTN_LEN];
      30             :         u8 ck[EAP_AKA_CK_LEN];
      31             :         u8 ik[EAP_AKA_IK_LEN];
      32             :         u8 res[EAP_AKA_RES_MAX_LEN];
      33             :         size_t res_len;
      34             :         enum {
      35             :                 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
      36             :         } state;
      37             :         char *next_pseudonym;
      38             :         char *next_reauth_id;
      39             :         u16 counter;
      40             :         struct eap_sim_reauth *reauth;
      41             :         int auts_reported; /* whether the current AUTS has been reported to the
      42             :                             * eap_sim_db */
      43             :         u16 notification;
      44             :         int use_result_ind;
      45             : 
      46             :         struct wpabuf *id_msgs;
      47             :         int pending_id;
      48             :         u8 eap_method;
      49             :         u8 *network_name;
      50             :         size_t network_name_len;
      51             :         u16 kdf;
      52             :         int identity_round;
      53             :         char permanent[20]; /* Permanent username */
      54             : };
      55             : 
      56             : 
      57             : static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
      58             : 
      59             : 
      60         346 : static const char * eap_aka_state_txt(int state)
      61             : {
      62         346 :         switch (state) {
      63             :         case IDENTITY:
      64          81 :                 return "IDENTITY";
      65             :         case CHALLENGE:
      66         135 :                 return "CHALLENGE";
      67             :         case REAUTH:
      68          37 :                 return "REAUTH";
      69             :         case SUCCESS:
      70          48 :                 return "SUCCESS";
      71             :         case FAILURE:
      72          26 :                 return "FAILURE";
      73             :         case NOTIFICATION:
      74          19 :                 return "NOTIFICATION";
      75             :         default:
      76           0 :                 return "Unknown?!";
      77             :         }
      78             : }
      79             : 
      80             : 
      81         173 : static void eap_aka_state(struct eap_aka_data *data, int state)
      82             : {
      83         346 :         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
      84         173 :                    eap_aka_state_txt(data->state),
      85             :                    eap_aka_state_txt(state));
      86         173 :         data->state = state;
      87         173 : }
      88             : 
      89             : 
      90         213 : static int eap_aka_check_identity_reauth(struct eap_sm *sm,
      91             :                                          struct eap_aka_data *data,
      92             :                                          const char *username)
      93             : {
      94         277 :         if (data->eap_method == EAP_TYPE_AKA_PRIME &&
      95          64 :             username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
      96          51 :                 return 0;
      97         311 :         if (data->eap_method == EAP_TYPE_AKA &&
      98         149 :             username[0] != EAP_AKA_REAUTH_ID_PREFIX)
      99         135 :                 return 0;
     100             : 
     101          27 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
     102          27 :         data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
     103             :                                                    username);
     104          27 :         if (data->reauth == NULL) {
     105           8 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
     106             :                            "request full auth identity");
     107             :                 /* Remain in IDENTITY state for another round */
     108           8 :                 return 0;
     109             :         }
     110             : 
     111          19 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
     112          19 :         os_strlcpy(data->permanent, data->reauth->permanent,
     113             :                    sizeof(data->permanent));
     114          19 :         data->counter = data->reauth->counter;
     115          19 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     116           9 :                 os_memcpy(data->k_encr, data->reauth->k_encr,
     117             :                           EAP_SIM_K_ENCR_LEN);
     118           9 :                 os_memcpy(data->k_aut, data->reauth->k_aut,
     119             :                           EAP_AKA_PRIME_K_AUT_LEN);
     120           9 :                 os_memcpy(data->k_re, data->reauth->k_re,
     121             :                           EAP_AKA_PRIME_K_RE_LEN);
     122             :         } else {
     123          10 :                 os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
     124             :         }
     125             : 
     126          19 :         eap_aka_state(data, REAUTH);
     127          19 :         return 1;
     128             : }
     129             : 
     130             : 
     131          84 : static void eap_aka_check_identity(struct eap_sm *sm,
     132             :                                    struct eap_aka_data *data)
     133             : {
     134             :         char *username;
     135             : 
     136             :         /* Check if we already know the identity from EAP-Response/Identity */
     137             : 
     138          84 :         username = sim_get_username(sm->identity, sm->identity_len);
     139          84 :         if (username == NULL)
     140           0 :                 return;
     141             : 
     142          84 :         if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
     143          19 :                 os_free(username);
     144             :                 /*
     145             :                  * Since re-auth username was recognized, skip AKA/Identity
     146             :                  * exchange.
     147             :                  */
     148          19 :                 return;
     149             :         }
     150             : 
     151          83 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     152          83 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     153         112 :             (data->eap_method == EAP_TYPE_AKA &&
     154          47 :              username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
     155             :                 const char *permanent;
     156           3 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
     157             :                            username);
     158           3 :                 permanent = eap_sim_db_get_permanent(
     159             :                         sm->eap_sim_db_priv, username);
     160           3 :                 if (permanent == NULL) {
     161           1 :                         os_free(username);
     162           1 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
     163             :                                    "identity - request permanent identity");
     164             :                         /* Remain in IDENTITY state for another round */
     165           1 :                         return;
     166             :                 }
     167           2 :                 os_strlcpy(data->permanent, permanent,
     168             :                            sizeof(data->permanent));
     169             :                 /*
     170             :                  * Since pseudonym username was recognized, skip AKA/Identity
     171             :                  * exchange.
     172             :                  */
     173           2 :                 eap_aka_fullauth(sm, data);
     174             :         }
     175             : 
     176          64 :         os_free(username);
     177             : }
     178             : 
     179             : 
     180          57 : static void * eap_aka_init(struct eap_sm *sm)
     181             : {
     182             :         struct eap_aka_data *data;
     183             : 
     184          57 :         if (sm->eap_sim_db_priv == NULL) {
     185           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
     186           0 :                 return NULL;
     187             :         }
     188             : 
     189          57 :         data = os_zalloc(sizeof(*data));
     190          57 :         if (data == NULL)
     191           0 :                 return NULL;
     192             : 
     193          57 :         data->eap_method = EAP_TYPE_AKA;
     194             : 
     195          57 :         data->state = IDENTITY;
     196          57 :         data->pending_id = -1;
     197          57 :         eap_aka_check_identity(sm, data);
     198             : 
     199          57 :         return data;
     200             : }
     201             : 
     202             : 
     203             : #ifdef EAP_SERVER_AKA_PRIME
     204          27 : static void * eap_aka_prime_init(struct eap_sm *sm)
     205             : {
     206             :         struct eap_aka_data *data;
     207             :         /* TODO: make ANID configurable; see 3GPP TS 24.302 */
     208          27 :         char *network_name = "WLAN";
     209             : 
     210          27 :         if (sm->eap_sim_db_priv == NULL) {
     211           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
     212           0 :                 return NULL;
     213             :         }
     214             : 
     215          27 :         data = os_zalloc(sizeof(*data));
     216          27 :         if (data == NULL)
     217           0 :                 return NULL;
     218             : 
     219          27 :         data->eap_method = EAP_TYPE_AKA_PRIME;
     220          27 :         data->network_name = (u8 *) os_strdup(network_name);
     221          27 :         if (data->network_name == NULL) {
     222           0 :                 os_free(data);
     223           0 :                 return NULL;
     224             :         }
     225             : 
     226          27 :         data->network_name_len = os_strlen(network_name);
     227             : 
     228          27 :         data->state = IDENTITY;
     229          27 :         data->pending_id = -1;
     230          27 :         eap_aka_check_identity(sm, data);
     231             : 
     232          27 :         return data;
     233             : }
     234             : #endif /* EAP_SERVER_AKA_PRIME */
     235             : 
     236             : 
     237          84 : static void eap_aka_reset(struct eap_sm *sm, void *priv)
     238             : {
     239          84 :         struct eap_aka_data *data = priv;
     240          84 :         os_free(data->next_pseudonym);
     241          84 :         os_free(data->next_reauth_id);
     242          84 :         wpabuf_free(data->id_msgs);
     243          84 :         os_free(data->network_name);
     244          84 :         bin_clear_free(data, sizeof(*data));
     245          84 : }
     246             : 
     247             : 
     248         138 : static int eap_aka_add_id_msg(struct eap_aka_data *data,
     249             :                               const struct wpabuf *msg)
     250             : {
     251         138 :         if (msg == NULL)
     252           0 :                 return -1;
     253             : 
     254         138 :         if (data->id_msgs == NULL) {
     255          63 :                 data->id_msgs = wpabuf_dup(msg);
     256          63 :                 return data->id_msgs == NULL ? -1 : 0;
     257             :         }
     258             : 
     259          75 :         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
     260           0 :                 return -1;
     261          75 :         wpabuf_put_buf(data->id_msgs, msg);
     262             : 
     263          75 :         return 0;
     264             : }
     265             : 
     266             : 
     267          88 : static void eap_aka_add_checkcode(struct eap_aka_data *data,
     268             :                                   struct eap_sim_msg *msg)
     269             : {
     270             :         const u8 *addr;
     271             :         size_t len;
     272             :         u8 hash[SHA256_MAC_LEN];
     273             : 
     274          88 :         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
     275             : 
     276          88 :         if (data->id_msgs == NULL) {
     277             :                 /*
     278             :                  * No EAP-AKA/Identity packets were exchanged - send empty
     279             :                  * checkcode.
     280             :                  */
     281          22 :                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
     282         110 :                 return;
     283             :         }
     284             : 
     285             :         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
     286          66 :         addr = wpabuf_head(data->id_msgs);
     287          66 :         len = wpabuf_len(data->id_msgs);
     288          66 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
     289          66 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     290          17 :                 sha256_vector(1, &addr, &len, hash);
     291             :         else
     292          49 :                 sha1_vector(1, &addr, &len, hash);
     293             : 
     294          66 :         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
     295          66 :                         data->eap_method == EAP_TYPE_AKA_PRIME ?
     296             :                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
     297             : }
     298             : 
     299             : 
     300          38 : static int eap_aka_verify_checkcode(struct eap_aka_data *data,
     301             :                                     const u8 *checkcode, size_t checkcode_len)
     302             : {
     303             :         const u8 *addr;
     304             :         size_t len;
     305             :         u8 hash[SHA256_MAC_LEN];
     306             :         size_t hash_len;
     307             : 
     308          38 :         if (checkcode == NULL)
     309           0 :                 return -1;
     310             : 
     311          38 :         if (data->id_msgs == NULL) {
     312           2 :                 if (checkcode_len != 0) {
     313           0 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer "
     314             :                                    "indicates that AKA/Identity messages were "
     315             :                                    "used, but they were not");
     316           0 :                         return -1;
     317             :                 }
     318           2 :                 return 0;
     319             :         }
     320             : 
     321          36 :         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
     322             :                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
     323             : 
     324          36 :         if (checkcode_len != hash_len) {
     325           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
     326             :                            "that AKA/Identity message were not used, but they "
     327             :                            "were");
     328           0 :                 return -1;
     329             :         }
     330             : 
     331             :         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
     332          36 :         addr = wpabuf_head(data->id_msgs);
     333          36 :         len = wpabuf_len(data->id_msgs);
     334          36 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     335          13 :                 sha256_vector(1, &addr, &len, hash);
     336             :         else
     337          23 :                 sha1_vector(1, &addr, &len, hash);
     338             : 
     339          36 :         if (os_memcmp_const(hash, checkcode, hash_len) != 0) {
     340           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
     341           0 :                 return -1;
     342             :         }
     343             : 
     344          36 :         return 0;
     345             : }
     346             : 
     347             : 
     348          70 : static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm,
     349             :                                               struct eap_aka_data *data, u8 id)
     350             : {
     351             :         struct eap_sim_msg *msg;
     352             :         struct wpabuf *buf;
     353             : 
     354          70 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
     355          70 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     356             :                                EAP_AKA_SUBTYPE_IDENTITY);
     357          70 :         data->identity_round++;
     358          70 :         if (data->identity_round == 1) {
     359             :                 /*
     360             :                  * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
     361             :                  * ignored and the AKA/Identity is used to request the
     362             :                  * identity.
     363             :                  */
     364          63 :                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
     365          63 :                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
     366           7 :         } else if (data->identity_round > 3) {
     367             :                 /* Cannot use more than three rounds of Identity messages */
     368           0 :                 eap_sim_msg_free(msg);
     369           0 :                 return NULL;
     370          14 :         } else if (sm->identity && sm->identity_len > 0 &&
     371          12 :                    (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
     372           5 :                     sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
     373             :                 /* Reauth id may have expired - try fullauth */
     374           4 :                 wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
     375           4 :                 eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
     376             :         } else {
     377           3 :                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
     378           3 :                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
     379             :         }
     380          70 :         buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
     381          70 :         if (eap_aka_add_id_msg(data, buf) < 0) {
     382           0 :                 wpabuf_free(buf);
     383           0 :                 return NULL;
     384             :         }
     385          70 :         data->pending_id = id;
     386          70 :         return buf;
     387             : }
     388             : 
     389             : 
     390          88 : static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
     391             :                               struct eap_sim_msg *msg, u16 counter,
     392             :                               const u8 *nonce_s)
     393             : {
     394          88 :         os_free(data->next_pseudonym);
     395          88 :         if (nonce_s == NULL) {
     396          69 :                 data->next_pseudonym =
     397          69 :                         eap_sim_db_get_next_pseudonym(
     398             :                                 sm->eap_sim_db_priv,
     399          69 :                                 data->eap_method == EAP_TYPE_AKA_PRIME ?
     400             :                                 EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
     401             :         } else {
     402             :                 /* Do not update pseudonym during re-authentication */
     403          19 :                 data->next_pseudonym = NULL;
     404             :         }
     405          88 :         os_free(data->next_reauth_id);
     406          88 :         if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
     407          86 :                 data->next_reauth_id =
     408          86 :                         eap_sim_db_get_next_reauth_id(
     409             :                                 sm->eap_sim_db_priv,
     410          86 :                                 data->eap_method == EAP_TYPE_AKA_PRIME ?
     411             :                                 EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA);
     412             :         } else {
     413           2 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
     414             :                            "count exceeded - force full authentication");
     415           2 :                 data->next_reauth_id = NULL;
     416             :         }
     417             : 
     418          88 :         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
     419           0 :             counter == 0 && nonce_s == NULL)
     420           0 :                 return 0;
     421             : 
     422          88 :         wpa_printf(MSG_DEBUG, "   AT_IV");
     423          88 :         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     424          88 :         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
     425             : 
     426          88 :         if (counter > 0) {
     427          19 :                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
     428          19 :                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
     429             :         }
     430             : 
     431          88 :         if (nonce_s) {
     432          19 :                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
     433          19 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
     434             :                                 EAP_SIM_NONCE_S_LEN);
     435             :         }
     436             : 
     437          88 :         if (data->next_pseudonym) {
     438          69 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
     439             :                            data->next_pseudonym);
     440         138 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
     441          69 :                                 os_strlen(data->next_pseudonym),
     442          69 :                                 (u8 *) data->next_pseudonym,
     443          69 :                                 os_strlen(data->next_pseudonym));
     444             :         }
     445             : 
     446          88 :         if (data->next_reauth_id) {
     447          86 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
     448             :                            data->next_reauth_id);
     449         172 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
     450          86 :                                 os_strlen(data->next_reauth_id),
     451          86 :                                 (u8 *) data->next_reauth_id,
     452          86 :                                 os_strlen(data->next_reauth_id));
     453             :         }
     454             : 
     455          88 :         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
     456           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
     457             :                            "AT_ENCR_DATA");
     458           0 :                 return -1;
     459             :         }
     460             : 
     461          88 :         return 0;
     462             : }
     463             : 
     464             : 
     465          69 : static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm,
     466             :                                                struct eap_aka_data *data,
     467             :                                                u8 id)
     468             : {
     469             :         struct eap_sim_msg *msg;
     470             : 
     471          69 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
     472          69 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     473             :                                EAP_AKA_SUBTYPE_CHALLENGE);
     474          69 :         wpa_printf(MSG_DEBUG, "   AT_RAND");
     475          69 :         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
     476          69 :         wpa_printf(MSG_DEBUG, "   AT_AUTN");
     477          69 :         eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
     478          69 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     479          18 :                 if (data->kdf) {
     480             :                         /* Add the selected KDF into the beginning */
     481           0 :                         wpa_printf(MSG_DEBUG, "   AT_KDF");
     482           0 :                         eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
     483             :                                         NULL, 0);
     484             :                 }
     485          18 :                 wpa_printf(MSG_DEBUG, "   AT_KDF");
     486          18 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
     487             :                                 NULL, 0);
     488          18 :                 wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
     489          36 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
     490          18 :                                 data->network_name_len,
     491          18 :                                 data->network_name, data->network_name_len);
     492             :         }
     493             : 
     494          69 :         if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
     495           0 :                 eap_sim_msg_free(msg);
     496           0 :                 return NULL;
     497             :         }
     498             : 
     499          69 :         eap_aka_add_checkcode(data, msg);
     500             : 
     501          69 :         if (sm->eap_sim_aka_result_ind) {
     502          66 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     503          66 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     504             :         }
     505             : 
     506             : #ifdef EAP_SERVER_AKA_PRIME
     507          69 :         if (data->eap_method == EAP_TYPE_AKA) {
     508          51 :                 u16 flags = 0;
     509             :                 int i;
     510          51 :                 int aka_prime_preferred = 0;
     511             : 
     512          51 :                 i = 0;
     513         153 :                 while (sm->user && i < EAP_MAX_METHODS &&
     514         102 :                        (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
     515          51 :                         sm->user->methods[i].method != EAP_TYPE_NONE)) {
     516          51 :                         if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
     517          51 :                                 if (sm->user->methods[i].method ==
     518             :                                     EAP_TYPE_AKA)
     519          51 :                                         break;
     520           0 :                                 if (sm->user->methods[i].method ==
     521             :                                     EAP_TYPE_AKA_PRIME) {
     522           0 :                                         aka_prime_preferred = 1;
     523           0 :                                         break;
     524             :                                 }
     525             :                         }
     526           0 :                         i++;
     527             :                 }
     528             : 
     529          51 :                 if (aka_prime_preferred)
     530           0 :                         flags |= EAP_AKA_BIDDING_FLAG_D;
     531          51 :                 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
     532             :         }
     533             : #endif /* EAP_SERVER_AKA_PRIME */
     534             : 
     535          69 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     536          69 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     537          69 :         return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
     538             : }
     539             : 
     540             : 
     541          19 : static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm,
     542             :                                             struct eap_aka_data *data, u8 id)
     543             : {
     544             :         struct eap_sim_msg *msg;
     545             : 
     546          19 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
     547             : 
     548          19 :         if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
     549           0 :                 return NULL;
     550          19 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
     551          19 :                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
     552             : 
     553          19 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     554          18 :                 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
     555           9 :                                                  sm->identity,
     556             :                                                  sm->identity_len,
     557           9 :                                                  data->nonce_s,
     558           9 :                                                  data->msk, data->emsk);
     559             :         } else {
     560          10 :                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
     561          10 :                                     data->msk, data->emsk);
     562          10 :                 eap_sim_derive_keys_reauth(data->counter, sm->identity,
     563          10 :                                            sm->identity_len, data->nonce_s,
     564          10 :                                            data->mk, data->msk, data->emsk);
     565             :         }
     566             : 
     567          19 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     568             :                                EAP_AKA_SUBTYPE_REAUTHENTICATION);
     569             : 
     570          19 :         if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
     571           0 :                 eap_sim_msg_free(msg);
     572           0 :                 return NULL;
     573             :         }
     574             : 
     575          19 :         eap_aka_add_checkcode(data, msg);
     576             : 
     577          19 :         if (sm->eap_sim_aka_result_ind) {
     578          19 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     579          19 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     580             :         }
     581             : 
     582          19 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     583          19 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     584          19 :         return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
     585             : }
     586             : 
     587             : 
     588          11 : static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm,
     589             :                                                   struct eap_aka_data *data,
     590             :                                                   u8 id)
     591             : {
     592             :         struct eap_sim_msg *msg;
     593             : 
     594          11 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
     595          11 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     596             :                                EAP_AKA_SUBTYPE_NOTIFICATION);
     597          11 :         wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
     598          11 :         eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
     599             :                         NULL, 0);
     600          11 :         if (data->use_result_ind) {
     601          11 :                 if (data->reauth) {
     602           5 :                         wpa_printf(MSG_DEBUG, "   AT_IV");
     603           5 :                         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     604           5 :                         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
     605             :                                                    EAP_SIM_AT_ENCR_DATA);
     606           5 :                         wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
     607           5 :                                    data->counter);
     608           5 :                         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
     609             :                                         NULL, 0);
     610             : 
     611           5 :                         if (eap_sim_msg_add_encr_end(msg, data->k_encr,
     612             :                                                      EAP_SIM_AT_PADDING)) {
     613           0 :                                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to "
     614             :                                            "encrypt AT_ENCR_DATA");
     615           0 :                                 eap_sim_msg_free(msg);
     616           0 :                                 return NULL;
     617             :                         }
     618             :                 }
     619             : 
     620          11 :                 wpa_printf(MSG_DEBUG, "   AT_MAC");
     621          11 :                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     622             :         }
     623          11 :         return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0);
     624             : }
     625             : 
     626             : 
     627         169 : static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
     628             : {
     629         169 :         struct eap_aka_data *data = priv;
     630             : 
     631         169 :         data->auts_reported = 0;
     632         169 :         switch (data->state) {
     633             :         case IDENTITY:
     634          70 :                 return eap_aka_build_identity(sm, data, id);
     635             :         case CHALLENGE:
     636          69 :                 return eap_aka_build_challenge(sm, data, id);
     637             :         case REAUTH:
     638          19 :                 return eap_aka_build_reauth(sm, data, id);
     639             :         case NOTIFICATION:
     640          11 :                 return eap_aka_build_notification(sm, data, id);
     641             :         default:
     642           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
     643           0 :                            "buildReq", data->state);
     644           0 :                 break;
     645             :         }
     646           0 :         return NULL;
     647             : }
     648             : 
     649             : 
     650         163 : static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
     651             :                              struct wpabuf *respData)
     652             : {
     653         163 :         struct eap_aka_data *data = priv;
     654             :         const u8 *pos;
     655             :         size_t len;
     656             : 
     657         163 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
     658             :                                &len);
     659         163 :         if (pos == NULL || len < 3) {
     660           0 :                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
     661           0 :                 return TRUE;
     662             :         }
     663             : 
     664         163 :         return FALSE;
     665             : }
     666             : 
     667             : 
     668         228 : static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
     669             : {
     670         228 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
     671             :             subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
     672          27 :                 return FALSE;
     673             : 
     674         201 :         switch (data->state) {
     675             :         case IDENTITY:
     676         129 :                 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
     677           0 :                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
     678             :                                    "subtype %d", subtype);
     679           0 :                         return TRUE;
     680             :                 }
     681         129 :                 break;
     682             :         case CHALLENGE:
     683          48 :                 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
     684             :                     subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
     685           0 :                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
     686             :                                    "subtype %d", subtype);
     687           0 :                         return TRUE;
     688             :                 }
     689          48 :                 break;
     690             :         case REAUTH:
     691          17 :                 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
     692           0 :                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
     693             :                                    "subtype %d", subtype);
     694           0 :                         return TRUE;
     695             :                 }
     696          17 :                 break;
     697             :         case NOTIFICATION:
     698           7 :                 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
     699           0 :                         wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
     700             :                                    "subtype %d", subtype);
     701           0 :                         return TRUE;
     702             :                 }
     703           7 :                 break;
     704             :         default:
     705           0 :                 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
     706           0 :                            "processing a response", data->state);
     707           0 :                 return TRUE;
     708             :         }
     709             : 
     710         201 :         return FALSE;
     711             : }
     712             : 
     713             : 
     714         129 : static void eap_aka_determine_identity(struct eap_sm *sm,
     715             :                                        struct eap_aka_data *data)
     716             : {
     717             :         char *username;
     718             : 
     719         258 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
     720         129 :                           sm->identity, sm->identity_len);
     721             : 
     722         129 :         username = sim_get_username(sm->identity, sm->identity_len);
     723         129 :         if (username == NULL) {
     724           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     725           0 :                 eap_aka_state(data, NOTIFICATION);
     726           0 :                 return;
     727             :         }
     728             : 
     729         129 :         if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
     730           0 :                 os_free(username);
     731           0 :                 return;
     732             :         }
     733             : 
     734         166 :         if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
     735         164 :               username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
     736         219 :              (data->eap_method == EAP_TYPE_AKA &&
     737          96 :               username[0] == EAP_AKA_REAUTH_ID_PREFIX)) &&
     738           4 :             data->identity_round == 1) {
     739             :                 /* Remain in IDENTITY state for another round to request full
     740             :                  * auth identity since we did not recognize reauth id */
     741           4 :                 os_free(username);
     742           4 :                 return;
     743             :         }
     744             : 
     745         160 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     746         157 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     747         212 :             (data->eap_method == EAP_TYPE_AKA &&
     748          94 :              username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
     749             :                 const char *permanent;
     750           7 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
     751             :                            username);
     752           7 :                 permanent = eap_sim_db_get_permanent(
     753             :                         sm->eap_sim_db_priv, username);
     754           7 :                 os_free(username);
     755           7 :                 if (permanent == NULL) {
     756           3 :                         wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
     757             :                                    "identity - request permanent identity");
     758             :                         /* Remain in IDENTITY state for another round */
     759           3 :                         return;
     760             :                 }
     761           4 :                 os_strlcpy(data->permanent, permanent,
     762             :                            sizeof(data->permanent));
     763         150 :         } else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     764         118 :                     username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
     765         172 :                    (data->eap_method == EAP_TYPE_AKA &&
     766          86 :                     username[0] == EAP_AKA_PERMANENT_PREFIX)) {
     767         118 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
     768             :                            username);
     769         118 :                 os_strlcpy(data->permanent, username, sizeof(data->permanent));
     770         118 :                 os_free(username);
     771             :         } else {
     772           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
     773             :                            username);
     774           0 :                 os_free(username);
     775           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     776           0 :                 eap_aka_state(data, NOTIFICATION);
     777           0 :                 return;
     778             :         }
     779             : 
     780         122 :         eap_aka_fullauth(sm, data);
     781             : }
     782             : 
     783             : 
     784         138 : static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
     785             : {
     786             :         size_t identity_len;
     787             :         int res;
     788             : 
     789         276 :         res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
     790         138 :                                       data->rand, data->autn, data->ik,
     791         138 :                                       data->ck, data->res, &data->res_len, sm);
     792         138 :         if (res == EAP_SIM_DB_PENDING) {
     793          69 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
     794             :                            "not yet available - pending request");
     795          69 :                 sm->method_pending = METHOD_PENDING_WAIT;
     796          69 :                 return;
     797             :         }
     798             : 
     799             : #ifdef EAP_SERVER_AKA_PRIME
     800          69 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     801             :                 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
     802             :                  * needed 6-octet SQN ^AK for CK',IK' derivation */
     803          36 :                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
     804          18 :                                                  data->autn,
     805          18 :                                                  data->network_name,
     806             :                                                  data->network_name_len);
     807             :         }
     808             : #endif /* EAP_SERVER_AKA_PRIME */
     809             : 
     810          69 :         data->reauth = NULL;
     811          69 :         data->counter = 0; /* reset re-auth counter since this is full auth */
     812             : 
     813          69 :         if (res != 0) {
     814           0 :                 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
     815             :                            "authentication data for the peer");
     816           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     817           0 :                 eap_aka_state(data, NOTIFICATION);
     818           0 :                 return;
     819             :         }
     820          69 :         if (sm->method_pending == METHOD_PENDING_WAIT) {
     821           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
     822             :                            "available - abort pending wait");
     823           0 :                 sm->method_pending = METHOD_PENDING_NONE;
     824             :         }
     825             : 
     826          69 :         identity_len = sm->identity_len;
     827         138 :         while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
     828           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null "
     829             :                            "character from identity");
     830           0 :                 identity_len--;
     831             :         }
     832          69 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
     833          69 :                           sm->identity, identity_len);
     834             : 
     835          69 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     836          18 :                 eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
     837          18 :                                           data->ck, data->k_encr, data->k_aut,
     838          18 :                                           data->k_re, data->msk, data->emsk);
     839             :         } else {
     840          51 :                 eap_aka_derive_mk(sm->identity, identity_len, data->ik,
     841          51 :                                   data->ck, data->mk);
     842          51 :                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
     843          51 :                                     data->msk, data->emsk);
     844             :         }
     845             : 
     846          69 :         eap_aka_state(data, CHALLENGE);
     847             : }
     848             : 
     849             : 
     850         129 : static void eap_aka_process_identity(struct eap_sm *sm,
     851             :                                      struct eap_aka_data *data,
     852             :                                      struct wpabuf *respData,
     853             :                                      struct eap_sim_attrs *attr)
     854             : {
     855             :         u8 *new_identity;
     856             : 
     857         129 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
     858             : 
     859         129 :         if (attr->mac || attr->iv || attr->encr_data) {
     860           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
     861             :                            "received in EAP-Response/AKA-Identity");
     862           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     863           0 :                 eap_aka_state(data, NOTIFICATION);
     864           0 :                 return;
     865             :         }
     866             : 
     867             :         /*
     868             :          * We always request identity with AKA/Identity, so the peer is
     869             :          * required to have replied with one.
     870             :          */
     871         129 :         if (!attr->identity || attr->identity_len == 0) {
     872           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
     873             :                            "identity");
     874           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     875           0 :                 eap_aka_state(data, NOTIFICATION);
     876           0 :                 return;
     877             :         }
     878             : 
     879         129 :         new_identity = os_malloc(attr->identity_len);
     880         129 :         if (new_identity == NULL) {
     881           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     882           0 :                 eap_aka_state(data, NOTIFICATION);
     883           0 :                 return;
     884             :         }
     885         129 :         os_free(sm->identity);
     886         129 :         sm->identity = new_identity;
     887         129 :         os_memcpy(sm->identity, attr->identity, attr->identity_len);
     888         129 :         sm->identity_len = attr->identity_len;
     889             : 
     890         129 :         eap_aka_determine_identity(sm, data);
     891         129 :         if (eap_get_id(respData) == data->pending_id) {
     892          68 :                 data->pending_id = -1;
     893          68 :                 eap_aka_add_id_msg(data, respData);
     894             :         }
     895             : }
     896             : 
     897             : 
     898          55 : static int eap_aka_verify_mac(struct eap_aka_data *data,
     899             :                               const struct wpabuf *req,
     900             :                               const u8 *mac, const u8 *extra,
     901             :                               size_t extra_len)
     902             : {
     903          55 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     904          21 :                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
     905             :                                                  extra_len);
     906          34 :         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
     907             : }
     908             : 
     909             : 
     910          38 : static void eap_aka_process_challenge(struct eap_sm *sm,
     911             :                                       struct eap_aka_data *data,
     912             :                                       struct wpabuf *respData,
     913             :                                       struct eap_sim_attrs *attr)
     914             : {
     915          38 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
     916             : 
     917             : #ifdef EAP_SERVER_AKA_PRIME
     918             : #if 0
     919             :         /* KDF negotiation; to be enabled only after more than one KDF is
     920             :          * supported */
     921             :         if (data->eap_method == EAP_TYPE_AKA_PRIME &&
     922             :             attr->kdf_count == 1 && attr->mac == NULL) {
     923             :                 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
     924             :                         wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
     925             :                                    "unknown KDF");
     926             :                         data->notification =
     927             :                                 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     928             :                         eap_aka_state(data, NOTIFICATION);
     929             :                         return;
     930             :                 }
     931             : 
     932             :                 data->kdf = attr->kdf[0];
     933             : 
     934             :                 /* Allow negotiation to continue with the selected KDF by
     935             :                  * sending another Challenge message */
     936             :                 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
     937             :                 return;
     938             :         }
     939             : #endif
     940             : #endif /* EAP_SERVER_AKA_PRIME */
     941             : 
     942          76 :         if (attr->checkcode &&
     943          38 :             eap_aka_verify_checkcode(data, attr->checkcode,
     944             :                                      attr->checkcode_len)) {
     945           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the "
     946             :                            "message");
     947           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     948           0 :                 eap_aka_state(data, NOTIFICATION);
     949           0 :                 return;
     950             :         }
     951          76 :         if (attr->mac == NULL ||
     952          38 :             eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
     953           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
     954             :                            "did not include valid AT_MAC");
     955           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     956           0 :                 eap_aka_state(data, NOTIFICATION);
     957           0 :                 return;
     958             :         }
     959             : 
     960             :         /*
     961             :          * AT_RES is padded, so verify that there is enough room for RES and
     962             :          * that the RES length in bits matches with the expected RES.
     963             :          */
     964          76 :         if (attr->res == NULL || attr->res_len < data->res_len ||
     965          76 :             attr->res_len_bits != data->res_len * 8 ||
     966          38 :             os_memcmp_const(attr->res, data->res, data->res_len) != 0) {
     967           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
     968             :                            "include valid AT_RES (attr len=%lu, res len=%lu "
     969             :                            "bits, expected %lu bits)",
     970             :                            (unsigned long) attr->res_len,
     971             :                            (unsigned long) attr->res_len_bits,
     972           0 :                            (unsigned long) data->res_len * 8);
     973           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     974           0 :                 eap_aka_state(data, NOTIFICATION);
     975           0 :                 return;
     976             :         }
     977             : 
     978          38 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
     979             :                    "correct AT_MAC");
     980          38 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
     981           6 :                 data->use_result_ind = 1;
     982           6 :                 data->notification = EAP_SIM_SUCCESS;
     983           6 :                 eap_aka_state(data, NOTIFICATION);
     984             :         } else
     985          32 :                 eap_aka_state(data, SUCCESS);
     986             : 
     987          38 :         if (data->next_pseudonym) {
     988          38 :                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
     989             :                                          data->next_pseudonym);
     990          38 :                 data->next_pseudonym = NULL;
     991             :         }
     992          38 :         if (data->next_reauth_id) {
     993          38 :                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     994             : #ifdef EAP_SERVER_AKA_PRIME
     995          28 :                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
     996          14 :                                                     data->permanent,
     997             :                                                     data->next_reauth_id,
     998          14 :                                                     data->counter + 1,
     999          14 :                                                     data->k_encr, data->k_aut,
    1000          14 :                                                     data->k_re);
    1001             : #endif /* EAP_SERVER_AKA_PRIME */
    1002             :                 } else {
    1003          48 :                         eap_sim_db_add_reauth(sm->eap_sim_db_priv,
    1004          24 :                                               data->permanent,
    1005             :                                               data->next_reauth_id,
    1006          24 :                                               data->counter + 1,
    1007          24 :                                               data->mk);
    1008             :                 }
    1009          38 :                 data->next_reauth_id = NULL;
    1010             :         }
    1011             : }
    1012             : 
    1013             : 
    1014          10 : static void eap_aka_process_sync_failure(struct eap_sm *sm,
    1015             :                                          struct eap_aka_data *data,
    1016             :                                          struct wpabuf *respData,
    1017             :                                          struct eap_sim_attrs *attr)
    1018             : {
    1019          10 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
    1020             : 
    1021          10 :         if (attr->auts == NULL) {
    1022           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
    1023             :                            "message did not include valid AT_AUTS");
    1024           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    1025           0 :                 eap_aka_state(data, NOTIFICATION);
    1026           0 :                 return;
    1027             :         }
    1028             : 
    1029             :         /* Avoid re-reporting AUTS when processing pending EAP packet by
    1030             :          * maintaining a local flag stating whether this AUTS has already been
    1031             :          * reported. */
    1032          15 :         if (!data->auts_reported &&
    1033           5 :             eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
    1034           5 :                                      attr->auts, data->rand)) {
    1035           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
    1036           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    1037           0 :                 eap_aka_state(data, NOTIFICATION);
    1038           0 :                 return;
    1039             :         }
    1040          10 :         data->auts_reported = 1;
    1041             : 
    1042             :         /* Remain in CHALLENGE state to re-try after resynchronization */
    1043          10 :         eap_aka_fullauth(sm, data);
    1044             : }
    1045             : 
    1046             : 
    1047          17 : static void eap_aka_process_reauth(struct eap_sm *sm,
    1048             :                                    struct eap_aka_data *data,
    1049             :                                    struct wpabuf *respData,
    1050             :                                    struct eap_sim_attrs *attr)
    1051             : {
    1052             :         struct eap_sim_attrs eattr;
    1053          17 :         u8 *decrypted = NULL;
    1054             : 
    1055          17 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
    1056             : 
    1057          34 :         if (attr->mac == NULL ||
    1058          17 :             eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
    1059             :                                EAP_SIM_NONCE_S_LEN)) {
    1060           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
    1061             :                            "did not include valid AT_MAC");
    1062           0 :                 goto fail;
    1063             :         }
    1064             : 
    1065          17 :         if (attr->encr_data == NULL || attr->iv == NULL) {
    1066           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
    1067             :                            "message did not include encrypted data");
    1068           0 :                 goto fail;
    1069             :         }
    1070             : 
    1071          17 :         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    1072             :                                        attr->encr_data_len, attr->iv, &eattr,
    1073             :                                        0);
    1074          17 :         if (decrypted == NULL) {
    1075           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
    1076             :                            "data from reauthentication message");
    1077           0 :                 goto fail;
    1078             :         }
    1079             : 
    1080          17 :         if (eattr.counter != data->counter) {
    1081           0 :                 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
    1082             :                            "used incorrect counter %u, expected %u",
    1083           0 :                            eattr.counter, data->counter);
    1084           0 :                 goto fail;
    1085             :         }
    1086          17 :         os_free(decrypted);
    1087          17 :         decrypted = NULL;
    1088             : 
    1089          17 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
    1090             :                    "the correct AT_MAC");
    1091             : 
    1092          17 :         if (eattr.counter_too_small) {
    1093           4 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
    1094             :                            "included AT_COUNTER_TOO_SMALL - starting full "
    1095             :                            "authentication");
    1096           4 :                 eap_aka_fullauth(sm, data);
    1097           4 :                 return;
    1098             :         }
    1099             : 
    1100          13 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
    1101           5 :                 data->use_result_ind = 1;
    1102           5 :                 data->notification = EAP_SIM_SUCCESS;
    1103           5 :                 eap_aka_state(data, NOTIFICATION);
    1104             :         } else
    1105           8 :                 eap_aka_state(data, SUCCESS);
    1106             : 
    1107          13 :         if (data->next_reauth_id) {
    1108          11 :                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
    1109             : #ifdef EAP_SERVER_AKA_PRIME
    1110           8 :                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
    1111           4 :                                                     data->permanent,
    1112             :                                                     data->next_reauth_id,
    1113           4 :                                                     data->counter + 1,
    1114           4 :                                                     data->k_encr, data->k_aut,
    1115           4 :                                                     data->k_re);
    1116             : #endif /* EAP_SERVER_AKA_PRIME */
    1117             :                 } else {
    1118          14 :                         eap_sim_db_add_reauth(sm->eap_sim_db_priv,
    1119           7 :                                               data->permanent,
    1120             :                                               data->next_reauth_id,
    1121           7 :                                               data->counter + 1,
    1122           7 :                                               data->mk);
    1123             :                 }
    1124          11 :                 data->next_reauth_id = NULL;
    1125             :         } else {
    1126           2 :                 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
    1127           2 :                 data->reauth = NULL;
    1128             :         }
    1129             : 
    1130          13 :         return;
    1131             : 
    1132             : fail:
    1133           0 :         data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    1134           0 :         eap_aka_state(data, NOTIFICATION);
    1135           0 :         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
    1136           0 :         data->reauth = NULL;
    1137           0 :         os_free(decrypted);
    1138             : }
    1139             : 
    1140             : 
    1141           7 : static void eap_aka_process_client_error(struct eap_sm *sm,
    1142             :                                          struct eap_aka_data *data,
    1143             :                                          struct wpabuf *respData,
    1144             :                                          struct eap_sim_attrs *attr)
    1145             : {
    1146           7 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
    1147             :                    attr->client_error_code);
    1148           7 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    1149           1 :                 eap_aka_state(data, SUCCESS);
    1150             :         else
    1151           6 :                 eap_aka_state(data, FAILURE);
    1152           7 : }
    1153             : 
    1154             : 
    1155          20 : static void eap_aka_process_authentication_reject(
    1156             :         struct eap_sm *sm, struct eap_aka_data *data,
    1157             :         struct wpabuf *respData, struct eap_sim_attrs *attr)
    1158             : {
    1159          20 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
    1160          20 :         eap_aka_state(data, FAILURE);
    1161          20 : }
    1162             : 
    1163             : 
    1164           7 : static void eap_aka_process_notification(struct eap_sm *sm,
    1165             :                                          struct eap_aka_data *data,
    1166             :                                          struct wpabuf *respData,
    1167             :                                          struct eap_sim_attrs *attr)
    1168             : {
    1169           7 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
    1170           7 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    1171           7 :                 eap_aka_state(data, SUCCESS);
    1172             :         else
    1173           0 :                 eap_aka_state(data, FAILURE);
    1174           7 : }
    1175             : 
    1176             : 
    1177         228 : static void eap_aka_process(struct eap_sm *sm, void *priv,
    1178             :                             struct wpabuf *respData)
    1179             : {
    1180         228 :         struct eap_aka_data *data = priv;
    1181             :         const u8 *pos, *end;
    1182             :         u8 subtype;
    1183             :         size_t len;
    1184             :         struct eap_sim_attrs attr;
    1185             : 
    1186         228 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
    1187             :                                &len);
    1188         228 :         if (pos == NULL || len < 3)
    1189          27 :                 return;
    1190             : 
    1191         228 :         end = pos + len;
    1192         228 :         subtype = *pos;
    1193         228 :         pos += 3;
    1194             : 
    1195         228 :         if (eap_aka_subtype_ok(data, subtype)) {
    1196           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
    1197             :                            "EAP-AKA Subtype in EAP Response");
    1198           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    1199           0 :                 eap_aka_state(data, NOTIFICATION);
    1200           0 :                 return;
    1201             :         }
    1202             : 
    1203         228 :         if (eap_sim_parse_attr(pos, end, &attr,
    1204         228 :                                data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
    1205             :                                0)) {
    1206           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
    1207           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
    1208           0 :                 eap_aka_state(data, NOTIFICATION);
    1209           0 :                 return;
    1210             :         }
    1211             : 
    1212         228 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
    1213           7 :                 eap_aka_process_client_error(sm, data, respData, &attr);
    1214           7 :                 return;
    1215             :         }
    1216             : 
    1217         221 :         if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
    1218          20 :                 eap_aka_process_authentication_reject(sm, data, respData,
    1219             :                                                       &attr);
    1220          20 :                 return;
    1221             :         }
    1222             : 
    1223         201 :         switch (data->state) {
    1224             :         case IDENTITY:
    1225         129 :                 eap_aka_process_identity(sm, data, respData, &attr);
    1226         129 :                 break;
    1227             :         case CHALLENGE:
    1228          48 :                 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
    1229          10 :                         eap_aka_process_sync_failure(sm, data, respData,
    1230             :                                                      &attr);
    1231             :                 } else {
    1232          38 :                         eap_aka_process_challenge(sm, data, respData, &attr);
    1233             :                 }
    1234          48 :                 break;
    1235             :         case REAUTH:
    1236          17 :                 eap_aka_process_reauth(sm, data, respData, &attr);
    1237          17 :                 break;
    1238             :         case NOTIFICATION:
    1239           7 :                 eap_aka_process_notification(sm, data, respData, &attr);
    1240           7 :                 break;
    1241             :         default:
    1242           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
    1243           0 :                            "process", data->state);
    1244           0 :                 break;
    1245             :         }
    1246             : }
    1247             : 
    1248             : 
    1249         254 : static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
    1250             : {
    1251         254 :         struct eap_aka_data *data = priv;
    1252         254 :         return data->state == SUCCESS || data->state == FAILURE;
    1253             : }
    1254             : 
    1255             : 
    1256          73 : static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
    1257             : {
    1258          73 :         struct eap_aka_data *data = priv;
    1259             :         u8 *key;
    1260             : 
    1261          73 :         if (data->state != SUCCESS)
    1262          26 :                 return NULL;
    1263             : 
    1264          47 :         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
    1265          47 :         if (key == NULL)
    1266           0 :                 return NULL;
    1267          47 :         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
    1268          47 :         *len = EAP_SIM_KEYING_DATA_LEN;
    1269          47 :         return key;
    1270             : }
    1271             : 
    1272             : 
    1273           2 : static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    1274             : {
    1275           2 :         struct eap_aka_data *data = priv;
    1276             :         u8 *key;
    1277             : 
    1278           2 :         if (data->state != SUCCESS)
    1279           0 :                 return NULL;
    1280             : 
    1281           2 :         key = os_malloc(EAP_EMSK_LEN);
    1282           2 :         if (key == NULL)
    1283           0 :                 return NULL;
    1284           2 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    1285           2 :         *len = EAP_EMSK_LEN;
    1286           2 :         return key;
    1287             : }
    1288             : 
    1289             : 
    1290         100 : static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
    1291             : {
    1292         100 :         struct eap_aka_data *data = priv;
    1293         100 :         return data->state == SUCCESS;
    1294             : }
    1295             : 
    1296             : 
    1297          71 : static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    1298             : {
    1299          71 :         struct eap_aka_data *data = priv;
    1300             :         u8 *id;
    1301             : 
    1302          71 :         if (data->state != SUCCESS)
    1303          26 :                 return NULL;
    1304             : 
    1305          45 :         *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
    1306          45 :         id = os_malloc(*len);
    1307          45 :         if (id == NULL)
    1308           0 :                 return NULL;
    1309             : 
    1310          45 :         id[0] = data->eap_method;
    1311          45 :         os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
    1312          45 :         os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
    1313          45 :         wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
    1314             : 
    1315          45 :         return id;
    1316             : }
    1317             : 
    1318             : 
    1319          25 : int eap_server_aka_register(void)
    1320             : {
    1321             :         struct eap_method *eap;
    1322             : 
    1323          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1324             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
    1325          25 :         if (eap == NULL)
    1326           0 :                 return -1;
    1327             : 
    1328          25 :         eap->init = eap_aka_init;
    1329          25 :         eap->reset = eap_aka_reset;
    1330          25 :         eap->buildReq = eap_aka_buildReq;
    1331          25 :         eap->check = eap_aka_check;
    1332          25 :         eap->process = eap_aka_process;
    1333          25 :         eap->isDone = eap_aka_isDone;
    1334          25 :         eap->getKey = eap_aka_getKey;
    1335          25 :         eap->isSuccess = eap_aka_isSuccess;
    1336          25 :         eap->get_emsk = eap_aka_get_emsk;
    1337          25 :         eap->getSessionId = eap_aka_get_session_id;
    1338             : 
    1339          25 :         return eap_server_method_register(eap);
    1340             : }
    1341             : 
    1342             : 
    1343             : #ifdef EAP_SERVER_AKA_PRIME
    1344          25 : int eap_server_aka_prime_register(void)
    1345             : {
    1346             :         struct eap_method *eap;
    1347             : 
    1348          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1349             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
    1350             :                                       "AKA'");
    1351          25 :         if (eap == NULL)
    1352           0 :                 return -1;
    1353             : 
    1354          25 :         eap->init = eap_aka_prime_init;
    1355          25 :         eap->reset = eap_aka_reset;
    1356          25 :         eap->buildReq = eap_aka_buildReq;
    1357          25 :         eap->check = eap_aka_check;
    1358          25 :         eap->process = eap_aka_process;
    1359          25 :         eap->isDone = eap_aka_isDone;
    1360          25 :         eap->getKey = eap_aka_getKey;
    1361          25 :         eap->isSuccess = eap_aka_isSuccess;
    1362          25 :         eap->get_emsk = eap_aka_get_emsk;
    1363          25 :         eap->getSessionId = eap_aka_get_session_id;
    1364             : 
    1365          25 :         return eap_server_method_register(eap);
    1366             : }
    1367             : #endif /* EAP_SERVER_AKA_PRIME */

Generated by: LCOV version 1.10