LCOV - code coverage report
Current view: top level - src/eap_server - eap_server_sim.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 357 445 80.2 %
Date: 2015-09-27 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-SIM (RFC 4186)
       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/random.h"
      13             : #include "eap_server/eap_i.h"
      14             : #include "eap_common/eap_sim_common.h"
      15             : #include "eap_server/eap_sim_db.h"
      16             : 
      17             : 
      18             : struct eap_sim_data {
      19             :         u8 mk[EAP_SIM_MK_LEN];
      20             :         u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
      21             :         u8 nonce_s[EAP_SIM_NONCE_S_LEN];
      22             :         u8 k_aut[EAP_SIM_K_AUT_LEN];
      23             :         u8 k_encr[EAP_SIM_K_ENCR_LEN];
      24             :         u8 msk[EAP_SIM_KEYING_DATA_LEN];
      25             :         u8 emsk[EAP_EMSK_LEN];
      26             :         u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
      27             :         u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
      28             :         u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
      29             :         int num_chal;
      30             :         enum {
      31             :                 START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
      32             :         } state;
      33             :         char *next_pseudonym;
      34             :         char *next_reauth_id;
      35             :         u16 counter;
      36             :         struct eap_sim_reauth *reauth;
      37             :         u16 notification;
      38             :         int use_result_ind;
      39             :         int start_round;
      40             :         char permanent[20]; /* Permanent username */
      41             : };
      42             : 
      43             : 
      44         216 : static const char * eap_sim_state_txt(int state)
      45             : {
      46         216 :         switch (state) {
      47             :         case START:
      48          54 :                 return "START";
      49             :         case CHALLENGE:
      50          90 :                 return "CHALLENGE";
      51             :         case REAUTH:
      52          14 :                 return "REAUTH";
      53             :         case SUCCESS:
      54          25 :                 return "SUCCESS";
      55             :         case FAILURE:
      56          27 :                 return "FAILURE";
      57             :         case NOTIFICATION:
      58           6 :                 return "NOTIFICATION";
      59             :         default:
      60           0 :                 return "Unknown?!";
      61             :         }
      62             : }
      63             : 
      64             : 
      65         108 : static void eap_sim_state(struct eap_sim_data *data, int state)
      66             : {
      67         216 :         wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
      68         108 :                    eap_sim_state_txt(data->state),
      69             :                    eap_sim_state_txt(state));
      70         108 :         data->state = state;
      71         108 : }
      72             : 
      73             : 
      74          54 : static void * eap_sim_init(struct eap_sm *sm)
      75             : {
      76             :         struct eap_sim_data *data;
      77             : 
      78          54 :         if (sm->eap_sim_db_priv == NULL) {
      79           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured");
      80           0 :                 return NULL;
      81             :         }
      82             : 
      83          54 :         data = os_zalloc(sizeof(*data));
      84          54 :         if (data == NULL)
      85           0 :                 return NULL;
      86          54 :         data->state = START;
      87             : 
      88          54 :         return data;
      89             : }
      90             : 
      91             : 
      92          54 : static void eap_sim_reset(struct eap_sm *sm, void *priv)
      93             : {
      94          54 :         struct eap_sim_data *data = priv;
      95          54 :         os_free(data->next_pseudonym);
      96          54 :         os_free(data->next_reauth_id);
      97          54 :         bin_clear_free(data, sizeof(*data));
      98          54 : }
      99             : 
     100             : 
     101          59 : static struct wpabuf * eap_sim_build_start(struct eap_sm *sm,
     102             :                                            struct eap_sim_data *data, u8 id)
     103             : {
     104             :         struct eap_sim_msg *msg;
     105             :         u8 ver[2];
     106             : 
     107          59 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
     108          59 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
     109             :                                EAP_SIM_SUBTYPE_START);
     110          59 :         data->start_round++;
     111          59 :         if (data->start_round == 1) {
     112             :                 /*
     113             :                  * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
     114             :                  * ignored and the SIM/Start is used to request the identity.
     115             :                  */
     116          54 :                 wpa_printf(MSG_DEBUG, "   AT_ANY_ID_REQ");
     117          54 :                 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
     118           5 :         } else if (data->start_round > 3) {
     119             :                 /* Cannot use more than three rounds of Start messages */
     120           0 :                 eap_sim_msg_free(msg);
     121           0 :                 return NULL;
     122           5 :         } else if (data->start_round == 0) {
     123             :                 /*
     124             :                  * This is a special case that is used to recover from
     125             :                  * AT_COUNTER_TOO_SMALL during re-authentication. Since we
     126             :                  * already know the identity of the peer, there is no need to
     127             :                  * request any identity in this case.
     128             :                  */
     129           8 :         } else if (sm->identity && sm->identity_len > 0 &&
     130           4 :                    sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
     131             :                 /* Reauth id may have expired - try fullauth */
     132           2 :                 wpa_printf(MSG_DEBUG, "   AT_FULLAUTH_ID_REQ");
     133           2 :                 eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
     134             :         } else {
     135           2 :                 wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
     136           2 :                 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
     137             :         }
     138          59 :         wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
     139          59 :         ver[0] = 0;
     140          59 :         ver[1] = EAP_SIM_VERSION;
     141          59 :         eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
     142             :                         ver, sizeof(ver));
     143          59 :         return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0);
     144             : }
     145             : 
     146             : 
     147          52 : static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
     148             :                               struct eap_sim_msg *msg, u16 counter,
     149             :                               const u8 *nonce_s)
     150             : {
     151          52 :         os_free(data->next_pseudonym);
     152          52 :         if (nonce_s == NULL) {
     153          45 :                 data->next_pseudonym =
     154          45 :                         eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv,
     155             :                                                       EAP_SIM_DB_SIM);
     156             :         } else {
     157             :                 /* Do not update pseudonym during re-authentication */
     158           7 :                 data->next_pseudonym = NULL;
     159             :         }
     160          52 :         os_free(data->next_reauth_id);
     161          52 :         if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
     162          51 :                 data->next_reauth_id =
     163          51 :                         eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv,
     164             :                                                       EAP_SIM_DB_SIM);
     165             :         } else {
     166           1 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
     167             :                            "count exceeded - force full authentication");
     168           1 :                 data->next_reauth_id = NULL;
     169             :         }
     170             : 
     171          52 :         if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
     172           0 :             counter == 0 && nonce_s == NULL)
     173           0 :                 return 0;
     174             : 
     175          52 :         wpa_printf(MSG_DEBUG, "   AT_IV");
     176          52 :         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     177          52 :         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
     178             : 
     179          52 :         if (counter > 0) {
     180           7 :                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
     181           7 :                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
     182             :         }
     183             : 
     184          52 :         if (nonce_s) {
     185           7 :                 wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
     186           7 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
     187             :                                 EAP_SIM_NONCE_S_LEN);
     188             :         }
     189             : 
     190          52 :         if (data->next_pseudonym) {
     191          45 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
     192             :                            data->next_pseudonym);
     193          90 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
     194          45 :                                 os_strlen(data->next_pseudonym),
     195          45 :                                 (u8 *) data->next_pseudonym,
     196          45 :                                 os_strlen(data->next_pseudonym));
     197             :         }
     198             : 
     199          52 :         if (data->next_reauth_id) {
     200          51 :                 wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
     201             :                            data->next_reauth_id);
     202         102 :                 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
     203          51 :                                 os_strlen(data->next_reauth_id),
     204          51 :                                 (u8 *) data->next_reauth_id,
     205          51 :                                 os_strlen(data->next_reauth_id));
     206             :         }
     207             : 
     208          52 :         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
     209           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
     210             :                            "AT_ENCR_DATA");
     211           0 :                 return -1;
     212             :         }
     213             : 
     214          52 :         return 0;
     215             : }
     216             : 
     217             : 
     218          45 : static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm,
     219             :                                                struct eap_sim_data *data,
     220             :                                                u8 id)
     221             : {
     222             :         struct eap_sim_msg *msg;
     223             : 
     224          45 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
     225          45 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
     226             :                                EAP_SIM_SUBTYPE_CHALLENGE);
     227          45 :         wpa_printf(MSG_DEBUG, "   AT_RAND");
     228          45 :         eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
     229          45 :                         data->num_chal * GSM_RAND_LEN);
     230             : 
     231          45 :         if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
     232           0 :                 eap_sim_msg_free(msg);
     233           0 :                 return NULL;
     234             :         }
     235             : 
     236          45 :         if (sm->eap_sim_aka_result_ind) {
     237          44 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     238          44 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     239             :         }
     240             : 
     241          45 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     242          45 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     243          45 :         return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut,
     244          45 :                                   data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
     245             : }
     246             : 
     247             : 
     248           7 : static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm,
     249             :                                             struct eap_sim_data *data, u8 id)
     250             : {
     251             :         struct eap_sim_msg *msg;
     252             : 
     253           7 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
     254             : 
     255           7 :         if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN))
     256           0 :                 return NULL;
     257           7 :         wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
     258           7 :                         data->nonce_s, EAP_SIM_NONCE_S_LEN);
     259             : 
     260           7 :         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
     261           7 :                             data->emsk);
     262           7 :         eap_sim_derive_keys_reauth(data->counter, sm->identity,
     263           7 :                                    sm->identity_len, data->nonce_s, data->mk,
     264           7 :                                    data->msk, data->emsk);
     265             : 
     266           7 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
     267             :                                EAP_SIM_SUBTYPE_REAUTHENTICATION);
     268             : 
     269           7 :         if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
     270           0 :                 eap_sim_msg_free(msg);
     271           0 :                 return NULL;
     272             :         }
     273             : 
     274           7 :         if (sm->eap_sim_aka_result_ind) {
     275           7 :                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
     276           7 :                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
     277             :         }
     278             : 
     279           7 :         wpa_printf(MSG_DEBUG, "   AT_MAC");
     280           7 :         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     281           7 :         return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
     282             : }
     283             : 
     284             : 
     285           3 : static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm,
     286             :                                                   struct eap_sim_data *data,
     287             :                                                   u8 id)
     288             : {
     289             :         struct eap_sim_msg *msg;
     290             : 
     291           3 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification");
     292           3 :         msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
     293             :                                EAP_SIM_SUBTYPE_NOTIFICATION);
     294           3 :         wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
     295           3 :         eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
     296             :                         NULL, 0);
     297           3 :         if (data->use_result_ind) {
     298           2 :                 if (data->reauth) {
     299           1 :                         wpa_printf(MSG_DEBUG, "   AT_IV");
     300           1 :                         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
     301           1 :                         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
     302             :                                                    EAP_SIM_AT_ENCR_DATA);
     303           1 :                         wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)",
     304           1 :                                    data->counter);
     305           1 :                         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
     306             :                                         NULL, 0);
     307             : 
     308           1 :                         if (eap_sim_msg_add_encr_end(msg, data->k_encr,
     309             :                                                      EAP_SIM_AT_PADDING)) {
     310           0 :                                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to "
     311             :                                            "encrypt AT_ENCR_DATA");
     312           0 :                                 eap_sim_msg_free(msg);
     313           0 :                                 return NULL;
     314             :                         }
     315             :                 }
     316             : 
     317           2 :                 wpa_printf(MSG_DEBUG, "   AT_MAC");
     318           2 :                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
     319             :         }
     320           3 :         return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0);
     321             : }
     322             : 
     323             : 
     324         114 : static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id)
     325             : {
     326         114 :         struct eap_sim_data *data = priv;
     327             : 
     328         114 :         switch (data->state) {
     329             :         case START:
     330          59 :                 return eap_sim_build_start(sm, data, id);
     331             :         case CHALLENGE:
     332          45 :                 return eap_sim_build_challenge(sm, data, id);
     333             :         case REAUTH:
     334           7 :                 return eap_sim_build_reauth(sm, data, id);
     335             :         case NOTIFICATION:
     336           3 :                 return eap_sim_build_notification(sm, data, id);
     337             :         default:
     338           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
     339           0 :                            "buildReq", data->state);
     340           0 :                 break;
     341             :         }
     342           0 :         return NULL;
     343             : }
     344             : 
     345             : 
     346         112 : static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
     347             :                              struct wpabuf *respData)
     348             : {
     349             :         const u8 *pos;
     350             :         size_t len;
     351             : 
     352         112 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
     353         112 :         if (pos == NULL || len < 3) {
     354           0 :                 wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
     355           0 :                 return TRUE;
     356             :         }
     357             : 
     358         112 :         return FALSE;
     359             : }
     360             : 
     361             : 
     362         158 : static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
     363             :                                           u8 subtype)
     364             : {
     365         158 :         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
     366          26 :                 return FALSE;
     367             : 
     368         132 :         switch (data->state) {
     369             :         case START:
     370         103 :                 if (subtype != EAP_SIM_SUBTYPE_START) {
     371           0 :                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
     372             :                                    "subtype %d", subtype);
     373           0 :                         return TRUE;
     374             :                 }
     375         103 :                 break;
     376             :         case CHALLENGE:
     377          20 :                 if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) {
     378           0 :                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
     379             :                                    "subtype %d", subtype);
     380           0 :                         return TRUE;
     381             :                 }
     382          20 :                 break;
     383             :         case REAUTH:
     384           6 :                 if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
     385           0 :                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
     386             :                                    "subtype %d", subtype);
     387           0 :                         return TRUE;
     388             :                 }
     389           6 :                 break;
     390             :         case NOTIFICATION:
     391           3 :                 if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) {
     392           0 :                         wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
     393             :                                    "subtype %d", subtype);
     394           0 :                         return TRUE;
     395             :                 }
     396           3 :                 break;
     397             :         default:
     398           0 :                 wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
     399           0 :                            "processing a response", data->state);
     400           0 :                 return TRUE;
     401             :         }
     402             : 
     403         132 :         return FALSE;
     404             : }
     405             : 
     406             : 
     407          92 : static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
     408             : {
     409          92 :         return version == EAP_SIM_VERSION;
     410             : }
     411             : 
     412             : 
     413         103 : static void eap_sim_process_start(struct eap_sm *sm,
     414             :                                   struct eap_sim_data *data,
     415             :                                   struct wpabuf *respData,
     416             :                                   struct eap_sim_attrs *attr)
     417             : {
     418             :         size_t identity_len;
     419             :         u8 ver_list[2];
     420             :         u8 *new_identity;
     421             :         char *username;
     422             : 
     423         103 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
     424             : 
     425         103 :         if (data->start_round == 0) {
     426             :                 /*
     427             :                  * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
     428             :                  * was requested since we already know it.
     429             :                  */
     430           2 :                 goto skip_id_update;
     431             :         }
     432             : 
     433             :         /*
     434             :          * We always request identity in SIM/Start, so the peer is required to
     435             :          * have replied with one.
     436             :          */
     437         101 :         if (!attr->identity || attr->identity_len == 0) {
     438           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
     439             :                            "identity");
     440           0 :                 goto failed;
     441             :         }
     442             : 
     443         101 :         new_identity = os_malloc(attr->identity_len);
     444         101 :         if (new_identity == NULL)
     445           0 :                 goto failed;
     446         101 :         os_free(sm->identity);
     447         101 :         sm->identity = new_identity;
     448         101 :         os_memcpy(sm->identity, attr->identity, attr->identity_len);
     449         101 :         sm->identity_len = attr->identity_len;
     450             : 
     451         202 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
     452         101 :                           sm->identity, sm->identity_len);
     453         101 :         username = sim_get_username(sm->identity, sm->identity_len);
     454         101 :         if (username == NULL)
     455           0 :                 goto failed;
     456             : 
     457         101 :         if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
     458           9 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
     459             :                            username);
     460           9 :                 data->reauth = eap_sim_db_get_reauth_entry(
     461             :                         sm->eap_sim_db_priv, username);
     462           9 :                 os_free(username);
     463           9 :                 if (data->reauth == NULL) {
     464           2 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
     465             :                                    "identity - request full auth identity");
     466             :                         /* Remain in START state for another round */
     467           2 :                         return;
     468             :                 }
     469           7 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
     470           7 :                 os_strlcpy(data->permanent, data->reauth->permanent,
     471             :                            sizeof(data->permanent));
     472           7 :                 data->counter = data->reauth->counter;
     473           7 :                 os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
     474           7 :                 eap_sim_state(data, REAUTH);
     475           7 :                 return;
     476             :         }
     477             : 
     478          92 :         if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
     479             :                 const char *permanent;
     480           4 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
     481             :                            username);
     482           4 :                 permanent = eap_sim_db_get_permanent(
     483             :                         sm->eap_sim_db_priv, username);
     484           4 :                 os_free(username);
     485           4 :                 if (permanent == NULL) {
     486           2 :                         wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
     487             :                                    "identity - request permanent identity");
     488             :                         /* Remain in START state for another round */
     489           2 :                         return;
     490             :                 }
     491           2 :                 os_strlcpy(data->permanent, permanent,
     492             :                            sizeof(data->permanent));
     493          88 :         } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
     494          88 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
     495             :                            username);
     496          88 :                 os_strlcpy(data->permanent, username, sizeof(data->permanent));
     497          88 :                 os_free(username);
     498             :         } else {
     499           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
     500             :                            username);
     501           0 :                 os_free(username);
     502           0 :                 goto failed;
     503             :         }
     504             : 
     505             : skip_id_update:
     506             :         /* Full authentication */
     507             : 
     508          92 :         if (attr->nonce_mt == NULL || attr->selected_version < 0) {
     509           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
     510             :                            "required attributes");
     511           0 :                 goto failed;
     512             :         }
     513             : 
     514          92 :         if (!eap_sim_supported_ver(data, attr->selected_version)) {
     515           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
     516             :                            "version %d", attr->selected_version);
     517           0 :                 goto failed;
     518             :         }
     519             : 
     520          92 :         data->counter = 0; /* reset re-auth counter since this is full auth */
     521          92 :         data->reauth = NULL;
     522             : 
     523          92 :         data->num_chal = eap_sim_db_get_gsm_triplets(
     524          92 :                 sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
     525          92 :                 (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
     526          92 :         if (data->num_chal == EAP_SIM_DB_PENDING) {
     527          46 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
     528             :                            "not yet available - pending request");
     529          46 :                 sm->method_pending = METHOD_PENDING_WAIT;
     530          46 :                 return;
     531             :         }
     532          46 :         if (data->num_chal < 2) {
     533           1 :                 wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
     534             :                            "authentication triplets for the peer");
     535           1 :                 goto failed;
     536             :         }
     537             : 
     538          45 :         identity_len = sm->identity_len;
     539          90 :         while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
     540           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
     541             :                            "character from identity");
     542           0 :                 identity_len--;
     543             :         }
     544          45 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
     545          45 :                           sm->identity, identity_len);
     546             : 
     547          45 :         os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
     548          45 :         WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
     549          90 :         eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt,
     550          45 :                           attr->selected_version, ver_list, sizeof(ver_list),
     551          45 :                           data->num_chal, (const u8 *) data->kc, data->mk);
     552          45 :         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
     553          45 :                             data->emsk);
     554             : 
     555          45 :         eap_sim_state(data, CHALLENGE);
     556          45 :         return;
     557             : 
     558             : failed:
     559           1 :         data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     560           1 :         eap_sim_state(data, NOTIFICATION);
     561             : }
     562             : 
     563             : 
     564          20 : static void eap_sim_process_challenge(struct eap_sm *sm,
     565             :                                       struct eap_sim_data *data,
     566             :                                       struct wpabuf *respData,
     567             :                                       struct eap_sim_attrs *attr)
     568             : {
     569          40 :         if (attr->mac == NULL ||
     570          40 :             eap_sim_verify_mac(data->k_aut, respData, attr->mac,
     571          20 :                                (u8 *) data->sres,
     572          20 :                                data->num_chal * EAP_SIM_SRES_LEN)) {
     573           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
     574             :                            "did not include valid AT_MAC");
     575           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     576           0 :                 eap_sim_state(data, NOTIFICATION);
     577          20 :                 return;
     578             :         }
     579             : 
     580          20 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
     581             :                    "correct AT_MAC");
     582          20 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
     583           1 :                 data->use_result_ind = 1;
     584           1 :                 data->notification = EAP_SIM_SUCCESS;
     585           1 :                 eap_sim_state(data, NOTIFICATION);
     586             :         } else
     587          19 :                 eap_sim_state(data, SUCCESS);
     588             : 
     589          20 :         if (data->next_pseudonym) {
     590          20 :                 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
     591             :                                          data->next_pseudonym);
     592          20 :                 data->next_pseudonym = NULL;
     593             :         }
     594          20 :         if (data->next_reauth_id) {
     595          20 :                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
     596          20 :                                       data->next_reauth_id, data->counter + 1,
     597          20 :                                       data->mk);
     598          20 :                 data->next_reauth_id = NULL;
     599             :         }
     600             : }
     601             : 
     602             : 
     603           6 : static void eap_sim_process_reauth(struct eap_sm *sm,
     604             :                                    struct eap_sim_data *data,
     605             :                                    struct wpabuf *respData,
     606             :                                    struct eap_sim_attrs *attr)
     607             : {
     608             :         struct eap_sim_attrs eattr;
     609           6 :         u8 *decrypted = NULL;
     610             : 
     611          12 :         if (attr->mac == NULL ||
     612           6 :             eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
     613             :                                EAP_SIM_NONCE_S_LEN)) {
     614           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
     615             :                            "did not include valid AT_MAC");
     616           0 :                 goto fail;
     617             :         }
     618             : 
     619           6 :         if (attr->encr_data == NULL || attr->iv == NULL) {
     620           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
     621             :                            "message did not include encrypted data");
     622           0 :                 goto fail;
     623             :         }
     624             : 
     625           6 :         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
     626             :                                        attr->encr_data_len, attr->iv, &eattr,
     627             :                                        0);
     628           6 :         if (decrypted == NULL) {
     629           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
     630             :                            "data from reauthentication message");
     631           0 :                 goto fail;
     632             :         }
     633             : 
     634           6 :         if (eattr.counter != data->counter) {
     635           0 :                 wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
     636             :                            "used incorrect counter %u, expected %u",
     637           0 :                            eattr.counter, data->counter);
     638           0 :                 goto fail;
     639             :         }
     640           6 :         os_free(decrypted);
     641           6 :         decrypted = NULL;
     642             : 
     643           6 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
     644             :                    "the correct AT_MAC");
     645             : 
     646           6 :         if (eattr.counter_too_small) {
     647           1 :                 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
     648             :                            "included AT_COUNTER_TOO_SMALL - starting full "
     649             :                            "authentication");
     650           1 :                 data->start_round = -1;
     651           1 :                 eap_sim_state(data, START);
     652           1 :                 return;
     653             :         }
     654             : 
     655           5 :         if (sm->eap_sim_aka_result_ind && attr->result_ind) {
     656           1 :                 data->use_result_ind = 1;
     657           1 :                 data->notification = EAP_SIM_SUCCESS;
     658           1 :                 eap_sim_state(data, NOTIFICATION);
     659             :         } else
     660           4 :                 eap_sim_state(data, SUCCESS);
     661             : 
     662           5 :         if (data->next_reauth_id) {
     663           4 :                 eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
     664             :                                       data->next_reauth_id,
     665           4 :                                       data->counter + 1, data->mk);
     666           4 :                 data->next_reauth_id = NULL;
     667             :         } else {
     668           1 :                 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
     669           1 :                 data->reauth = NULL;
     670             :         }
     671             : 
     672           5 :         return;
     673             : 
     674             : fail:
     675           0 :         data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     676           0 :         eap_sim_state(data, NOTIFICATION);
     677           0 :         eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
     678           0 :         data->reauth = NULL;
     679           0 :         os_free(decrypted);
     680             : }
     681             : 
     682             : 
     683          26 : static void eap_sim_process_client_error(struct eap_sm *sm,
     684             :                                          struct eap_sim_data *data,
     685             :                                          struct wpabuf *respData,
     686             :                                          struct eap_sim_attrs *attr)
     687             : {
     688          26 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d",
     689             :                    attr->client_error_code);
     690          26 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
     691           0 :                 eap_sim_state(data, SUCCESS);
     692             :         else
     693          26 :                 eap_sim_state(data, FAILURE);
     694          26 : }
     695             : 
     696             : 
     697           3 : static void eap_sim_process_notification(struct eap_sm *sm,
     698             :                                          struct eap_sim_data *data,
     699             :                                          struct wpabuf *respData,
     700             :                                          struct eap_sim_attrs *attr)
     701             : {
     702           3 :         wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification");
     703           3 :         if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind)
     704           2 :                 eap_sim_state(data, SUCCESS);
     705             :         else
     706           1 :                 eap_sim_state(data, FAILURE);
     707           3 : }
     708             : 
     709             : 
     710         158 : static void eap_sim_process(struct eap_sm *sm, void *priv,
     711             :                             struct wpabuf *respData)
     712             : {
     713         158 :         struct eap_sim_data *data = priv;
     714             :         const u8 *pos, *end;
     715             :         u8 subtype;
     716             :         size_t len;
     717             :         struct eap_sim_attrs attr;
     718             : 
     719         158 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
     720         158 :         if (pos == NULL || len < 3)
     721          26 :                 return;
     722             : 
     723         158 :         end = pos + len;
     724         158 :         subtype = *pos;
     725         158 :         pos += 3;
     726             : 
     727         158 :         if (eap_sim_unexpected_subtype(data, subtype)) {
     728           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
     729             :                            "EAP-SIM Subtype in EAP Response");
     730           0 :                 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     731           0 :                 eap_sim_state(data, NOTIFICATION);
     732           0 :                 return;
     733             :         }
     734             : 
     735         158 :         if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
     736           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
     737           0 :                 if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
     738           0 :                     (data->state == START || data->state == CHALLENGE ||
     739           0 :                      data->state == REAUTH)) {
     740           0 :                         data->notification =
     741             :                                 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
     742           0 :                         eap_sim_state(data, NOTIFICATION);
     743           0 :                         return;
     744             :                 }
     745           0 :                 eap_sim_state(data, FAILURE);
     746           0 :                 return;
     747             :         }
     748             : 
     749         158 :         if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) {
     750          26 :                 eap_sim_process_client_error(sm, data, respData, &attr);
     751          26 :                 return;
     752             :         }
     753             : 
     754         132 :         switch (data->state) {
     755             :         case START:
     756         103 :                 eap_sim_process_start(sm, data, respData, &attr);
     757         103 :                 break;
     758             :         case CHALLENGE:
     759          20 :                 eap_sim_process_challenge(sm, data, respData, &attr);
     760          20 :                 break;
     761             :         case REAUTH:
     762           6 :                 eap_sim_process_reauth(sm, data, respData, &attr);
     763           6 :                 break;
     764             :         case NOTIFICATION:
     765           3 :                 eap_sim_process_notification(sm, data, respData, &attr);
     766           3 :                 break;
     767             :         default:
     768           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
     769           0 :                            "process", data->state);
     770           0 :                 break;
     771             :         }
     772             : }
     773             : 
     774             : 
     775         185 : static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv)
     776             : {
     777         185 :         struct eap_sim_data *data = priv;
     778         185 :         return data->state == SUCCESS || data->state == FAILURE;
     779             : }
     780             : 
     781             : 
     782          52 : static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
     783             : {
     784          52 :         struct eap_sim_data *data = priv;
     785             :         u8 *key;
     786             : 
     787          52 :         if (data->state != SUCCESS)
     788          27 :                 return NULL;
     789             : 
     790          25 :         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
     791          25 :         if (key == NULL)
     792           0 :                 return NULL;
     793          25 :         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
     794          25 :         *len = EAP_SIM_KEYING_DATA_LEN;
     795          25 :         return key;
     796             : }
     797             : 
     798             : 
     799           1 : static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
     800             : {
     801           1 :         struct eap_sim_data *data = priv;
     802             :         u8 *key;
     803             : 
     804           1 :         if (data->state != SUCCESS)
     805           0 :                 return NULL;
     806             : 
     807           1 :         key = os_malloc(EAP_EMSK_LEN);
     808           1 :         if (key == NULL)
     809           0 :                 return NULL;
     810           1 :         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
     811           1 :         *len = EAP_EMSK_LEN;
     812           1 :         return key;
     813             : }
     814             : 
     815             : 
     816          79 : static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
     817             : {
     818          79 :         struct eap_sim_data *data = priv;
     819          79 :         return data->state == SUCCESS;
     820             : }
     821             : 
     822             : 
     823          52 : static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
     824             : {
     825          52 :         struct eap_sim_data *data = priv;
     826             :         u8 *id;
     827             : 
     828          52 :         if (data->state != SUCCESS)
     829          27 :                 return NULL;
     830             : 
     831          25 :         *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
     832          25 :         id = os_malloc(*len);
     833          25 :         if (id == NULL)
     834           0 :                 return NULL;
     835             : 
     836          25 :         id[0] = EAP_TYPE_SIM;
     837          25 :         os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
     838          25 :         os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
     839             :                   EAP_SIM_NONCE_MT_LEN);
     840          25 :         wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
     841             : 
     842          25 :         return id;
     843             : }
     844             : 
     845             : 
     846          25 : int eap_server_sim_register(void)
     847             : {
     848             :         struct eap_method *eap;
     849             :         int ret;
     850             : 
     851          25 :         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
     852             :                                       EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
     853          25 :         if (eap == NULL)
     854           0 :                 return -1;
     855             : 
     856          25 :         eap->init = eap_sim_init;
     857          25 :         eap->reset = eap_sim_reset;
     858          25 :         eap->buildReq = eap_sim_buildReq;
     859          25 :         eap->check = eap_sim_check;
     860          25 :         eap->process = eap_sim_process;
     861          25 :         eap->isDone = eap_sim_isDone;
     862          25 :         eap->getKey = eap_sim_getKey;
     863          25 :         eap->isSuccess = eap_sim_isSuccess;
     864          25 :         eap->get_emsk = eap_sim_get_emsk;
     865          25 :         eap->getSessionId = eap_sim_get_session_id;
     866             : 
     867          25 :         ret = eap_server_method_register(eap);
     868          25 :         if (ret)
     869           0 :                 eap_server_method_free(eap);
     870          25 :         return ret;
     871             : }

Generated by: LCOV version 1.10