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 1443382998 Lines: 538 684 78.7 %
Date: 2015-09-27 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         250 : static const char * eap_aka_state_txt(int state)
      61             : {
      62         250 :         switch (state) {
      63             :         case IDENTITY:
      64          57 :                 return "IDENTITY";
      65             :         case CHALLENGE:
      66         100 :                 return "CHALLENGE";
      67             :         case REAUTH:
      68          28 :                 return "REAUTH";
      69             :         case SUCCESS:
      70          37 :                 return "SUCCESS";
      71             :         case FAILURE:
      72          20 :                 return "FAILURE";
      73             :         case NOTIFICATION:
      74           8 :                 return "NOTIFICATION";
      75             :         default:
      76           0 :                 return "Unknown?!";
      77             :         }
      78             : }
      79             : 
      80             : 
      81         125 : static void eap_aka_state(struct eap_aka_data *data, int state)
      82             : {
      83         250 :         wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
      84         125 :                    eap_aka_state_txt(data->state),
      85             :                    eap_aka_state_txt(state));
      86         125 :         data->state = state;
      87         125 : }
      88             : 
      89             : 
      90         150 : static int eap_aka_check_identity_reauth(struct eap_sm *sm,
      91             :                                          struct eap_aka_data *data,
      92             :                                          const char *username)
      93             : {
      94         196 :         if (data->eap_method == EAP_TYPE_AKA_PRIME &&
      95          46 :             username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
      96          35 :                 return 0;
      97         219 :         if (data->eap_method == EAP_TYPE_AKA &&
      98         104 :             username[0] != EAP_AKA_REAUTH_ID_PREFIX)
      99          93 :                 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          57 : 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          57 :         username = sim_get_username(sm->identity, sm->identity_len);
     139          57 :         if (username == NULL)
     140           0 :                 return;
     141             : 
     142          57 :         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          55 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     152          55 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     153          74 :             (data->eap_method == EAP_TYPE_AKA &&
     154          31 :              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          42 :         os_free(username);
     177             : }
     178             : 
     179             : 
     180          38 : static void * eap_aka_init(struct eap_sm *sm)
     181             : {
     182             :         struct eap_aka_data *data;
     183             : 
     184          38 :         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          38 :         data = os_zalloc(sizeof(*data));
     190          38 :         if (data == NULL)
     191           0 :                 return NULL;
     192             : 
     193          38 :         data->eap_method = EAP_TYPE_AKA;
     194             : 
     195          38 :         data->state = IDENTITY;
     196          38 :         data->pending_id = -1;
     197          38 :         eap_aka_check_identity(sm, data);
     198             : 
     199          38 :         return data;
     200             : }
     201             : 
     202             : 
     203             : #ifdef EAP_SERVER_AKA_PRIME
     204          19 : 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          19 :         char *network_name = "WLAN";
     209             : 
     210          19 :         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          19 :         data = os_zalloc(sizeof(*data));
     216          19 :         if (data == NULL)
     217           0 :                 return NULL;
     218             : 
     219          19 :         data->eap_method = EAP_TYPE_AKA_PRIME;
     220          19 :         data->network_name = (u8 *) os_strdup(network_name);
     221          19 :         if (data->network_name == NULL) {
     222           0 :                 os_free(data);
     223           0 :                 return NULL;
     224             :         }
     225             : 
     226          19 :         data->network_name_len = os_strlen(network_name);
     227             : 
     228          19 :         data->state = IDENTITY;
     229          19 :         data->pending_id = -1;
     230          19 :         eap_aka_check_identity(sm, data);
     231             : 
     232          19 :         return data;
     233             : }
     234             : #endif /* EAP_SERVER_AKA_PRIME */
     235             : 
     236             : 
     237          57 : static void eap_aka_reset(struct eap_sm *sm, void *priv)
     238             : {
     239          57 :         struct eap_aka_data *data = priv;
     240          57 :         os_free(data->next_pseudonym);
     241          57 :         os_free(data->next_reauth_id);
     242          57 :         wpabuf_free(data->id_msgs);
     243          57 :         os_free(data->network_name);
     244          57 :         bin_clear_free(data, sizeof(*data));
     245          57 : }
     246             : 
     247             : 
     248         100 : static int eap_aka_add_id_msg(struct eap_aka_data *data,
     249             :                               const struct wpabuf *msg)
     250             : {
     251         100 :         if (msg == NULL)
     252           0 :                 return -1;
     253             : 
     254         100 :         if (data->id_msgs == NULL) {
     255          43 :                 data->id_msgs = wpabuf_dup(msg);
     256          43 :                 return data->id_msgs == NULL ? -1 : 0;
     257             :         }
     258             : 
     259          57 :         if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
     260           0 :                 return -1;
     261          57 :         wpabuf_put_buf(data->id_msgs, msg);
     262             : 
     263          57 :         return 0;
     264             : }
     265             : 
     266             : 
     267          64 : 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          64 :         wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
     275             : 
     276          64 :         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          80 :                 return;
     283             :         }
     284             : 
     285             :         /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
     286          48 :         addr = wpabuf_head(data->id_msgs);
     287          48 :         len = wpabuf_len(data->id_msgs);
     288          48 :         wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
     289          48 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     290          12 :                 sha256_vector(1, &addr, &len, hash);
     291             :         else
     292          36 :                 sha1_vector(1, &addr, &len, hash);
     293             : 
     294          48 :         eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
     295          48 :                         data->eap_method == EAP_TYPE_AKA_PRIME ?
     296             :                         EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
     297             : }
     298             : 
     299             : 
     300          27 : 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          27 :         if (checkcode == NULL)
     309           0 :                 return -1;
     310             : 
     311          27 :         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          25 :         hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
     322             :                 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
     323             : 
     324          25 :         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          25 :         addr = wpabuf_head(data->id_msgs);
     333          25 :         len = wpabuf_len(data->id_msgs);
     334          25 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     335          11 :                 sha256_vector(1, &addr, &len, hash);
     336             :         else
     337          14 :                 sha1_vector(1, &addr, &len, hash);
     338             : 
     339          25 :         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          25 :         return 0;
     345             : }
     346             : 
     347             : 
     348          50 : 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          50 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
     355          50 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     356             :                                EAP_AKA_SUBTYPE_IDENTITY);
     357          50 :         data->identity_round++;
     358          50 :         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          43 :                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
     365          43 :                 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          50 :         buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
     381          50 :         if (eap_aka_add_id_msg(data, buf) < 0) {
     382           0 :                 wpabuf_free(buf);
     383           0 :                 return NULL;
     384             :         }
     385          50 :         data->pending_id = id;
     386          50 :         return buf;
     387             : }
     388             : 
     389             : 
     390          64 : 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          64 :         os_free(data->next_pseudonym);
     395          64 :         if (nonce_s == NULL) {
     396          50 :                 data->next_pseudonym =
     397          50 :                         eap_sim_db_get_next_pseudonym(
     398             :                                 sm->eap_sim_db_priv,
     399          50 :                                 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          64 :         os_free(data->next_reauth_id);
     406          64 :         if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
     407          62 :                 data->next_reauth_id =
     408          62 :                         eap_sim_db_get_next_reauth_id(
     409             :                                 sm->eap_sim_db_priv,
     410          62 :                                 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          64 :         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
     419           0 :             counter == 0 && nonce_s == NULL)
     420           0 :                 return 0;
     421             : 
     422          64 :         wpa_printf(MSG_DEBUG, "   AT_IV");
     423          64 :         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     424          64 :         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
     425             : 
     426          64 :         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          64 :         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          64 :         if (data->next_pseudonym) {
     438          50 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
     439             :                            data->next_pseudonym);
     440         100 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
     441          50 :                                 os_strlen(data->next_pseudonym),
     442          50 :                                 (u8 *) data->next_pseudonym,
     443          50 :                                 os_strlen(data->next_pseudonym));
     444             :         }
     445             : 
     446          64 :         if (data->next_reauth_id) {
     447          62 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
     448             :                            data->next_reauth_id);
     449         124 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
     450          62 :                                 os_strlen(data->next_reauth_id),
     451          62 :                                 (u8 *) data->next_reauth_id,
     452          62 :                                 os_strlen(data->next_reauth_id));
     453             :         }
     454             : 
     455          64 :         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          64 :         return 0;
     462             : }
     463             : 
     464             : 
     465          50 : 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          50 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
     472          50 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
     473             :                                EAP_AKA_SUBTYPE_CHALLENGE);
     474          50 :         wpa_printf(MSG_DEBUG, "   AT_RAND");
     475          50 :         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
     476          50 :         wpa_printf(MSG_DEBUG, "   AT_AUTN");
     477          50 :         eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
     478          50 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     479          13 :                 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          13 :                 wpa_printf(MSG_DEBUG, "   AT_KDF");
     486          13 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
     487             :                                 NULL, 0);
     488          13 :                 wpa_printf(MSG_DEBUG, "   AT_KDF_INPUT");
     489          26 :                 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
     490          13 :                                 data->network_name_len,
     491          13 :                                 data->network_name, data->network_name_len);
     492             :         }
     493             : 
     494          50 :         if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
     495           0 :                 eap_sim_msg_free(msg);
     496           0 :                 return NULL;
     497             :         }
     498             : 
     499          50 :         eap_aka_add_checkcode(data, msg);
     500             : 
     501          50 :         if (sm->eap_sim_aka_result_ind) {
     502          47 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     503          47 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     504             :         }
     505             : 
     506             : #ifdef EAP_SERVER_AKA_PRIME
     507          50 :         if (data->eap_method == EAP_TYPE_AKA) {
     508          37 :                 u16 flags = 0;
     509             :                 int i;
     510          37 :                 int aka_prime_preferred = 0;
     511             : 
     512          37 :                 i = 0;
     513         111 :                 while (sm->user && i < EAP_MAX_METHODS &&
     514          74 :                        (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
     515          37 :                         sm->user->methods[i].method != EAP_TYPE_NONE)) {
     516          37 :                         if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
     517          37 :                                 if (sm->user->methods[i].method ==
     518             :                                     EAP_TYPE_AKA)
     519          37 :                                         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          37 :                 if (aka_prime_preferred)
     530           0 :                         flags |= EAP_AKA_BIDDING_FLAG_D;
     531          37 :                 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
     532             :         }
     533             : #endif /* EAP_SERVER_AKA_PRIME */
     534             : 
     535          50 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     536          50 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     537          50 :         return eap_sim_msg_finish(msg, data->eap_method, 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->eap_method, 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->eap_method, data->k_aut, NULL, 0);
     624             : }
     625             : 
     626             : 
     627         118 : static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id)
     628             : {
     629         118 :         struct eap_aka_data *data = priv;
     630             : 
     631         118 :         data->auts_reported = 0;
     632         118 :         switch (data->state) {
     633             :         case IDENTITY:
     634          50 :                 return eap_aka_build_identity(sm, data, id);
     635             :         case CHALLENGE:
     636          50 :                 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         122 : static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
     651             :                              struct wpabuf *respData)
     652             : {
     653         122 :         struct eap_aka_data *data = priv;
     654             :         const u8 *pos;
     655             :         size_t len;
     656             : 
     657         122 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
     658             :                                &len);
     659         122 :         if (pos == NULL || len < 3) {
     660           0 :                 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
     661           0 :                 return TRUE;
     662             :         }
     663             : 
     664         122 :         return FALSE;
     665             : }
     666             : 
     667             : 
     668         168 : static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
     669             : {
     670         168 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
     671             :             subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
     672          20 :                 return FALSE;
     673             : 
     674         148 :         switch (data->state) {
     675             :         case IDENTITY:
     676          93 :                 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          93 :                 break;
     682             :         case CHALLENGE:
     683          37 :                 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          37 :                 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         148 :         return FALSE;
     711             : }
     712             : 
     713             : 
     714          93 : static void eap_aka_determine_identity(struct eap_sm *sm,
     715             :                                        struct eap_aka_data *data)
     716             : {
     717             :         char *username;
     718             : 
     719         186 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
     720          93 :                           sm->identity, sm->identity_len);
     721             : 
     722          93 :         username = sim_get_username(sm->identity, sm->identity_len);
     723          93 :         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          93 :         if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
     730           0 :                 os_free(username);
     731           0 :                 return;
     732             :         }
     733             : 
     734         120 :         if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
     735         118 :               username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
     736         157 :              (data->eap_method == EAP_TYPE_AKA &&
     737          70 :               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         114 :         if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     746         111 :              username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
     747         150 :             (data->eap_method == EAP_TYPE_AKA &&
     748          68 :              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         104 :         } else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
     764          82 :                     username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
     765         120 :                    (data->eap_method == EAP_TYPE_AKA &&
     766          60 :                     username[0] == EAP_AKA_PERMANENT_PREFIX)) {
     767          82 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
     768             :                            username);
     769          82 :                 os_strlcpy(data->permanent, username, sizeof(data->permanent));
     770          82 :                 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          86 :         eap_aka_fullauth(sm, data);
     781             : }
     782             : 
     783             : 
     784         100 : 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         200 :         res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
     790         100 :                                       data->rand, data->autn, data->ik,
     791         100 :                                       data->ck, data->res, &data->res_len, sm);
     792         100 :         if (res == EAP_SIM_DB_PENDING) {
     793          50 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
     794             :                            "not yet available - pending request");
     795          50 :                 sm->method_pending = METHOD_PENDING_WAIT;
     796          50 :                 return;
     797             :         }
     798             : 
     799             : #ifdef EAP_SERVER_AKA_PRIME
     800          50 :         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          26 :                 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
     804          13 :                                                  data->autn,
     805          13 :                                                  data->network_name,
     806             :                                                  data->network_name_len);
     807             :         }
     808             : #endif /* EAP_SERVER_AKA_PRIME */
     809             : 
     810          50 :         data->reauth = NULL;
     811          50 :         data->counter = 0; /* reset re-auth counter since this is full auth */
     812             : 
     813          50 :         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          50 :         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          50 :         identity_len = sm->identity_len;
     827         100 :         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          50 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
     833          50 :                           sm->identity, identity_len);
     834             : 
     835          50 :         if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     836          13 :                 eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik,
     837          13 :                                           data->ck, data->k_encr, data->k_aut,
     838          13 :                                           data->k_re, data->msk, data->emsk);
     839             :         } else {
     840          37 :                 eap_aka_derive_mk(sm->identity, identity_len, data->ik,
     841          37 :                                   data->ck, data->mk);
     842          37 :                 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
     843          37 :                                     data->msk, data->emsk);
     844             :         }
     845             : 
     846          50 :         eap_aka_state(data, CHALLENGE);
     847             : }
     848             : 
     849             : 
     850          93 : 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          93 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
     858             : 
     859          93 :         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          93 :         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          93 :         new_identity = os_malloc(attr->identity_len);
     880          93 :         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          93 :         os_free(sm->identity);
     886          93 :         sm->identity = new_identity;
     887          93 :         os_memcpy(sm->identity, attr->identity, attr->identity_len);
     888          93 :         sm->identity_len = attr->identity_len;
     889             : 
     890          93 :         eap_aka_determine_identity(sm, data);
     891          93 :         if (eap_get_id(respData) == data->pending_id) {
     892          50 :                 data->pending_id = -1;
     893          50 :                 eap_aka_add_id_msg(data, respData);
     894             :         }
     895             : }
     896             : 
     897             : 
     898          41 : 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          41 :         if (data->eap_method == EAP_TYPE_AKA_PRIME)
     904          19 :                 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
     905             :                                                  extra_len);
     906          22 :         return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
     907             : }
     908             : 
     909             : 
     910          27 : 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          27 :         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          54 :         if (attr->checkcode &&
     943          27 :             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          54 :         if (attr->mac == NULL ||
     952          27 :             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          54 :         if (attr->res == NULL || attr->res_len < data->res_len ||
     965          54 :             attr->res_len_bits != data->res_len * 8 ||
     966          27 :             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          27 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
     979             :                    "correct AT_MAC");
     980          27 :         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          25 :                 eap_aka_state(data, SUCCESS);
     986             : 
     987          27 :         if (data->next_pseudonym) {
     988          27 :                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
     989             :                                          data->next_pseudonym);
     990          27 :                 data->next_pseudonym = NULL;
     991             :         }
     992          27 :         if (data->next_reauth_id) {
     993          27 :                 if (data->eap_method == EAP_TYPE_AKA_PRIME) {
     994             : #ifdef EAP_SERVER_AKA_PRIME
     995          24 :                         eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
     996          12 :                                                     data->permanent,
     997             :                                                     data->next_reauth_id,
     998          12 :                                                     data->counter + 1,
     999          12 :                                                     data->k_encr, data->k_aut,
    1000          12 :                                                     data->k_re);
    1001             : #endif /* EAP_SERVER_AKA_PRIME */
    1002             :                 } else {
    1003          30 :                         eap_sim_db_add_reauth(sm->eap_sim_db_priv,
    1004          15 :                                               data->permanent,
    1005             :                                               data->next_reauth_id,
    1006          15 :                                               data->counter + 1,
    1007          15 :                                               data->mk);
    1008             :                 }
    1009          27 :                 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          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          17 : 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          17 :         wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
    1160          17 :         eap_aka_state(data, FAILURE);
    1161          17 : }
    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         168 : static void eap_aka_process(struct eap_sm *sm, void *priv,
    1178             :                             struct wpabuf *respData)
    1179             : {
    1180         168 :         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         168 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
    1187             :                                &len);
    1188         168 :         if (pos == NULL || len < 3)
    1189          20 :                 return;
    1190             : 
    1191         168 :         end = pos + len;
    1192         168 :         subtype = *pos;
    1193         168 :         pos += 3;
    1194             : 
    1195         168 :         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         168 :         if (eap_sim_parse_attr(pos, end, &attr,
    1204         168 :                                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         168 :         if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
    1213           3 :                 eap_aka_process_client_error(sm, data, respData, &attr);
    1214           3 :                 return;
    1215             :         }
    1216             : 
    1217         165 :         if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
    1218          17 :                 eap_aka_process_authentication_reject(sm, data, respData,
    1219             :                                                       &attr);
    1220          17 :                 return;
    1221             :         }
    1222             : 
    1223         148 :         switch (data->state) {
    1224             :         case IDENTITY:
    1225          93 :                 eap_aka_process_identity(sm, data, respData, &attr);
    1226          93 :                 break;
    1227             :         case CHALLENGE:
    1228          37 :                 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
    1229          10 :                         eap_aka_process_sync_failure(sm, data, respData,
    1230             :                                                      &attr);
    1231             :                 } else {
    1232          27 :                         eap_aka_process_challenge(sm, data, respData, &attr);
    1233             :                 }
    1234          37 :                 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         188 : static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
    1250             : {
    1251         188 :         struct eap_aka_data *data = priv;
    1252         188 :         return data->state == SUCCESS || data->state == FAILURE;
    1253             : }
    1254             : 
    1255             : 
    1256          56 : static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
    1257             : {
    1258          56 :         struct eap_aka_data *data = priv;
    1259             :         u8 *key;
    1260             : 
    1261          56 :         if (data->state != SUCCESS)
    1262          20 :                 return NULL;
    1263             : 
    1264          36 :         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
    1265          36 :         if (key == NULL)
    1266           0 :                 return NULL;
    1267          36 :         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
    1268          36 :         *len = EAP_SIM_KEYING_DATA_LEN;
    1269          36 :         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          77 : static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
    1291             : {
    1292          77 :         struct eap_aka_data *data = priv;
    1293          77 :         return data->state == SUCCESS;
    1294             : }
    1295             : 
    1296             : 
    1297          54 : static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
    1298             : {
    1299          54 :         struct eap_aka_data *data = priv;
    1300             :         u8 *id;
    1301             : 
    1302          54 :         if (data->state != SUCCESS)
    1303          20 :                 return NULL;
    1304             : 
    1305          34 :         *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
    1306          34 :         id = os_malloc(*len);
    1307          34 :         if (id == NULL)
    1308           0 :                 return NULL;
    1309             : 
    1310          34 :         id[0] = data->eap_method;
    1311          34 :         os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
    1312          34 :         os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
    1313          34 :         wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
    1314             : 
    1315          34 :         return id;
    1316             : }
    1317             : 
    1318             : 
    1319          25 : int eap_server_aka_register(void)
    1320             : {
    1321             :         struct eap_method *eap;
    1322             :         int ret;
    1323             : 
    1324          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1325             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
    1326          25 :         if (eap == NULL)
    1327           0 :                 return -1;
    1328             : 
    1329          25 :         eap->init = eap_aka_init;
    1330          25 :         eap->reset = eap_aka_reset;
    1331          25 :         eap->buildReq = eap_aka_buildReq;
    1332          25 :         eap->check = eap_aka_check;
    1333          25 :         eap->process = eap_aka_process;
    1334          25 :         eap->isDone = eap_aka_isDone;
    1335          25 :         eap->getKey = eap_aka_getKey;
    1336          25 :         eap->isSuccess = eap_aka_isSuccess;
    1337          25 :         eap->get_emsk = eap_aka_get_emsk;
    1338          25 :         eap->getSessionId = eap_aka_get_session_id;
    1339             : 
    1340          25 :         ret = eap_server_method_register(eap);
    1341          25 :         if (ret)
    1342           0 :                 eap_server_method_free(eap);
    1343          25 :         return ret;
    1344             : }
    1345             : 
    1346             : 
    1347             : #ifdef EAP_SERVER_AKA_PRIME
    1348          25 : int eap_server_aka_prime_register(void)
    1349             : {
    1350             :         struct eap_method *eap;
    1351             :         int ret;
    1352             : 
    1353          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
    1354             :                                       EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
    1355             :                                       "AKA'");
    1356          25 :         if (eap == NULL)
    1357           0 :                 return -1;
    1358             : 
    1359          25 :         eap->init = eap_aka_prime_init;
    1360          25 :         eap->reset = eap_aka_reset;
    1361          25 :         eap->buildReq = eap_aka_buildReq;
    1362          25 :         eap->check = eap_aka_check;
    1363          25 :         eap->process = eap_aka_process;
    1364          25 :         eap->isDone = eap_aka_isDone;
    1365          25 :         eap->getKey = eap_aka_getKey;
    1366          25 :         eap->isSuccess = eap_aka_isSuccess;
    1367          25 :         eap->get_emsk = eap_aka_get_emsk;
    1368          25 :         eap->getSessionId = eap_aka_get_session_id;
    1369             : 
    1370          25 :         ret = eap_server_method_register(eap);
    1371          25 :         if (ret)
    1372           0 :                 eap_server_method_free(eap);
    1373             : 
    1374          25 :         return ret;
    1375             : }
    1376             : #endif /* EAP_SERVER_AKA_PRIME */

Generated by: LCOV version 1.10