eap_sim.c
Go to the documentation of this file.
00001 /*
00002  * EAP peer method: EAP-SIM (RFC 4186)
00003  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "pcsc_funcs.h"
00019 #include "crypto/milenage.h"
00020 #include "eap_peer/eap_i.h"
00021 #include "eap_config.h"
00022 #include "eap_common/eap_sim_common.h"
00023 
00024 
00025 struct eap_sim_data {
00026         u8 *ver_list;
00027         size_t ver_list_len;
00028         int selected_version;
00029         size_t min_num_chal, num_chal;
00030 
00031         u8 kc[3][EAP_SIM_KC_LEN];
00032         u8 sres[3][EAP_SIM_SRES_LEN];
00033         u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
00034         u8 mk[EAP_SIM_MK_LEN];
00035         u8 k_aut[EAP_SIM_K_AUT_LEN];
00036         u8 k_encr[EAP_SIM_K_ENCR_LEN];
00037         u8 msk[EAP_SIM_KEYING_DATA_LEN];
00038         u8 emsk[EAP_EMSK_LEN];
00039         u8 rand[3][GSM_RAND_LEN];
00040 
00041         int num_id_req, num_notification;
00042         u8 *pseudonym;
00043         size_t pseudonym_len;
00044         u8 *reauth_id;
00045         size_t reauth_id_len;
00046         int reauth;
00047         unsigned int counter, counter_too_small;
00048         u8 *last_eap_identity;
00049         size_t last_eap_identity_len;
00050         enum {
00051                 CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE
00052         } state;
00053         int result_ind, use_result_ind;
00054 };
00055 
00056 
00057 #ifndef CONFIG_NO_STDOUT_DEBUG
00058 static const char * eap_sim_state_txt(int state)
00059 {
00060         switch (state) {
00061         case CONTINUE:
00062                 return "CONTINUE";
00063         case RESULT_SUCCESS:
00064                 return "RESULT_SUCCESS";
00065         case RESULT_FAILURE:
00066                 return "RESULT_FAILURE";
00067         case SUCCESS:
00068                 return "SUCCESS";
00069         case FAILURE:
00070                 return "FAILURE";
00071         default:
00072                 return "?";
00073         }
00074 }
00075 #endif /* CONFIG_NO_STDOUT_DEBUG */
00076 
00077 
00078 static void eap_sim_state(struct eap_sim_data *data, int state)
00079 {
00080         wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
00081                    eap_sim_state_txt(data->state),
00082                    eap_sim_state_txt(state));
00083         data->state = state;
00084 }
00085 
00086 
00087 static void * eap_sim_init(struct eap_sm *sm)
00088 {
00089         struct eap_sim_data *data;
00090         struct eap_peer_config *config = eap_get_config(sm);
00091 
00092         data = os_zalloc(sizeof(*data));
00093         if (data == NULL)
00094                 return NULL;
00095 
00096         if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
00097                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
00098                            "for NONCE_MT");
00099                 os_free(data);
00100                 return NULL;
00101         }
00102 
00103         data->min_num_chal = 2;
00104         if (config && config->phase1) {
00105                 char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
00106                 if (pos) {
00107                         data->min_num_chal = atoi(pos + 17);
00108                         if (data->min_num_chal < 2 || data->min_num_chal > 3) {
00109                                 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
00110                                            "sim_min_num_chal configuration "
00111                                            "(%lu, expected 2 or 3)",
00112                                            (unsigned long) data->min_num_chal);
00113                                 os_free(data);
00114                                 return NULL;
00115                         }
00116                         wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
00117                                    "challenges to %lu",
00118                                    (unsigned long) data->min_num_chal);
00119                 }
00120 
00121                 data->result_ind = os_strstr(config->phase1, "result_ind=1") !=
00122                         NULL;
00123         }
00124 
00125         eap_sim_state(data, CONTINUE);
00126 
00127         return data;
00128 }
00129 
00130 
00131 static void eap_sim_deinit(struct eap_sm *sm, void *priv)
00132 {
00133         struct eap_sim_data *data = priv;
00134         if (data) {
00135                 os_free(data->ver_list);
00136                 os_free(data->pseudonym);
00137                 os_free(data->reauth_id);
00138                 os_free(data->last_eap_identity);
00139                 os_free(data);
00140         }
00141 }
00142 
00143 
00144 static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
00145 {
00146         struct eap_peer_config *conf;
00147 
00148         wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm");
00149 
00150         conf = eap_get_config(sm);
00151         if (conf == NULL)
00152                 return -1;
00153         if (conf->pcsc) {
00154                 if (scard_gsm_auth(sm->scard_ctx, data->rand[0],
00155                                    data->sres[0], data->kc[0]) ||
00156                     scard_gsm_auth(sm->scard_ctx, data->rand[1],
00157                                    data->sres[1], data->kc[1]) ||
00158                     (data->num_chal > 2 &&
00159                      scard_gsm_auth(sm->scard_ctx, data->rand[2],
00160                                     data->sres[2], data->kc[2]))) {
00161                         wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM "
00162                                    "authentication could not be completed");
00163                         return -1;
00164                 }
00165                 return 0;
00166         }
00167 
00168 #ifdef CONFIG_SIM_SIMULATOR
00169         if (conf->password) {
00170                 u8 opc[16], k[16];
00171                 const char *pos;
00172                 size_t i;
00173                 wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage "
00174                            "implementation for authentication");
00175                 if (conf->password_len < 65) {
00176                         wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage "
00177                                    "password");
00178                         return -1;
00179                 }
00180                 pos = (const char *) conf->password;
00181                 if (hexstr2bin(pos, k, 16))
00182                         return -1;
00183                 pos += 32;
00184                 if (*pos != ':')
00185                         return -1;
00186                 pos++;
00187 
00188                 if (hexstr2bin(pos, opc, 16))
00189                         return -1;
00190 
00191                 for (i = 0; i < data->num_chal; i++) {
00192                         if (gsm_milenage(opc, k, data->rand[i],
00193                                          data->sres[i], data->kc[i])) {
00194                                 wpa_printf(MSG_DEBUG, "EAP-SIM: "
00195                                            "GSM-Milenage authentication "
00196                                            "could not be completed");
00197                                 return -1;
00198                         }
00199                         wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND",
00200                                     data->rand[i], GSM_RAND_LEN);
00201                         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES",
00202                                         data->sres[i], EAP_SIM_SRES_LEN);
00203                         wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc",
00204                                         data->kc[i], EAP_SIM_KC_LEN);
00205                 }
00206                 return 0;
00207         }
00208 #endif /* CONFIG_SIM_SIMULATOR */
00209 
00210 #ifdef CONFIG_SIM_HARDCODED
00211         /* These hardcoded Kc and SRES values are used for testing. RAND to
00212          * KC/SREC mapping is very bogus as far as real authentication is
00213          * concerned, but it is quite useful for cases where the AS is rotating
00214          * the order of pre-configured values. */
00215         {
00216                 size_t i;
00217 
00218                 wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES "
00219                            "values for testing");
00220 
00221                 for (i = 0; i < data->num_chal; i++) {
00222                         if (data->rand[i][0] == 0xaa) {
00223                                 os_memcpy(data->kc[i],
00224                                           "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
00225                                           EAP_SIM_KC_LEN);
00226                                 os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
00227                                           EAP_SIM_SRES_LEN);
00228                         } else if (data->rand[i][0] == 0xbb) {
00229                                 os_memcpy(data->kc[i],
00230                                           "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
00231                                           EAP_SIM_KC_LEN);
00232                                 os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
00233                                           EAP_SIM_SRES_LEN);
00234                         } else {
00235                                 os_memcpy(data->kc[i],
00236                                           "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
00237                                           EAP_SIM_KC_LEN);
00238                                 os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
00239                                           EAP_SIM_SRES_LEN);
00240                         }
00241                 }
00242         }
00243 
00244         return 0;
00245 
00246 #else /* CONFIG_SIM_HARDCODED */
00247 
00248         wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm "
00249                    "enabled");
00250         return -1;
00251 
00252 #endif /* CONFIG_SIM_HARDCODED */
00253 }
00254 
00255 
00256 static int eap_sim_supported_ver(int version)
00257 {
00258         return version == EAP_SIM_VERSION;
00259 }
00260 
00261 
00262 #define CLEAR_PSEUDONYM 0x01
00263 #define CLEAR_REAUTH_ID 0x02
00264 #define CLEAR_EAP_ID    0x04
00265 
00266 static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
00267 {
00268         wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
00269                    id & CLEAR_PSEUDONYM ? " pseudonym" : "",
00270                    id & CLEAR_REAUTH_ID ? " reauth_id" : "",
00271                    id & CLEAR_EAP_ID ? " eap_id" : "");
00272         if (id & CLEAR_PSEUDONYM) {
00273                 os_free(data->pseudonym);
00274                 data->pseudonym = NULL;
00275                 data->pseudonym_len = 0;
00276         }
00277         if (id & CLEAR_REAUTH_ID) {
00278                 os_free(data->reauth_id);
00279                 data->reauth_id = NULL;
00280                 data->reauth_id_len = 0;
00281         }
00282         if (id & CLEAR_EAP_ID) {
00283                 os_free(data->last_eap_identity);
00284                 data->last_eap_identity = NULL;
00285                 data->last_eap_identity_len = 0;
00286         }
00287 }
00288 
00289 
00290 static int eap_sim_learn_ids(struct eap_sim_data *data,
00291                              struct eap_sim_attrs *attr)
00292 {
00293         if (attr->next_pseudonym) {
00294                 os_free(data->pseudonym);
00295                 data->pseudonym = os_malloc(attr->next_pseudonym_len);
00296                 if (data->pseudonym == NULL) {
00297                         wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
00298                                    "next pseudonym");
00299                         return -1;
00300                 }
00301                 os_memcpy(data->pseudonym, attr->next_pseudonym,
00302                           attr->next_pseudonym_len);
00303                 data->pseudonym_len = attr->next_pseudonym_len;
00304                 wpa_hexdump_ascii(MSG_DEBUG,
00305                                   "EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
00306                                   data->pseudonym,
00307                                   data->pseudonym_len);
00308         }
00309 
00310         if (attr->next_reauth_id) {
00311                 os_free(data->reauth_id);
00312                 data->reauth_id = os_malloc(attr->next_reauth_id_len);
00313                 if (data->reauth_id == NULL) {
00314                         wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
00315                                    "next reauth_id");
00316                         return -1;
00317                 }
00318                 os_memcpy(data->reauth_id, attr->next_reauth_id,
00319                           attr->next_reauth_id_len);
00320                 data->reauth_id_len = attr->next_reauth_id_len;
00321                 wpa_hexdump_ascii(MSG_DEBUG,
00322                                   "EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
00323                                   data->reauth_id,
00324                                   data->reauth_id_len);
00325         }
00326 
00327         return 0;
00328 }
00329 
00330 
00331 static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id,
00332                                             int err)
00333 {
00334         struct eap_sim_msg *msg;
00335 
00336         eap_sim_state(data, FAILURE);
00337         data->num_id_req = 0;
00338         data->num_notification = 0;
00339 
00340         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
00341                                EAP_SIM_SUBTYPE_CLIENT_ERROR);
00342         eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
00343         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00344 }
00345 
00346 
00347 static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
00348                                               struct eap_sim_data *data, u8 id,
00349                                               enum eap_sim_id_req id_req)
00350 {
00351         const u8 *identity = NULL;
00352         size_t identity_len = 0;
00353         struct eap_sim_msg *msg;
00354 
00355         data->reauth = 0;
00356         if (id_req == ANY_ID && data->reauth_id) {
00357                 identity = data->reauth_id;
00358                 identity_len = data->reauth_id_len;
00359                 data->reauth = 1;
00360         } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) &&
00361                    data->pseudonym) {
00362                 identity = data->pseudonym;
00363                 identity_len = data->pseudonym_len;
00364                 eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
00365         } else if (id_req != NO_ID_REQ) {
00366                 identity = eap_get_config_identity(sm, &identity_len);
00367                 if (identity) {
00368                         eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
00369                                                  CLEAR_REAUTH_ID);
00370                 }
00371         }
00372         if (id_req != NO_ID_REQ)
00373                 eap_sim_clear_identities(data, CLEAR_EAP_ID);
00374 
00375         wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
00376         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
00377                                EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
00378         if (!data->reauth) {
00379                 wpa_hexdump(MSG_DEBUG, "   AT_NONCE_MT",
00380                             data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
00381                 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0,
00382                                 data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
00383                 wpa_printf(MSG_DEBUG, "   AT_SELECTED_VERSION %d",
00384                            data->selected_version);
00385                 eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION,
00386                                 data->selected_version, NULL, 0);
00387         }
00388 
00389         if (identity) {
00390                 wpa_hexdump_ascii(MSG_DEBUG, "   AT_IDENTITY",
00391                                   identity, identity_len);
00392                 eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
00393                                 identity, identity_len);
00394         }
00395 
00396         return eap_sim_msg_finish(msg, NULL, NULL, 0);
00397 }
00398 
00399 
00400 static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data,
00401                                                   u8 id)
00402 {
00403         struct eap_sim_msg *msg;
00404 
00405         wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id);
00406         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
00407                                EAP_SIM_SUBTYPE_CHALLENGE);
00408         if (data->use_result_ind) {
00409                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00410                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00411         }
00412         wpa_printf(MSG_DEBUG, "   AT_MAC");
00413         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00414         return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres,
00415                                   data->num_chal * EAP_SIM_SRES_LEN);
00416 }
00417 
00418 
00419 static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
00420                                                u8 id, int counter_too_small)
00421 {
00422         struct eap_sim_msg *msg;
00423         unsigned int counter;
00424 
00425         wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)",
00426                    id);
00427         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
00428                                EAP_SIM_SUBTYPE_REAUTHENTICATION);
00429         wpa_printf(MSG_DEBUG, "   AT_IV");
00430         wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00431         eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
00432 
00433         if (counter_too_small) {
00434                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER_TOO_SMALL");
00435                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0);
00436                 counter = data->counter_too_small;
00437         } else
00438                 counter = data->counter;
00439 
00440         wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", counter);
00441         eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
00442 
00443         if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
00444                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
00445                            "AT_ENCR_DATA");
00446                 eap_sim_msg_free(msg);
00447                 return NULL;
00448         }
00449         if (data->use_result_ind) {
00450                 wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
00451                 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
00452         }
00453         wpa_printf(MSG_DEBUG, "   AT_MAC");
00454         eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00455         return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
00456                                   EAP_SIM_NONCE_S_LEN);
00457 }
00458 
00459 
00460 static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
00461                                                      u8 id, u16 notification)
00462 {
00463         struct eap_sim_msg *msg;
00464         u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
00465 
00466         wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
00467         msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
00468                                EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
00469         if (k_aut && data->reauth) {
00470                 wpa_printf(MSG_DEBUG, "   AT_IV");
00471                 wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
00472                 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV,
00473                                            EAP_SIM_AT_ENCR_DATA);
00474                 wpa_printf(MSG_DEBUG, "   *AT_COUNTER %d", data->counter);
00475                 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter,
00476                                 NULL, 0);
00477                 if (eap_sim_msg_add_encr_end(msg, data->k_encr,
00478                                              EAP_SIM_AT_PADDING)) {
00479                         wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
00480                                    "AT_ENCR_DATA");
00481                         eap_sim_msg_free(msg);
00482                         return NULL;
00483                 }
00484         }
00485         if (k_aut) {
00486                 wpa_printf(MSG_DEBUG, "   AT_MAC");
00487                 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
00488         }
00489         return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0);
00490 }
00491 
00492 
00493 static struct wpabuf * eap_sim_process_start(struct eap_sm *sm,
00494                                              struct eap_sim_data *data, u8 id,
00495                                              struct eap_sim_attrs *attr)
00496 {
00497         int selected_version = -1, id_error;
00498         size_t i;
00499         u8 *pos;
00500 
00501         wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
00502         if (attr->version_list == NULL) {
00503                 wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
00504                            "SIM/Start");
00505                 return eap_sim_client_error(data, id,
00506                                             EAP_SIM_UNSUPPORTED_VERSION);
00507         }
00508 
00509         os_free(data->ver_list);
00510         data->ver_list = os_malloc(attr->version_list_len);
00511         if (data->ver_list == NULL) {
00512                 wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
00513                            "memory for version list");
00514                 return eap_sim_client_error(data, id,
00515                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00516         }
00517         os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
00518         data->ver_list_len = attr->version_list_len;
00519         pos = data->ver_list;
00520         for (i = 0; i < data->ver_list_len / 2; i++) {
00521                 int ver = pos[0] * 256 + pos[1];
00522                 pos += 2;
00523                 if (eap_sim_supported_ver(ver)) {
00524                         selected_version = ver;
00525                         break;
00526                 }
00527         }
00528         if (selected_version < 0) {
00529                 wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
00530                            "version");
00531                 return eap_sim_client_error(data, id,
00532                                             EAP_SIM_UNSUPPORTED_VERSION);
00533         }
00534         wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
00535                    selected_version);
00536         data->selected_version = selected_version;
00537 
00538         id_error = 0;
00539         switch (attr->id_req) {
00540         case NO_ID_REQ:
00541                 break;
00542         case ANY_ID:
00543                 if (data->num_id_req > 0)
00544                         id_error++;
00545                 data->num_id_req++;
00546                 break;
00547         case FULLAUTH_ID:
00548                 if (data->num_id_req > 1)
00549                         id_error++;
00550                 data->num_id_req++;
00551                 break;
00552         case PERMANENT_ID:
00553                 if (data->num_id_req > 2)
00554                         id_error++;
00555                 data->num_id_req++;
00556                 break;
00557         }
00558         if (id_error) {
00559                 wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
00560                            "used within one authentication");
00561                 return eap_sim_client_error(data, id,
00562                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00563         }
00564 
00565         return eap_sim_response_start(sm, data, id, attr->id_req);
00566 }
00567 
00568 
00569 static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm,
00570                                                  struct eap_sim_data *data,
00571                                                  u8 id,
00572                                                  const struct wpabuf *reqData,
00573                                                  struct eap_sim_attrs *attr)
00574 {
00575         const u8 *identity;
00576         size_t identity_len;
00577         struct eap_sim_attrs eattr;
00578 
00579         wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge");
00580         data->reauth = 0;
00581         if (!attr->mac || !attr->rand) {
00582                 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
00583                            "did not include%s%s",
00584                            !attr->mac ? " AT_MAC" : "",
00585                            !attr->rand ? " AT_RAND" : "");
00586                 return eap_sim_client_error(data, id,
00587                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00588         }
00589 
00590         wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges",
00591                    (unsigned long) attr->num_chal);
00592         if (attr->num_chal < data->min_num_chal) {
00593                 wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
00594                            "challenges (%lu)", (unsigned long) attr->num_chal);
00595                 return eap_sim_client_error(data, id,
00596                                             EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
00597         }
00598         if (attr->num_chal > 3) {
00599                 wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
00600                            "(%lu)", (unsigned long) attr->num_chal);
00601                 return eap_sim_client_error(data, id,
00602                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00603         }
00604 
00605         /* Verify that RANDs are different */
00606         if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
00607                    GSM_RAND_LEN) == 0 ||
00608             (attr->num_chal > 2 &&
00609              (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
00610                         GSM_RAND_LEN) == 0 ||
00611               os_memcmp(attr->rand + GSM_RAND_LEN,
00612                         attr->rand + 2 * GSM_RAND_LEN,
00613                         GSM_RAND_LEN) == 0))) {
00614                 wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
00615                 return eap_sim_client_error(data, id,
00616                                             EAP_SIM_RAND_NOT_FRESH);
00617         }
00618 
00619         os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
00620         data->num_chal = attr->num_chal;
00621                 
00622         if (eap_sim_gsm_auth(sm, data)) {
00623                 wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
00624                 return eap_sim_client_error(data, id,
00625                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00626         }
00627         if (data->last_eap_identity) {
00628                 identity = data->last_eap_identity;
00629                 identity_len = data->last_eap_identity_len;
00630         } else if (data->pseudonym) {
00631                 identity = data->pseudonym;
00632                 identity_len = data->pseudonym_len;
00633         } else
00634                 identity = eap_get_config_identity(sm, &identity_len);
00635         wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
00636                           "derivation", identity, identity_len);
00637         eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
00638                           data->selected_version, data->ver_list,
00639                           data->ver_list_len, data->num_chal,
00640                           (const u8 *) data->kc, data->mk);
00641         eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
00642                             data->emsk);
00643         if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt,
00644                                EAP_SIM_NONCE_MT_LEN)) {
00645                 wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
00646                            "used invalid AT_MAC");
00647                 return eap_sim_client_error(data, id,
00648                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00649         }
00650 
00651         /* Old reauthentication and pseudonym identities must not be used
00652          * anymore. In other words, if no new identities are received, full
00653          * authentication will be used on next reauthentication. */
00654         eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
00655                                  CLEAR_EAP_ID);
00656 
00657         if (attr->encr_data) {
00658                 u8 *decrypted;
00659                 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00660                                                attr->encr_data_len, attr->iv,
00661                                                &eattr, 0);
00662                 if (decrypted == NULL) {
00663                         return eap_sim_client_error(
00664                                 data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00665                 }
00666                 eap_sim_learn_ids(data, &eattr);
00667                 os_free(decrypted);
00668         }
00669 
00670         if (data->result_ind && attr->result_ind)
00671                 data->use_result_ind = 1;
00672 
00673         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
00674                 eap_sim_state(data, data->use_result_ind ?
00675                               RESULT_SUCCESS : SUCCESS);
00676         }
00677 
00678         data->num_id_req = 0;
00679         data->num_notification = 0;
00680         /* RFC 4186 specifies that counter is initialized to one after
00681          * fullauth, but initializing it to zero makes it easier to implement
00682          * reauth verification. */
00683         data->counter = 0;
00684         return eap_sim_response_challenge(data, id);
00685 }
00686 
00687 
00688 static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
00689                                                struct eap_sim_attrs *attr)
00690 {
00691         struct eap_sim_attrs eattr;
00692         u8 *decrypted;
00693 
00694         if (attr->encr_data == NULL || attr->iv == NULL) {
00695                 wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
00696                            "reauth did not include encrypted data");
00697                 return -1;
00698         }
00699 
00700         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00701                                        attr->encr_data_len, attr->iv, &eattr,
00702                                        0);
00703         if (decrypted == NULL) {
00704                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
00705                            "data from notification message");
00706                 return -1;
00707         }
00708 
00709         if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
00710                 wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
00711                            "message does not match with counter in reauth "
00712                            "message");
00713                 os_free(decrypted);
00714                 return -1;
00715         }
00716 
00717         os_free(decrypted);
00718         return 0;
00719 }
00720 
00721 
00722 static int eap_sim_process_notification_auth(struct eap_sim_data *data,
00723                                              const struct wpabuf *reqData,
00724                                              struct eap_sim_attrs *attr)
00725 {
00726         if (attr->mac == NULL) {
00727                 wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth "
00728                            "Notification message");
00729                 return -1;
00730         }
00731 
00732         if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
00733         {
00734                 wpa_printf(MSG_WARNING, "EAP-SIM: Notification message "
00735                            "used invalid AT_MAC");
00736                 return -1;
00737         }
00738 
00739         if (data->reauth &&
00740             eap_sim_process_notification_reauth(data, attr)) {
00741                 wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
00742                            "message after reauth");
00743                 return -1;
00744         }
00745 
00746         return 0;
00747 }
00748 
00749 
00750 static struct wpabuf * eap_sim_process_notification(
00751         struct eap_sm *sm, struct eap_sim_data *data, u8 id,
00752         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
00753 {
00754         wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification");
00755         if (data->num_notification > 0) {
00756                 wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
00757                            "rounds (only one allowed)");
00758                 return eap_sim_client_error(data, id,
00759                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00760         }
00761         data->num_notification++;
00762         if (attr->notification == -1) {
00763                 wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
00764                            "Notification message");
00765                 return eap_sim_client_error(data, id,
00766                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00767         }
00768 
00769         if ((attr->notification & 0x4000) == 0 &&
00770             eap_sim_process_notification_auth(data, reqData, attr)) {
00771                 return eap_sim_client_error(data, id,
00772                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00773         }
00774 
00775         eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
00776         if (attr->notification >= 0 && attr->notification < 32768) {
00777                 eap_sim_state(data, FAILURE);
00778         } else if (attr->notification == EAP_SIM_SUCCESS &&
00779                    data->state == RESULT_SUCCESS)
00780                 eap_sim_state(data, SUCCESS);
00781         return eap_sim_response_notification(data, id, attr->notification);
00782 }
00783 
00784 
00785 static struct wpabuf * eap_sim_process_reauthentication(
00786         struct eap_sm *sm, struct eap_sim_data *data, u8 id,
00787         const struct wpabuf *reqData, struct eap_sim_attrs *attr)
00788 {
00789         struct eap_sim_attrs eattr;
00790         u8 *decrypted;
00791 
00792         wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
00793 
00794         if (data->reauth_id == NULL) {
00795                 wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
00796                            "reauthentication, but no reauth_id available");
00797                 return eap_sim_client_error(data, id,
00798                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00799         }
00800 
00801         data->reauth = 1;
00802         if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
00803         {
00804                 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
00805                            "did not have valid AT_MAC");
00806                 return eap_sim_client_error(data, id,
00807                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00808         }
00809 
00810         if (attr->encr_data == NULL || attr->iv == NULL) {
00811                 wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
00812                            "message did not include encrypted data");
00813                 return eap_sim_client_error(data, id,
00814                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00815         }
00816 
00817         decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
00818                                        attr->encr_data_len, attr->iv, &eattr,
00819                                        0);
00820         if (decrypted == NULL) {
00821                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
00822                            "data from reauthentication message");
00823                 return eap_sim_client_error(data, id,
00824                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00825         }
00826 
00827         if (eattr.nonce_s == NULL || eattr.counter < 0) {
00828                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
00829                            !eattr.nonce_s ? " AT_NONCE_S" : "",
00830                            eattr.counter < 0 ? " AT_COUNTER" : "");
00831                 os_free(decrypted);
00832                 return eap_sim_client_error(data, id,
00833                                             EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00834         }
00835 
00836         if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
00837                 wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
00838                            "(%d <= %d)", eattr.counter, data->counter);
00839                 data->counter_too_small = eattr.counter;
00840                 /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
00841                  * reauth_id must not be used to start a new reauthentication.
00842                  * However, since it was used in the last EAP-Response-Identity
00843                  * packet, it has to saved for the following fullauth to be
00844                  * used in MK derivation. */
00845                 os_free(data->last_eap_identity);
00846                 data->last_eap_identity = data->reauth_id;
00847                 data->last_eap_identity_len = data->reauth_id_len;
00848                 data->reauth_id = NULL;
00849                 data->reauth_id_len = 0;
00850                 os_free(decrypted);
00851                 return eap_sim_response_reauth(data, id, 1);
00852         }
00853         data->counter = eattr.counter;
00854 
00855         os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
00856         wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
00857                     data->nonce_s, EAP_SIM_NONCE_S_LEN);
00858 
00859         eap_sim_derive_keys_reauth(data->counter,
00860                                    data->reauth_id, data->reauth_id_len,
00861                                    data->nonce_s, data->mk, data->msk,
00862                                    data->emsk);
00863         eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
00864         eap_sim_learn_ids(data, &eattr);
00865 
00866         if (data->result_ind && attr->result_ind)
00867                 data->use_result_ind = 1;
00868 
00869         if (data->state != FAILURE && data->state != RESULT_FAILURE) {
00870                 eap_sim_state(data, data->use_result_ind ?
00871                               RESULT_SUCCESS : SUCCESS);
00872         }
00873 
00874         data->num_id_req = 0;
00875         data->num_notification = 0;
00876         if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
00877                 wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
00878                            "fast reauths performed - force fullauth");
00879                 eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
00880         }
00881         os_free(decrypted);
00882         return eap_sim_response_reauth(data, id, 0);
00883 }
00884 
00885 
00886 static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv,
00887                                        struct eap_method_ret *ret,
00888                                        const struct wpabuf *reqData)
00889 {
00890         struct eap_sim_data *data = priv;
00891         const struct eap_hdr *req;
00892         u8 subtype, id;
00893         struct wpabuf *res;
00894         const u8 *pos;
00895         struct eap_sim_attrs attr;
00896         size_t len;
00897 
00898         wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData);
00899         if (eap_get_config_identity(sm, &len) == NULL) {
00900                 wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
00901                 eap_sm_request_identity(sm);
00902                 ret->ignore = TRUE;
00903                 return NULL;
00904         }
00905 
00906         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len);
00907         if (pos == NULL || len < 1) {
00908                 ret->ignore = TRUE;
00909                 return NULL;
00910         }
00911         req = wpabuf_head(reqData);
00912         id = req->identifier;
00913         len = be_to_host16(req->length);
00914 
00915         ret->ignore = FALSE;
00916         ret->methodState = METHOD_MAY_CONT;
00917         ret->decision = DECISION_FAIL;
00918         ret->allowNotifications = TRUE;
00919 
00920         subtype = *pos++;
00921         wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
00922         pos += 2; /* Reserved */
00923 
00924         if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0,
00925                                0)) {
00926                 res = eap_sim_client_error(data, id,
00927                                            EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00928                 goto done;
00929         }
00930 
00931         switch (subtype) {
00932         case EAP_SIM_SUBTYPE_START:
00933                 res = eap_sim_process_start(sm, data, id, &attr);
00934                 break;
00935         case EAP_SIM_SUBTYPE_CHALLENGE:
00936                 res = eap_sim_process_challenge(sm, data, id, reqData, &attr);
00937                 break;
00938         case EAP_SIM_SUBTYPE_NOTIFICATION:
00939                 res = eap_sim_process_notification(sm, data, id, reqData,
00940                                                    &attr);
00941                 break;
00942         case EAP_SIM_SUBTYPE_REAUTHENTICATION:
00943                 res = eap_sim_process_reauthentication(sm, data, id, reqData,
00944                                                        &attr);
00945                 break;
00946         case EAP_SIM_SUBTYPE_CLIENT_ERROR:
00947                 wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
00948                 res = eap_sim_client_error(data, id,
00949                                            EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00950                 break;
00951         default:
00952                 wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
00953                 res = eap_sim_client_error(data, id,
00954                                            EAP_SIM_UNABLE_TO_PROCESS_PACKET);
00955                 break;
00956         }
00957 
00958 done:
00959         if (data->state == FAILURE) {
00960                 ret->decision = DECISION_FAIL;
00961                 ret->methodState = METHOD_DONE;
00962         } else if (data->state == SUCCESS) {
00963                 ret->decision = data->use_result_ind ?
00964                         DECISION_UNCOND_SUCC : DECISION_COND_SUCC;
00965                 ret->methodState = data->use_result_ind ?
00966                         METHOD_DONE : METHOD_MAY_CONT;
00967         } else if (data->state == RESULT_FAILURE)
00968                 ret->methodState = METHOD_CONT;
00969         else if (data->state == RESULT_SUCCESS)
00970                 ret->methodState = METHOD_CONT;
00971 
00972         if (ret->methodState == METHOD_DONE) {
00973                 ret->allowNotifications = FALSE;
00974         }
00975 
00976         return res;
00977 }
00978 
00979 
00980 static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv)
00981 {
00982         struct eap_sim_data *data = priv;
00983         return data->pseudonym || data->reauth_id;
00984 }
00985 
00986 
00987 static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
00988 {
00989         struct eap_sim_data *data = priv;
00990         eap_sim_clear_identities(data, CLEAR_EAP_ID);
00991         data->use_result_ind = 0;
00992 }
00993 
00994 
00995 static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
00996 {
00997         struct eap_sim_data *data = priv;
00998         if (os_get_random(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
00999                 wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
01000                            "for NONCE_MT");
01001                 os_free(data);
01002                 return NULL;
01003         }
01004         data->num_id_req = 0;
01005         data->num_notification = 0;
01006         eap_sim_state(data, CONTINUE);
01007         return priv;
01008 }
01009 
01010 
01011 static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv,
01012                                        size_t *len)
01013 {
01014         struct eap_sim_data *data = priv;
01015 
01016         if (data->reauth_id) {
01017                 *len = data->reauth_id_len;
01018                 return data->reauth_id;
01019         }
01020 
01021         if (data->pseudonym) {
01022                 *len = data->pseudonym_len;
01023                 return data->pseudonym;
01024         }
01025 
01026         return NULL;
01027 }
01028 
01029 
01030 static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv)
01031 {
01032         struct eap_sim_data *data = priv;
01033         return data->state == SUCCESS;
01034 }
01035 
01036 
01037 static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
01038 {
01039         struct eap_sim_data *data = priv;
01040         u8 *key;
01041 
01042         if (data->state != SUCCESS)
01043                 return NULL;
01044 
01045         key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
01046         if (key == NULL)
01047                 return NULL;
01048 
01049         *len = EAP_SIM_KEYING_DATA_LEN;
01050         os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
01051 
01052         return key;
01053 }
01054 
01055 
01056 static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
01057 {
01058         struct eap_sim_data *data = priv;
01059         u8 *key;
01060 
01061         if (data->state != SUCCESS)
01062                 return NULL;
01063 
01064         key = os_malloc(EAP_EMSK_LEN);
01065         if (key == NULL)
01066                 return NULL;
01067 
01068         *len = EAP_EMSK_LEN;
01069         os_memcpy(key, data->emsk, EAP_EMSK_LEN);
01070 
01071         return key;
01072 }
01073 
01074 
01075 int eap_peer_sim_register(void)
01076 {
01077         struct eap_method *eap;
01078         int ret;
01079 
01080         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
01081                                     EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
01082         if (eap == NULL)
01083                 return -1;
01084 
01085         eap->init = eap_sim_init;
01086         eap->deinit = eap_sim_deinit;
01087         eap->process = eap_sim_process;
01088         eap->isKeyAvailable = eap_sim_isKeyAvailable;
01089         eap->getKey = eap_sim_getKey;
01090         eap->has_reauth_data = eap_sim_has_reauth_data;
01091         eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
01092         eap->init_for_reauth = eap_sim_init_for_reauth;
01093         eap->get_identity = eap_sim_get_identity;
01094         eap->get_emsk = eap_sim_get_emsk;
01095 
01096         ret = eap_peer_method_register(eap);
01097         if (ret)
01098                 eap_peer_method_free(eap);
01099         return ret;
01100 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35