$search
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 }