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 1401264779 Lines: 516 669 77.1 %
Date: 2014-05-28 Functions: 34 35 97.1 %

          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         178 : static const char * eap_aka_state_txt(int state)
      61             : {
      62         178 :         switch (state) {
      63             :         case IDENTITY:
      64          41 :                 return "IDENTITY";
      65             :         case CHALLENGE:
      66          60 :                 return "CHALLENGE";
      67             :         case REAUTH:
      68          28 :                 return "REAUTH";
      69             :         case SUCCESS:
      70          35 :                 return "SUCCESS";
      71             :         case FAILURE:
      72           6 :                 return "FAILURE";
      73             :         case NOTIFICATION:
      74           8 :                 return "NOTIFICATION";
      75             :         default:
      76           0 :                 return "Unknown?!";
      77             :         }
      78             : }
      79             : 
      80             : 
      81          89 : static void eap_aka_state(struct eap_aka_data *data, int state)
      82             : {
      83         178 :         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
      84          89 :                    eap_aka_state_txt(data->state),
      85             :                    eap_aka_state_txt(state));
      86          89 :         data->state = state;
      87          89 : }
      88             : 
      89             : 
      90         102 : static int eap_aka_check_identity_reauth(struct eap_sm *sm,
      91             :                                          struct eap_aka_data *data,
      92             :                                          const char *username)
      93             : {
      94         145 :         if (data->eap_method == EAP_TYPE_AKA_PRIME &&
      95          43 :             username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
      96          32 :                 return 0;
      97         129 :         if (data->eap_method == EAP_TYPE_AKA &&
      98          59 :             username[0] != EAP_AKA_REAUTH_ID_PREFIX)
      99          48 :                 return 0;
     100             : 
     101          22 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
     102          22 :         data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
     103             :                                                    username);
     104          22 :         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          14 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
     112          14 :         os_strlcpy(data->permanent, data->reauth->permanent,
     113             :                    sizeof(data->permanent));
     114          14 :         data->counter = data->reauth->counter;
     115          14 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     116           7 :                 os_memcpy(data->k_encr, data->reauth->k_encr,
     117             :                           EAP_SIM_K_ENCR_LEN);
     118           7 :                 os_memcpy(data->k_aut, data->reauth->k_aut,
     119             :                           EAP_AKA_PRIME_K_AUT_LEN);
     120           7 :                 os_memcpy(data->k_re, data->reauth->k_re,
     121             :                           EAP_AKA_PRIME_K_RE_LEN);
     122             :         } else {
     123           7 :                 os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
     124             :         }
     125             : 
     126          14 :         eap_aka_state(data, REAUTH);
     127          14 :         return 1;
     128             : }
     129             : 
     130             : 
     131          41 : 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          41 :         username = sim_get_username(sm->identity, sm->identity_len);
     139          41 :         if (username == NULL)
     140           0 :                 return;
     141             : 
     142          41 :         if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
     143          14 :                 os_free(username);
     144             :                 /*
     145             :                  * Since re-auth username was recognized, skip AKA/Identity
     146             :                  * exchange.
     147             :                  */
     148          14 :                 return;
     149             :         }
     150             : 
     151          38 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     152          38 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     153          43 :             (data->eap_method == EAP_TYPE_AKA &&
     154          16 :              username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
     155             :                 const char *permanent;
     156           1 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
     157             :                            username);
     158           1 :                 permanent = eap_sim_db_get_permanent(
     159             :                         sm->eap_sim_db_priv, username);
     160           1 :                 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           0 :                 os_strlcpy(data->permanent, permanent,
     168             :                            sizeof(data->permanent));
     169             :                 /*
     170             :                  * Since pseudonym username was recognized, skip AKA/Identity
     171             :                  * exchange.
     172             :                  */
     173           0 :                 eap_aka_fullauth(sm, data);
     174             :         }
     175             : 
     176          26 :         os_free(username);
     177             : }
     178             : 
     179             : 
     180          23 : static void * eap_aka_init(struct eap_sm *sm)
     181             : {
     182             :         struct eap_aka_data *data;
     183             : 
     184          23 :         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          23 :         data = os_zalloc(sizeof(*data));
     190          23 :         if (data == NULL)
     191           0 :                 return NULL;
     192             : 
     193          23 :         data->eap_method = EAP_TYPE_AKA;
     194             : 
     195          23 :         data->state = IDENTITY;
     196          23 :         data->pending_id = -1;
     197          23 :         eap_aka_check_identity(sm, data);
     198             : 
     199          23 :         return data;
     200             : }
     201             : 
     202             : 
     203             : #ifdef EAP_SERVER_AKA_PRIME
     204          18 : 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          18 :         char *network_name = "WLAN";
     209             : 
     210          18 :         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          18 :         data = os_zalloc(sizeof(*data));
     216          18 :         if (data == NULL)
     217           0 :                 return NULL;
     218             : 
     219          18 :         data->eap_method = EAP_TYPE_AKA_PRIME;
     220          18 :         data->network_name = (u8 *) os_strdup(network_name);
     221          18 :         if (data->network_name == NULL) {
     222           0 :                 os_free(data);
     223           0 :                 return NULL;
     224             :         }
     225             : 
     226          18 :         data->network_name_len = os_strlen(network_name);
     227             : 
     228          18 :         data->state = IDENTITY;
     229          18 :         data->pending_id = -1;
     230          18 :         eap_aka_check_identity(sm, data);
     231             : 
     232          18 :         return data;
     233             : }
     234             : #endif /* EAP_SERVER_AKA_PRIME */
     235             : 
     236             : 
     237          41 : static void eap_aka_reset(struct eap_sm *sm, void *priv)
     238             : {
     239          41 :         struct eap_aka_data *data = priv;
     240          41 :         os_free(data->next_pseudonym);
     241          41 :         os_free(data->next_reauth_id);
     242          41 :         wpabuf_free(data->id_msgs);
     243          41 :         os_free(data->network_name);
     244          41 :         os_free(data);
     245          41 : }
     246             : 
     247             : 
     248          68 : static int eap_aka_add_id_msg(struct eap_aka_data *data,
     249             :                               const struct wpabuf *msg)
     250             : {
     251          68 :         if (msg == NULL)
     252           0 :                 return -1;
     253             : 
     254          68 :         if (data->id_msgs == NULL) {
     255          27 :                 data->id_msgs = wpabuf_dup(msg);
     256          27 :                 return data->id_msgs == NULL ? -1 : 0;
     257             :         }
     258             : 
     259          41 :         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
     260           0 :                 return -1;
     261          41 :         wpabuf_put_buf(data->id_msgs, msg);
     262             : 
     263          41 :         return 0;
     264             : }
     265             : 
     266             : 
     267          44 : 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          44 :         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
     275             : 
     276          44 :         if (data->id_msgs == NULL) {
     277             :                 /*
     278             :                  * No EAP-AKA/Identity packets were exchanged - send empty
     279             :                  * checkcode.
     280             :                  */
     281          16 :                 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
     282          60 :                 return;
     283             :         }
     284             : 
     285             :         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
     286          28 :         addr = wpabuf_head(data->id_msgs);
     287          28 :         len = wpabuf_len(data->id_msgs);
     288          28 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
     289          28 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     290          11 :                 sha256_vector(1, &addr, &len, hash);
     291             :         else
     292          17 :                 sha1_vector(1, &addr, &len, hash);
     293             : 
     294          28 :         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
     295          28 :                         data->eap_method == EAP_TYPE_AKA_PRIME ?
     296             :                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
     297             : }
     298             : 
     299             : 
     300          25 : 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          25 :         if (checkcode == NULL)
     309           0 :                 return -1;
     310             : 
     311          25 :         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          23 :         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
     322             :                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
     323             : 
     324          23 :         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          23 :         addr = wpabuf_head(data->id_msgs);
     333          23 :         len = wpabuf_len(data->id_msgs);
     334          23 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     335          10 :                 sha256_vector(1, &addr, &len, hash);
     336             :         else
     337          13 :                 sha1_vector(1, &addr, &len, hash);
     338             : 
     339          23 :         if (os_memcmp(hash, checkcode, hash_len) != 0) {
     340           0 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
     341           0 :                 return -1;
     342             :         }
     343             : 
     344          23 :         return 0;
     345             : }
     346             : 
     347             : 
     348          34 : 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          34 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
     355          34 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     356             :                                EAP_AKA_SUBTYPE_IDENTITY);
     357          34 :         data->identity_round++;
     358          34 :         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          27 :                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
     365          27 :                 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          34 :         buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
     381          34 :         if (eap_aka_add_id_msg(data, buf) < 0) {
     382           0 :                 wpabuf_free(buf);
     383           0 :                 return NULL;
     384             :         }
     385          34 :         data->pending_id = id;
     386          34 :         return buf;
     387             : }
     388             : 
     389             : 
     390          44 : 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          44 :         os_free(data->next_pseudonym);
     395          44 :         if (nonce_s == NULL) {
     396          30 :                 data->next_pseudonym =
     397          30 :                         eap_sim_db_get_next_pseudonym(
     398             :                                 sm->eap_sim_db_priv,
     399          30 :                                 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          14 :                 data->next_pseudonym = NULL;
     404             :         }
     405          44 :         os_free(data->next_reauth_id);
     406          44 :         if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
     407          42 :                 data->next_reauth_id =
     408          42 :                         eap_sim_db_get_next_reauth_id(
     409             :                                 sm->eap_sim_db_priv,
     410          42 :                                 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          44 :         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
     419           0 :             counter == 0 && nonce_s == NULL)
     420           0 :                 return 0;
     421             : 
     422          44 :         wpa_printf(MSG_DEBUG, "   AT_IV");
     423          44 :         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     424          44 :         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
     425             : 
     426          44 :         if (counter > 0) {
     427          14 :                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
     428          14 :                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
     429             :         }
     430             : 
     431          44 :         if (nonce_s) {
     432          14 :                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
     433          14 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
     434             :                                 EAP_SIM_NONCE_S_LEN);
     435             :         }
     436             : 
     437          44 :         if (data->next_pseudonym) {
     438          30 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
     439             :                            data->next_pseudonym);
     440          60 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
     441          30 :                                 os_strlen(data->next_pseudonym),
     442          30 :                                 (u8 *) data->next_pseudonym,
     443          30 :                                 os_strlen(data->next_pseudonym));
     444             :         }
     445             : 
     446          44 :         if (data->next_reauth_id) {
     447          42 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
     448             :                            data->next_reauth_id);
     449          84 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
     450          42 :                                 os_strlen(data->next_reauth_id),
     451          42 :                                 (u8 *) data->next_reauth_id,
     452          42 :                                 os_strlen(data->next_reauth_id));
     453             :         }
     454             : 
     455          44 :         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          44 :         return 0;
     462             : }
     463             : 
     464             : 
     465          30 : 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          30 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
     472          30 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     473             :                                EAP_AKA_SUBTYPE_CHALLENGE);
     474          30 :         wpa_printf(MSG_DEBUG, "   AT_RAND");
     475          30 :         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
     476          30 :         wpa_printf(MSG_DEBUG, "   AT_AUTN");
     477          30 :         eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
     478          30 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     479          12 :                 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          12 :                 wpa_printf(MSG_DEBUG, "   AT_KDF");
     486          12 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
     487             :                                 NULL, 0);
     488          12 :                 wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
     489          24 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
     490          12 :                                 data->network_name_len,
     491          12 :                                 data->network_name, data->network_name_len);
     492             :         }
     493             : 
     494          30 :         if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
     495           0 :                 eap_sim_msg_free(msg);
     496           0 :                 return NULL;
     497             :         }
     498             : 
     499          30 :         eap_aka_add_checkcode(data, msg);
     500             : 
     501          30 :         if (sm->eap_sim_aka_result_ind) {
     502          30 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     503          30 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     504             :         }
     505             : 
     506             : #ifdef EAP_SERVER_AKA_PRIME
     507          30 :         if (data->eap_method == EAP_TYPE_AKA) {
     508          18 :                 u16 flags = 0;
     509             :                 int i;
     510          18 :                 int aka_prime_preferred = 0;
     511             : 
     512          18 :                 i = 0;
     513          54 :                 while (sm->user && i < EAP_MAX_METHODS &&
     514          36 :                        (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
     515          18 :                         sm->user->methods[i].method != EAP_TYPE_NONE)) {
     516          18 :                         if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
     517          18 :                                 if (sm->user->methods[i].method ==
     518             :                                     EAP_TYPE_AKA)
     519          18 :                                         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          18 :                 if (aka_prime_preferred)
     530           0 :                         flags |= EAP_AKA_BIDDING_FLAG_D;
     531          18 :                 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
     532             :         }
     533             : #endif /* EAP_SERVER_AKA_PRIME */
     534             : 
     535          30 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     536          30 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     537          30 :         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
     538             : }
     539             : 
     540             : 
     541          14 : 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          14 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
     547             : 
     548          14 :         if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
     549           0 :                 return NULL;
     550          14 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
     551          14 :                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
     552             : 
     553          14 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     554          14 :                 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
     555           7 :                                                  sm->identity,
     556             :                                                  sm->identity_len,
     557           7 :                                                  data->nonce_s,
     558           7 :                                                  data->msk, data->emsk);
     559             :         } else {
     560           7 :                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
     561           7 :                                     data->msk, data->emsk);
     562           7 :                 eap_sim_derive_keys_reauth(data->counter, sm->identity,
     563           7 :                                            sm->identity_len, data->nonce_s,
     564           7 :                                            data->mk, data->msk, data->emsk);
     565             :         }
     566             : 
     567          14 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     568             :                                EAP_AKA_SUBTYPE_REAUTHENTICATION);
     569             : 
     570          14 :         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          14 :         eap_aka_add_checkcode(data, msg);
     576             : 
     577          14 :         if (sm->eap_sim_aka_result_ind) {
     578          14 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     579          14 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     580             :         }
     581             : 
     582          14 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     583          14 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     584          14 :         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
     585             : }
     586             : 
     587             : 
     588           4 : 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           4 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
     595           4 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     596             :                                EAP_AKA_SUBTYPE_NOTIFICATION);
     597           4 :         wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
     598           4 :         eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
     599             :                         NULL, 0);
     600           4 :         if (data->use_result_ind) {
     601           4 :                 if (data->reauth) {
     602           2 :                         wpa_printf(MSG_DEBUG, "   AT_IV");
     603           2 :                         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     604           2 :                         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
     605             :                                                    EAP_SIM_AT_ENCR_DATA);
     606           2 :                         wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
     607           2 :                                    data->counter);
     608           2 :                         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
     609             :                                         NULL, 0);
     610             : 
     611           2 :                         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           4 :                 wpa_printf(MSG_DEBUG, "   AT_MAC");
     621           4 :                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     622             :         }
     623           4 :         return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);
     624             : }
     625             : 
     626             : 
     627          82 : static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
     628             : {
     629          82 :         struct eap_aka_data *data = priv;
     630             : 
     631          82 :         data->auts_reported = 0;
     632          82 :         switch (data->state) {
     633             :         case IDENTITY:
     634          34 :                 return eap_aka_build_identity(sm, data, id);
     635             :         case CHALLENGE:
     636          30 :                 return eap_aka_build_challenge(sm, data, id);
     637             :         case REAUTH:
     638          14 :                 return eap_aka_build_reauth(sm, data, id);
     639             :         case NOTIFICATION:
     640           4 :                 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          85 : static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
     651             :                              struct wpabuf *respData)
     652             : {
     653          85 :         struct eap_aka_data *data = priv;
     654             :         const u8 *pos;
     655             :         size_t len;
     656             : 
     657          85 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
     658             :                                &len);
     659          85 :         if (pos == NULL || len < 3) {
     660           0 :                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
     661           0 :                 return TRUE;
     662             :         }
     663             : 
     664          85 :         return FALSE;
     665             : }
     666             : 
     667             : 
     668         112 : static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
     669             : {
     670         112 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
     671             :             subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
     672           6 :                 return FALSE;
     673             : 
     674         106 :         switch (data->state) {
     675             :         case IDENTITY:
     676          61 :                 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          61 :                 break;
     682             :         case CHALLENGE:
     683          27 :                 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          27 :                 break;
     690             :         case REAUTH:
     691          14 :                 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          14 :                 break;
     697             :         case NOTIFICATION:
     698           4 :                 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           4 :                 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         106 :         return FALSE;
     711             : }
     712             : 
     713             : 
     714          61 : static void eap_aka_determine_identity(struct eap_sm *sm,
     715             :                                        struct eap_aka_data *data)
     716             : {
     717             :         char *username;
     718             : 
     719         122 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
     720          61 :                           sm->identity, sm->identity_len);
     721             : 
     722          61 :         username = sim_get_username(sm->identity, sm->identity_len);
     723          61 :         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          61 :         if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
     730           0 :                 os_free(username);
     731           0 :                 return;
     732             :         }
     733             : 
     734          86 :         if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
     735          84 :               username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
     736          95 :              (data->eap_method == EAP_TYPE_AKA &&
     737          40 :               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          80 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     746          77 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     747          88 :             (data->eap_method == EAP_TYPE_AKA &&
     748          38 :              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          70 :         } else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     764          50 :                     username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
     765          60 :                    (data->eap_method == EAP_TYPE_AKA &&
     766          30 :                     username[0] == EAP_AKA_PERMANENT_PREFIX)) {
     767          50 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
     768             :                            username);
     769          50 :                 os_strlcpy(data->permanent, username, sizeof(data->permanent));
     770          50 :                 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          54 :         eap_aka_fullauth(sm, data);
     781             : }
     782             : 
     783             : 
     784          60 : 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         120 :         res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
     790          60 :                                       data->rand, data->autn, data->ik,
     791          60 :                                       data->ck, data->res, &data->res_len, sm);
     792          60 :         if (res == EAP_SIM_DB_PENDING) {
     793          30 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
     794             :                            "not yet available - pending request");
     795          30 :                 sm->method_pending = METHOD_PENDING_WAIT;
     796          30 :                 return;
     797             :         }
     798             : 
     799             : #ifdef EAP_SERVER_AKA_PRIME
     800          30 :         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          24 :                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
     804          12 :                                                  data->autn,
     805          12 :                                                  data->network_name,
     806             :                                                  data->network_name_len);
     807             :         }
     808             : #endif /* EAP_SERVER_AKA_PRIME */
     809             : 
     810          30 :         data->reauth = NULL;
     811          30 :         data->counter = 0; /* reset re-auth counter since this is full auth */
     812             : 
     813          30 :         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          30 :         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          30 :         identity_len = sm->identity_len;
     827          60 :         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          30 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
     833          30 :                           sm->identity, identity_len);
     834             : 
     835          30 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     836          12 :                 eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
     837          12 :                                           data->ck, data->k_encr, data->k_aut,
     838          12 :                                           data->k_re, data->msk, data->emsk);
     839             :         } else {
     840          18 :                 eap_aka_derive_mk(sm->identity, identity_len, data->ik,
     841          18 :                                   data->ck, data->mk);
     842          18 :                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
     843          18 :                                     data->msk, data->emsk);
     844             :         }
     845             : 
     846          30 :         eap_aka_state(data, CHALLENGE);
     847             : }
     848             : 
     849             : 
     850          61 : 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          61 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
     858             : 
     859          61 :         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          61 :         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          61 :         new_identity = os_malloc(attr->identity_len);
     880          61 :         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          61 :         os_free(sm->identity);
     886          61 :         sm->identity = new_identity;
     887          61 :         os_memcpy(sm->identity, attr->identity, attr->identity_len);
     888          61 :         sm->identity_len = attr->identity_len;
     889             : 
     890          61 :         eap_aka_determine_identity(sm, data);
     891          61 :         if (eap_get_id(respData) == data->pending_id) {
     892          34 :                 data->pending_id = -1;
     893          34 :                 eap_aka_add_id_msg(data, respData);
     894             :         }
     895             : }
     896             : 
     897             : 
     898          39 : 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          39 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     904          18 :                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
     905             :                                                  extra_len);
     906          21 :         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
     907             : }
     908             : 
     909             : 
     910          25 : 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          25 :         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          50 :         if (attr->checkcode &&
     943          25 :             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          50 :         if (attr->mac == NULL ||
     952          25 :             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          50 :         if (attr->res == NULL || attr->res_len < data->res_len ||
     965          50 :             attr->res_len_bits != data->res_len * 8 ||
     966          25 :             os_memcmp(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          25 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
     979             :                    "correct AT_MAC");
     980          25 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
     981           2 :                 data->use_result_ind = 1;
     982           2 :                 data->notification = EAP_SIM_SUCCESS;
     983           2 :                 eap_aka_state(data, NOTIFICATION);
     984             :         } else
     985          23 :                 eap_aka_state(data, SUCCESS);
     986             : 
     987          25 :         if (data->next_pseudonym) {
     988          25 :                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
     989             :                                          data->next_pseudonym);
     990          25 :                 data->next_pseudonym = NULL;
     991             :         }
     992          25 :         if (data->next_reauth_id) {
     993          25 :                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     994             : #ifdef EAP_SERVER_AKA_PRIME
     995          22 :                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
     996          11 :                                                     data->permanent,
     997             :                                                     data->next_reauth_id,
     998          11 :                                                     data->counter + 1,
     999          11 :                                                     data->k_encr, data->k_aut,
    1000          11 :                                                     data->k_re);
    1001             : #endif /* EAP_SERVER_AKA_PRIME */
    1002             :                 } else {
    1003          28 :                         eap_sim_db_add_reauth(sm->eap_sim_db_priv,
    1004          14 :                                               data->permanent,
    1005             :                                               data->next_reauth_id,
    1006          14 :                                               data->counter + 1,
    1007          14 :                                               data->mk);
    1008             :                 }
    1009          25 :                 data->next_reauth_id = NULL;
    1010             :         }
    1011             : }
    1012             : 
    1013             : 
    1014           2 : 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           2 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
    1020             : 
    1021           2 :         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           3 :         if (!data->auts_reported &&
    1033           1 :             eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
    1034           1 :                                      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           2 :         data->auts_reported = 1;
    1041             : 
    1042             :         /* Remain in CHALLENGE state to re-try after resynchronization */
    1043           2 :         eap_aka_fullauth(sm, data);
    1044             : }
    1045             : 
    1046             : 
    1047          14 : 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          14 :         u8 *decrypted = NULL;
    1054             : 
    1055          14 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
    1056             : 
    1057          28 :         if (attr->mac == NULL ||
    1058          14 :             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          14 :         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          14 :         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
    1072             :                                        attr->encr_data_len, attr->iv, &eattr,
    1073             :                                        0);
    1074          14 :         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          14 :         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          14 :         os_free(decrypted);
    1087          14 :         decrypted = NULL;
    1088             : 
    1089          14 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
    1090             :                    "the correct AT_MAC");
    1091             : 
    1092          14 :         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          10 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
    1101           2 :                 data->use_result_ind = 1;
    1102           2 :                 data->notification = EAP_SIM_SUCCESS;
    1103           2 :                 eap_aka_state(data, NOTIFICATION);
    1104             :         } else
    1105           8 :                 eap_aka_state(data, SUCCESS);
    1106             : 
    1107          10 :         if (data->next_reauth_id) {
    1108           8 :                 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           8 :                         eap_sim_db_add_reauth(sm->eap_sim_db_priv,
    1119           4 :                                               data->permanent,
    1120             :                                               data->next_reauth_id,
    1121           4 :                                               data->counter + 1,
    1122           4 :                                               data->mk);
    1123             :                 }
    1124           8 :                 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          10 :         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           3 : 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           3 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
    1147             :                    attr->client_error_code);
    1148           3 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    1149           0 :                 eap_aka_state(data, SUCCESS);
    1150             :         else
    1151           3 :                 eap_aka_state(data, FAILURE);
    1152           3 : }
    1153             : 
    1154             : 
    1155           3 : 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           3 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
    1160           3 :         eap_aka_state(data, FAILURE);
    1161           3 : }
    1162             : 
    1163             : 
    1164           4 : 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           4 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
    1170           4 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
    1171           4 :                 eap_aka_state(data, SUCCESS);
    1172             :         else
    1173           0 :                 eap_aka_state(data, FAILURE);
    1174           4 : }
    1175             : 
    1176             : 
    1177         112 : static void eap_aka_process(struct eap_sm *sm, void *priv,
    1178             :                             struct wpabuf *respData)
    1179             : {
    1180         112 :         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         112 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
    1187             :                                &len);
    1188         112 :         if (pos == NULL || len < 3)
    1189           6 :                 return;
    1190             : 
    1191         112 :         end = pos + len;
    1192         112 :         subtype = *pos;
    1193         112 :         pos += 3;
    1194             : 
    1195         112 :         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         112 :         if (eap_sim_parse_attr(pos, end, &attr,
    1204         112 :                                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         112 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
    1213           3 :                 eap_aka_process_client_error(sm, data, respData, &attr);
    1214           3 :                 return;
    1215             :         }
    1216             : 
    1217         109 :         if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
    1218           3 :                 eap_aka_process_authentication_reject(sm, data, respData,
    1219             :                                                       &attr);
    1220           3 :                 return;
    1221             :         }
    1222             : 
    1223         106 :         switch (data->state) {
    1224             :         case IDENTITY:
    1225          61 :                 eap_aka_process_identity(sm, data, respData, &attr);
    1226          61 :                 break;
    1227             :         case CHALLENGE:
    1228          27 :                 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
    1229           2 :                         eap_aka_process_sync_failure(sm, data, respData,
    1230             :                                                      &attr);
    1231             :                 } else {
    1232          25 :                         eap_aka_process_challenge(sm, data, respData, &attr);
    1233             :                 }
    1234          27 :                 break;
    1235             :         case REAUTH:
    1236          14 :                 eap_aka_process_reauth(sm, data, respData, &attr);
    1237          14 :                 break;
    1238             :         case NOTIFICATION:
    1239           4 :                 eap_aka_process_notification(sm, data, respData, &attr);
    1240           4 :                 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         118 : static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
    1250             : {
    1251         118 :         struct eap_aka_data *data = priv;
    1252         118 :         return data->state == SUCCESS || data->state == FAILURE;
    1253             : }
    1254             : 
    1255             : 
    1256          40 : static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
    1257             : {
    1258          40 :         struct eap_aka_data *data = priv;
    1259             :         u8 *key;
    1260             : 
    1261          40 :         if (data->state != SUCCESS)
    1262           6 :                 return NULL;
    1263             : 
    1264          34 :         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
    1265          34 :         if (key == NULL)
    1266           0 :                 return NULL;
    1267          34 :         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
    1268          34 :         *len = EAP_SIM_KEYING_DATA_LEN;
    1269          34 :         return key;
    1270             : }
    1271             : 
    1272             : 
    1273           0 : static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
    1274             : {
    1275           0 :         struct eap_aka_data *data = priv;
    1276             :         u8 *key;
    1277             : 
    1278           0 :         if (data->state != SUCCESS)
    1279           0 :                 return NULL;
    1280             : 
    1281           0 :         key = os_malloc(EAP_EMSK_LEN);
    1282           0 :         if (key == NULL)
    1283           0 :                 return NULL;
    1284           0 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
    1285           0 :         *len = EAP_EMSK_LEN;
    1286           0 :         return key;
    1287             : }
    1288             : 
    1289             : 
    1290          47 : static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
    1291             : {
    1292          47 :         struct eap_aka_data *data = priv;
    1293          47 :         return data->state == SUCCESS;
    1294             : }
    1295             : 
    1296             : 
    1297           2 : int eap_server_aka_register(void)
    1298             : {
    1299             :         struct eap_method *eap;
    1300             :         int ret;
    1301             : 
    1302           2 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1303             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
    1304           2 :         if (eap == NULL)
    1305           0 :                 return -1;
    1306             : 
    1307           2 :         eap->init = eap_aka_init;
    1308           2 :         eap->reset = eap_aka_reset;
    1309           2 :         eap->buildReq = eap_aka_buildReq;
    1310           2 :         eap->check = eap_aka_check;
    1311           2 :         eap->process = eap_aka_process;
    1312           2 :         eap->isDone = eap_aka_isDone;
    1313           2 :         eap->getKey = eap_aka_getKey;
    1314           2 :         eap->isSuccess = eap_aka_isSuccess;
    1315           2 :         eap->get_emsk = eap_aka_get_emsk;
    1316             : 
    1317           2 :         ret = eap_server_method_register(eap);
    1318           2 :         if (ret)
    1319           0 :                 eap_server_method_free(eap);
    1320           2 :         return ret;
    1321             : }
    1322             : 
    1323             : 
    1324             : #ifdef EAP_SERVER_AKA_PRIME
    1325           2 : int eap_server_aka_prime_register(void)
    1326             : {
    1327             :         struct eap_method *eap;
    1328             :         int ret;
    1329             : 
    1330           2 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1331             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
    1332             :                                       "AKA'");
    1333           2 :         if (eap == NULL)
    1334           0 :                 return -1;
    1335             : 
    1336           2 :         eap->init = eap_aka_prime_init;
    1337           2 :         eap->reset = eap_aka_reset;
    1338           2 :         eap->buildReq = eap_aka_buildReq;
    1339           2 :         eap->check = eap_aka_check;
    1340           2 :         eap->process = eap_aka_process;
    1341           2 :         eap->isDone = eap_aka_isDone;
    1342           2 :         eap->getKey = eap_aka_getKey;
    1343           2 :         eap->isSuccess = eap_aka_isSuccess;
    1344           2 :         eap->get_emsk = eap_aka_get_emsk;
    1345             : 
    1346           2 :         ret = eap_server_method_register(eap);
    1347           2 :         if (ret)
    1348           0 :                 eap_server_method_free(eap);
    1349             : 
    1350           2 :         return ret;
    1351             : }
    1352             : #endif /* EAP_SERVER_AKA_PRIME */

Generated by: LCOV version 1.10