LCOV - code coverage report
Current view: top level - eap_server - eap_server_aka.c (source / functions) Hit Total Coverage
Test: hostapd hwsim test run 1401872338 Lines: 454 669 67.9 %
Date: 2014-06-04 Functions: 31 35 88.6 %

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

Generated by: LCOV version 1.10