$search
00001 /* 00002 * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) 00003 * Copyright (c) 2005-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 "crypto/sha256.h" 00019 #include "crypto/crypto.h" 00020 #include "eap_common/eap_sim_common.h" 00021 #include "eap_server/eap_i.h" 00022 #include "eap_server/eap_sim_db.h" 00023 00024 00025 struct eap_aka_data { 00026 u8 mk[EAP_SIM_MK_LEN]; 00027 u8 nonce_s[EAP_SIM_NONCE_S_LEN]; 00028 u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; 00029 u8 k_encr[EAP_SIM_K_ENCR_LEN]; 00030 u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ 00031 u8 msk[EAP_SIM_KEYING_DATA_LEN]; 00032 u8 emsk[EAP_EMSK_LEN]; 00033 u8 rand[EAP_AKA_RAND_LEN]; 00034 u8 autn[EAP_AKA_AUTN_LEN]; 00035 u8 ck[EAP_AKA_CK_LEN]; 00036 u8 ik[EAP_AKA_IK_LEN]; 00037 u8 res[EAP_AKA_RES_MAX_LEN]; 00038 size_t res_len; 00039 enum { 00040 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE 00041 } state; 00042 char *next_pseudonym; 00043 char *next_reauth_id; 00044 u16 counter; 00045 struct eap_sim_reauth *reauth; 00046 int auts_reported; /* whether the current AUTS has been reported to the 00047 * eap_sim_db */ 00048 u16 notification; 00049 int use_result_ind; 00050 00051 struct wpabuf *id_msgs; 00052 int pending_id; 00053 u8 eap_method; 00054 u8 *network_name; 00055 size_t network_name_len; 00056 u16 kdf; 00057 }; 00058 00059 00060 static void eap_aka_determine_identity(struct eap_sm *sm, 00061 struct eap_aka_data *data, 00062 int before_identity, int after_reauth); 00063 00064 00065 static const char * eap_aka_state_txt(int state) 00066 { 00067 switch (state) { 00068 case IDENTITY: 00069 return "IDENTITY"; 00070 case CHALLENGE: 00071 return "CHALLENGE"; 00072 case REAUTH: 00073 return "REAUTH"; 00074 case SUCCESS: 00075 return "SUCCESS"; 00076 case FAILURE: 00077 return "FAILURE"; 00078 case NOTIFICATION: 00079 return "NOTIFICATION"; 00080 default: 00081 return "Unknown?!"; 00082 } 00083 } 00084 00085 00086 static void eap_aka_state(struct eap_aka_data *data, int state) 00087 { 00088 wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", 00089 eap_aka_state_txt(data->state), 00090 eap_aka_state_txt(state)); 00091 data->state = state; 00092 } 00093 00094 00095 static void * eap_aka_init(struct eap_sm *sm) 00096 { 00097 struct eap_aka_data *data; 00098 00099 if (sm->eap_sim_db_priv == NULL) { 00100 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 00101 return NULL; 00102 } 00103 00104 data = os_zalloc(sizeof(*data)); 00105 if (data == NULL) 00106 return NULL; 00107 00108 data->eap_method = EAP_TYPE_AKA; 00109 00110 data->state = IDENTITY; 00111 eap_aka_determine_identity(sm, data, 1, 0); 00112 data->pending_id = -1; 00113 00114 return data; 00115 } 00116 00117 00118 #ifdef EAP_SERVER_AKA_PRIME 00119 static void * eap_aka_prime_init(struct eap_sm *sm) 00120 { 00121 struct eap_aka_data *data; 00122 /* TODO: make ANID configurable; see 3GPP TS 24.302 */ 00123 char *network_name = "WLAN"; 00124 00125 if (sm->eap_sim_db_priv == NULL) { 00126 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 00127 return NULL; 00128 } 00129 00130 data = os_zalloc(sizeof(*data)); 00131 if (data == NULL) 00132 return NULL; 00133 00134 data->eap_method = EAP_TYPE_AKA_PRIME; 00135 data->network_name = os_malloc(os_strlen(network_name)); 00136 if (data->network_name == NULL) { 00137 os_free(data); 00138 return NULL; 00139 } 00140 00141 data->network_name_len = os_strlen(network_name); 00142 os_memcpy(data->network_name, network_name, data->network_name_len); 00143 00144 data->state = IDENTITY; 00145 eap_aka_determine_identity(sm, data, 1, 0); 00146 data->pending_id = -1; 00147 00148 return data; 00149 } 00150 #endif /* EAP_SERVER_AKA_PRIME */ 00151 00152 00153 static void eap_aka_reset(struct eap_sm *sm, void *priv) 00154 { 00155 struct eap_aka_data *data = priv; 00156 os_free(data->next_pseudonym); 00157 os_free(data->next_reauth_id); 00158 wpabuf_free(data->id_msgs); 00159 os_free(data->network_name); 00160 os_free(data); 00161 } 00162 00163 00164 static int eap_aka_add_id_msg(struct eap_aka_data *data, 00165 const struct wpabuf *msg) 00166 { 00167 if (msg == NULL) 00168 return -1; 00169 00170 if (data->id_msgs == NULL) { 00171 data->id_msgs = wpabuf_dup(msg); 00172 return data->id_msgs == NULL ? -1 : 0; 00173 } 00174 00175 if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) 00176 return -1; 00177 wpabuf_put_buf(data->id_msgs, msg); 00178 00179 return 0; 00180 } 00181 00182 00183 static void eap_aka_add_checkcode(struct eap_aka_data *data, 00184 struct eap_sim_msg *msg) 00185 { 00186 const u8 *addr; 00187 size_t len; 00188 u8 hash[SHA256_MAC_LEN]; 00189 00190 wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); 00191 00192 if (data->id_msgs == NULL) { 00193 /* 00194 * No EAP-AKA/Identity packets were exchanged - send empty 00195 * checkcode. 00196 */ 00197 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); 00198 return; 00199 } 00200 00201 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 00202 addr = wpabuf_head(data->id_msgs); 00203 len = wpabuf_len(data->id_msgs); 00204 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); 00205 if (data->eap_method == EAP_TYPE_AKA_PRIME) 00206 sha256_vector(1, &addr, &len, hash); 00207 else 00208 sha1_vector(1, &addr, &len, hash); 00209 00210 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, 00211 data->eap_method == EAP_TYPE_AKA_PRIME ? 00212 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); 00213 } 00214 00215 00216 static int eap_aka_verify_checkcode(struct eap_aka_data *data, 00217 const u8 *checkcode, size_t checkcode_len) 00218 { 00219 const u8 *addr; 00220 size_t len; 00221 u8 hash[SHA256_MAC_LEN]; 00222 size_t hash_len; 00223 00224 if (checkcode == NULL) 00225 return -1; 00226 00227 if (data->id_msgs == NULL) { 00228 if (checkcode_len != 0) { 00229 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " 00230 "indicates that AKA/Identity messages were " 00231 "used, but they were not"); 00232 return -1; 00233 } 00234 return 0; 00235 } 00236 00237 hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? 00238 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; 00239 00240 if (checkcode_len != hash_len) { 00241 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates " 00242 "that AKA/Identity message were not used, but they " 00243 "were"); 00244 return -1; 00245 } 00246 00247 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 00248 addr = wpabuf_head(data->id_msgs); 00249 len = wpabuf_len(data->id_msgs); 00250 if (data->eap_method == EAP_TYPE_AKA_PRIME) 00251 sha256_vector(1, &addr, &len, hash); 00252 else 00253 sha1_vector(1, &addr, &len, hash); 00254 00255 if (os_memcmp(hash, checkcode, hash_len) != 0) { 00256 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); 00257 return -1; 00258 } 00259 00260 return 0; 00261 } 00262 00263 00264 static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, 00265 struct eap_aka_data *data, u8 id) 00266 { 00267 struct eap_sim_msg *msg; 00268 struct wpabuf *buf; 00269 00270 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); 00271 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 00272 EAP_AKA_SUBTYPE_IDENTITY); 00273 if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 00274 sm->identity_len)) { 00275 wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); 00276 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); 00277 } else { 00278 /* 00279 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is 00280 * ignored and the AKA/Identity is used to request the 00281 * identity. 00282 */ 00283 wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); 00284 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); 00285 } 00286 buf = eap_sim_msg_finish(msg, NULL, NULL, 0); 00287 if (eap_aka_add_id_msg(data, buf) < 0) { 00288 wpabuf_free(buf); 00289 return NULL; 00290 } 00291 data->pending_id = id; 00292 return buf; 00293 } 00294 00295 00296 static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, 00297 struct eap_sim_msg *msg, u16 counter, 00298 const u8 *nonce_s) 00299 { 00300 os_free(data->next_pseudonym); 00301 data->next_pseudonym = 00302 eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1); 00303 os_free(data->next_reauth_id); 00304 if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { 00305 data->next_reauth_id = 00306 eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); 00307 } else { 00308 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " 00309 "count exceeded - force full authentication"); 00310 data->next_reauth_id = NULL; 00311 } 00312 00313 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 00314 counter == 0 && nonce_s == NULL) 00315 return 0; 00316 00317 wpa_printf(MSG_DEBUG, " AT_IV"); 00318 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 00319 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 00320 00321 if (counter > 0) { 00322 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 00323 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 00324 } 00325 00326 if (nonce_s) { 00327 wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 00328 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 00329 EAP_SIM_NONCE_S_LEN); 00330 } 00331 00332 if (data->next_pseudonym) { 00333 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 00334 data->next_pseudonym); 00335 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 00336 os_strlen(data->next_pseudonym), 00337 (u8 *) data->next_pseudonym, 00338 os_strlen(data->next_pseudonym)); 00339 } 00340 00341 if (data->next_reauth_id) { 00342 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 00343 data->next_reauth_id); 00344 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 00345 os_strlen(data->next_reauth_id), 00346 (u8 *) data->next_reauth_id, 00347 os_strlen(data->next_reauth_id)); 00348 } 00349 00350 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 00351 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " 00352 "AT_ENCR_DATA"); 00353 return -1; 00354 } 00355 00356 return 0; 00357 } 00358 00359 00360 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, 00361 struct eap_aka_data *data, 00362 u8 id) 00363 { 00364 struct eap_sim_msg *msg; 00365 00366 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); 00367 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 00368 EAP_AKA_SUBTYPE_CHALLENGE); 00369 wpa_printf(MSG_DEBUG, " AT_RAND"); 00370 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); 00371 wpa_printf(MSG_DEBUG, " AT_AUTN"); 00372 eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); 00373 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00374 if (data->kdf) { 00375 /* Add the selected KDF into the beginning */ 00376 wpa_printf(MSG_DEBUG, " AT_KDF"); 00377 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, 00378 NULL, 0); 00379 } 00380 wpa_printf(MSG_DEBUG, " AT_KDF"); 00381 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, 00382 NULL, 0); 00383 wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); 00384 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, 00385 data->network_name_len, 00386 data->network_name, data->network_name_len); 00387 } 00388 00389 if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { 00390 eap_sim_msg_free(msg); 00391 return NULL; 00392 } 00393 00394 eap_aka_add_checkcode(data, msg); 00395 00396 if (sm->eap_sim_aka_result_ind) { 00397 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 00398 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 00399 } 00400 00401 #ifdef EAP_SERVER_AKA_PRIME 00402 if (data->eap_method == EAP_TYPE_AKA) { 00403 u16 flags = 0; 00404 int i; 00405 int aka_prime_preferred = 0; 00406 00407 i = 0; 00408 while (sm->user && i < EAP_MAX_METHODS && 00409 (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 00410 sm->user->methods[i].method != EAP_TYPE_NONE)) { 00411 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { 00412 if (sm->user->methods[i].method == 00413 EAP_TYPE_AKA) 00414 break; 00415 if (sm->user->methods[i].method == 00416 EAP_TYPE_AKA_PRIME) { 00417 aka_prime_preferred = 1; 00418 break; 00419 } 00420 } 00421 i++; 00422 } 00423 00424 if (aka_prime_preferred) 00425 flags |= EAP_AKA_BIDDING_FLAG_D; 00426 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); 00427 } 00428 #endif /* EAP_SERVER_AKA_PRIME */ 00429 00430 wpa_printf(MSG_DEBUG, " AT_MAC"); 00431 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 00432 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 00433 } 00434 00435 00436 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, 00437 struct eap_aka_data *data, u8 id) 00438 { 00439 struct eap_sim_msg *msg; 00440 00441 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); 00442 00443 if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 00444 return NULL; 00445 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", 00446 data->nonce_s, EAP_SIM_NONCE_S_LEN); 00447 00448 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00449 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, 00450 sm->identity, 00451 sm->identity_len, 00452 data->nonce_s, 00453 data->msk, data->emsk); 00454 } else { 00455 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 00456 data->msk, data->emsk); 00457 eap_sim_derive_keys_reauth(data->counter, sm->identity, 00458 sm->identity_len, data->nonce_s, 00459 data->mk, data->msk, data->emsk); 00460 } 00461 00462 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 00463 EAP_AKA_SUBTYPE_REAUTHENTICATION); 00464 00465 if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 00466 eap_sim_msg_free(msg); 00467 return NULL; 00468 } 00469 00470 eap_aka_add_checkcode(data, msg); 00471 00472 if (sm->eap_sim_aka_result_ind) { 00473 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 00474 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 00475 } 00476 00477 wpa_printf(MSG_DEBUG, " AT_MAC"); 00478 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 00479 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 00480 } 00481 00482 00483 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, 00484 struct eap_aka_data *data, 00485 u8 id) 00486 { 00487 struct eap_sim_msg *msg; 00488 00489 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); 00490 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 00491 EAP_AKA_SUBTYPE_NOTIFICATION); 00492 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 00493 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 00494 NULL, 0); 00495 if (data->use_result_ind) { 00496 if (data->reauth) { 00497 wpa_printf(MSG_DEBUG, " AT_IV"); 00498 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 00499 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 00500 EAP_SIM_AT_ENCR_DATA); 00501 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 00502 data->counter); 00503 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 00504 NULL, 0); 00505 00506 if (eap_sim_msg_add_encr_end(msg, data->k_encr, 00507 EAP_SIM_AT_PADDING)) { 00508 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " 00509 "encrypt AT_ENCR_DATA"); 00510 eap_sim_msg_free(msg); 00511 return NULL; 00512 } 00513 } 00514 00515 wpa_printf(MSG_DEBUG, " AT_MAC"); 00516 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 00517 } 00518 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 00519 } 00520 00521 00522 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) 00523 { 00524 struct eap_aka_data *data = priv; 00525 00526 data->auts_reported = 0; 00527 switch (data->state) { 00528 case IDENTITY: 00529 return eap_aka_build_identity(sm, data, id); 00530 case CHALLENGE: 00531 return eap_aka_build_challenge(sm, data, id); 00532 case REAUTH: 00533 return eap_aka_build_reauth(sm, data, id); 00534 case NOTIFICATION: 00535 return eap_aka_build_notification(sm, data, id); 00536 default: 00537 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 00538 "buildReq", data->state); 00539 break; 00540 } 00541 return NULL; 00542 } 00543 00544 00545 static Boolean eap_aka_check(struct eap_sm *sm, void *priv, 00546 struct wpabuf *respData) 00547 { 00548 struct eap_aka_data *data = priv; 00549 const u8 *pos; 00550 size_t len; 00551 00552 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 00553 &len); 00554 if (pos == NULL || len < 3) { 00555 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); 00556 return TRUE; 00557 } 00558 00559 return FALSE; 00560 } 00561 00562 00563 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) 00564 { 00565 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || 00566 subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) 00567 return FALSE; 00568 00569 switch (data->state) { 00570 case IDENTITY: 00571 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { 00572 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 00573 "subtype %d", subtype); 00574 return TRUE; 00575 } 00576 break; 00577 case CHALLENGE: 00578 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && 00579 subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 00580 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 00581 "subtype %d", subtype); 00582 return TRUE; 00583 } 00584 break; 00585 case REAUTH: 00586 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { 00587 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 00588 "subtype %d", subtype); 00589 return TRUE; 00590 } 00591 break; 00592 case NOTIFICATION: 00593 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { 00594 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 00595 "subtype %d", subtype); 00596 return TRUE; 00597 } 00598 break; 00599 default: 00600 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " 00601 "processing a response", data->state); 00602 return TRUE; 00603 } 00604 00605 return FALSE; 00606 } 00607 00608 00609 static void eap_aka_determine_identity(struct eap_sm *sm, 00610 struct eap_aka_data *data, 00611 int before_identity, int after_reauth) 00612 { 00613 const u8 *identity; 00614 size_t identity_len; 00615 int res; 00616 00617 identity = NULL; 00618 identity_len = 0; 00619 00620 if (after_reauth && data->reauth) { 00621 identity = data->reauth->identity; 00622 identity_len = data->reauth->identity_len; 00623 } else if (sm->identity && sm->identity_len > 0 && 00624 sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { 00625 identity = sm->identity; 00626 identity_len = sm->identity_len; 00627 } else { 00628 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, 00629 sm->identity, 00630 sm->identity_len, 00631 &identity_len); 00632 if (identity == NULL) { 00633 data->reauth = eap_sim_db_get_reauth_entry( 00634 sm->eap_sim_db_priv, sm->identity, 00635 sm->identity_len); 00636 if (data->reauth && 00637 data->reauth->aka_prime != 00638 (data->eap_method == EAP_TYPE_AKA_PRIME)) { 00639 wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " 00640 "was for different AKA version"); 00641 data->reauth = NULL; 00642 } 00643 if (data->reauth) { 00644 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " 00645 "re-authentication"); 00646 identity = data->reauth->identity; 00647 identity_len = data->reauth->identity_len; 00648 data->counter = data->reauth->counter; 00649 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00650 os_memcpy(data->k_encr, 00651 data->reauth->k_encr, 00652 EAP_SIM_K_ENCR_LEN); 00653 os_memcpy(data->k_aut, 00654 data->reauth->k_aut, 00655 EAP_AKA_PRIME_K_AUT_LEN); 00656 os_memcpy(data->k_re, 00657 data->reauth->k_re, 00658 EAP_AKA_PRIME_K_RE_LEN); 00659 } else { 00660 os_memcpy(data->mk, data->reauth->mk, 00661 EAP_SIM_MK_LEN); 00662 } 00663 } 00664 } 00665 } 00666 00667 if (identity == NULL || 00668 eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 00669 sm->identity_len) < 0) { 00670 if (before_identity) { 00671 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " 00672 "not known - send AKA-Identity request"); 00673 eap_aka_state(data, IDENTITY); 00674 return; 00675 } else { 00676 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " 00677 "permanent user name is known; try to use " 00678 "it"); 00679 /* eap_sim_db_get_aka_auth() will report failure, if 00680 * this identity is not known. */ 00681 } 00682 } 00683 00684 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", 00685 identity, identity_len); 00686 00687 if (!after_reauth && data->reauth) { 00688 eap_aka_state(data, REAUTH); 00689 return; 00690 } 00691 00692 res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, 00693 identity_len, data->rand, data->autn, 00694 data->ik, data->ck, data->res, 00695 &data->res_len, sm); 00696 if (res == EAP_SIM_DB_PENDING) { 00697 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 00698 "not yet available - pending request"); 00699 sm->method_pending = METHOD_PENDING_WAIT; 00700 return; 00701 } 00702 00703 #ifdef EAP_SERVER_AKA_PRIME 00704 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00705 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the 00706 * needed 6-octet SQN ^AK for CK',IK' derivation */ 00707 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, 00708 data->autn, 00709 data->network_name, 00710 data->network_name_len); 00711 } 00712 #endif /* EAP_SERVER_AKA_PRIME */ 00713 00714 data->reauth = NULL; 00715 data->counter = 0; /* reset re-auth counter since this is full auth */ 00716 00717 if (res != 0) { 00718 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " 00719 "authentication data for the peer"); 00720 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00721 eap_aka_state(data, NOTIFICATION); 00722 return; 00723 } 00724 if (sm->method_pending == METHOD_PENDING_WAIT) { 00725 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 00726 "available - abort pending wait"); 00727 sm->method_pending = METHOD_PENDING_NONE; 00728 } 00729 00730 identity_len = sm->identity_len; 00731 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 00732 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " 00733 "character from identity"); 00734 identity_len--; 00735 } 00736 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", 00737 sm->identity, identity_len); 00738 00739 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00740 eap_aka_prime_derive_keys(identity, identity_len, data->ik, 00741 data->ck, data->k_encr, data->k_aut, 00742 data->k_re, data->msk, data->emsk); 00743 } else { 00744 eap_aka_derive_mk(sm->identity, identity_len, data->ik, 00745 data->ck, data->mk); 00746 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 00747 data->msk, data->emsk); 00748 } 00749 00750 eap_aka_state(data, CHALLENGE); 00751 } 00752 00753 00754 static void eap_aka_process_identity(struct eap_sm *sm, 00755 struct eap_aka_data *data, 00756 struct wpabuf *respData, 00757 struct eap_sim_attrs *attr) 00758 { 00759 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); 00760 00761 if (attr->mac || attr->iv || attr->encr_data) { 00762 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " 00763 "received in EAP-Response/AKA-Identity"); 00764 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00765 eap_aka_state(data, NOTIFICATION); 00766 return; 00767 } 00768 00769 if (attr->identity) { 00770 os_free(sm->identity); 00771 sm->identity = os_malloc(attr->identity_len); 00772 if (sm->identity) { 00773 os_memcpy(sm->identity, attr->identity, 00774 attr->identity_len); 00775 sm->identity_len = attr->identity_len; 00776 } 00777 } 00778 00779 eap_aka_determine_identity(sm, data, 0, 0); 00780 if (eap_get_id(respData) == data->pending_id) { 00781 data->pending_id = -1; 00782 eap_aka_add_id_msg(data, respData); 00783 } 00784 } 00785 00786 00787 static int eap_aka_verify_mac(struct eap_aka_data *data, 00788 const struct wpabuf *req, 00789 const u8 *mac, const u8 *extra, 00790 size_t extra_len) 00791 { 00792 if (data->eap_method == EAP_TYPE_AKA_PRIME) 00793 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, 00794 extra_len); 00795 return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); 00796 } 00797 00798 00799 static void eap_aka_process_challenge(struct eap_sm *sm, 00800 struct eap_aka_data *data, 00801 struct wpabuf *respData, 00802 struct eap_sim_attrs *attr) 00803 { 00804 const u8 *identity; 00805 size_t identity_len; 00806 00807 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); 00808 00809 #ifdef EAP_SERVER_AKA_PRIME 00810 #if 0 00811 /* KDF negotiation; to be enabled only after more than one KDF is 00812 * supported */ 00813 if (data->eap_method == EAP_TYPE_AKA_PRIME && 00814 attr->kdf_count == 1 && attr->mac == NULL) { 00815 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { 00816 wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " 00817 "unknown KDF"); 00818 data->notification = 00819 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00820 eap_aka_state(data, NOTIFICATION); 00821 return; 00822 } 00823 00824 data->kdf = attr->kdf[0]; 00825 00826 /* Allow negotiation to continue with the selected KDF by 00827 * sending another Challenge message */ 00828 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); 00829 return; 00830 } 00831 #endif 00832 #endif /* EAP_SERVER_AKA_PRIME */ 00833 00834 if (attr->checkcode && 00835 eap_aka_verify_checkcode(data, attr->checkcode, 00836 attr->checkcode_len)) { 00837 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " 00838 "message"); 00839 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00840 eap_aka_state(data, NOTIFICATION); 00841 return; 00842 } 00843 if (attr->mac == NULL || 00844 eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { 00845 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " 00846 "did not include valid AT_MAC"); 00847 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00848 eap_aka_state(data, NOTIFICATION); 00849 return; 00850 } 00851 00852 /* 00853 * AT_RES is padded, so verify that there is enough room for RES and 00854 * that the RES length in bits matches with the expected RES. 00855 */ 00856 if (attr->res == NULL || attr->res_len < data->res_len || 00857 attr->res_len_bits != data->res_len * 8 || 00858 os_memcmp(attr->res, data->res, data->res_len) != 0) { 00859 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " 00860 "include valid AT_RES (attr len=%lu, res len=%lu " 00861 "bits, expected %lu bits)", 00862 (unsigned long) attr->res_len, 00863 (unsigned long) attr->res_len_bits, 00864 (unsigned long) data->res_len * 8); 00865 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00866 eap_aka_state(data, NOTIFICATION); 00867 return; 00868 } 00869 00870 wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " 00871 "correct AT_MAC"); 00872 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 00873 data->use_result_ind = 1; 00874 data->notification = EAP_SIM_SUCCESS; 00875 eap_aka_state(data, NOTIFICATION); 00876 } else 00877 eap_aka_state(data, SUCCESS); 00878 00879 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, 00880 sm->identity_len, &identity_len); 00881 if (identity == NULL) { 00882 identity = sm->identity; 00883 identity_len = sm->identity_len; 00884 } 00885 00886 if (data->next_pseudonym) { 00887 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 00888 identity_len, 00889 data->next_pseudonym); 00890 data->next_pseudonym = NULL; 00891 } 00892 if (data->next_reauth_id) { 00893 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 00894 #ifdef EAP_SERVER_AKA_PRIME 00895 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 00896 identity, 00897 identity_len, 00898 data->next_reauth_id, 00899 data->counter + 1, 00900 data->k_encr, data->k_aut, 00901 data->k_re); 00902 #endif /* EAP_SERVER_AKA_PRIME */ 00903 } else { 00904 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 00905 identity_len, 00906 data->next_reauth_id, 00907 data->counter + 1, 00908 data->mk); 00909 } 00910 data->next_reauth_id = NULL; 00911 } 00912 } 00913 00914 00915 static void eap_aka_process_sync_failure(struct eap_sm *sm, 00916 struct eap_aka_data *data, 00917 struct wpabuf *respData, 00918 struct eap_sim_attrs *attr) 00919 { 00920 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); 00921 00922 if (attr->auts == NULL) { 00923 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " 00924 "message did not include valid AT_AUTS"); 00925 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00926 eap_aka_state(data, NOTIFICATION); 00927 return; 00928 } 00929 00930 /* Avoid re-reporting AUTS when processing pending EAP packet by 00931 * maintaining a local flag stating whether this AUTS has already been 00932 * reported. */ 00933 if (!data->auts_reported && 00934 eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity, 00935 sm->identity_len, attr->auts, 00936 data->rand)) { 00937 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); 00938 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 00939 eap_aka_state(data, NOTIFICATION); 00940 return; 00941 } 00942 data->auts_reported = 1; 00943 00944 /* Try again after resynchronization */ 00945 eap_aka_determine_identity(sm, data, 0, 0); 00946 } 00947 00948 00949 static void eap_aka_process_reauth(struct eap_sm *sm, 00950 struct eap_aka_data *data, 00951 struct wpabuf *respData, 00952 struct eap_sim_attrs *attr) 00953 { 00954 struct eap_sim_attrs eattr; 00955 u8 *decrypted = NULL; 00956 const u8 *identity, *id2; 00957 size_t identity_len, id2_len; 00958 00959 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); 00960 00961 if (attr->mac == NULL || 00962 eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, 00963 EAP_SIM_NONCE_S_LEN)) { 00964 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 00965 "did not include valid AT_MAC"); 00966 goto fail; 00967 } 00968 00969 if (attr->encr_data == NULL || attr->iv == NULL) { 00970 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " 00971 "message did not include encrypted data"); 00972 goto fail; 00973 } 00974 00975 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 00976 attr->encr_data_len, attr->iv, &eattr, 00977 0); 00978 if (decrypted == NULL) { 00979 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " 00980 "data from reauthentication message"); 00981 goto fail; 00982 } 00983 00984 if (eattr.counter != data->counter) { 00985 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 00986 "used incorrect counter %u, expected %u", 00987 eattr.counter, data->counter); 00988 goto fail; 00989 } 00990 os_free(decrypted); 00991 decrypted = NULL; 00992 00993 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " 00994 "the correct AT_MAC"); 00995 00996 if (eattr.counter_too_small) { 00997 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 00998 "included AT_COUNTER_TOO_SMALL - starting full " 00999 "authentication"); 01000 eap_aka_determine_identity(sm, data, 0, 1); 01001 return; 01002 } 01003 01004 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 01005 data->use_result_ind = 1; 01006 data->notification = EAP_SIM_SUCCESS; 01007 eap_aka_state(data, NOTIFICATION); 01008 } else 01009 eap_aka_state(data, SUCCESS); 01010 01011 if (data->reauth) { 01012 identity = data->reauth->identity; 01013 identity_len = data->reauth->identity_len; 01014 } else { 01015 identity = sm->identity; 01016 identity_len = sm->identity_len; 01017 } 01018 01019 id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, 01020 identity_len, &id2_len); 01021 if (id2) { 01022 identity = id2; 01023 identity_len = id2_len; 01024 } 01025 01026 if (data->next_pseudonym) { 01027 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 01028 identity_len, data->next_pseudonym); 01029 data->next_pseudonym = NULL; 01030 } 01031 if (data->next_reauth_id) { 01032 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 01033 #ifdef EAP_SERVER_AKA_PRIME 01034 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 01035 identity, 01036 identity_len, 01037 data->next_reauth_id, 01038 data->counter + 1, 01039 data->k_encr, data->k_aut, 01040 data->k_re); 01041 #endif /* EAP_SERVER_AKA_PRIME */ 01042 } else { 01043 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 01044 identity_len, 01045 data->next_reauth_id, 01046 data->counter + 1, 01047 data->mk); 01048 } 01049 data->next_reauth_id = NULL; 01050 } else { 01051 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 01052 data->reauth = NULL; 01053 } 01054 01055 return; 01056 01057 fail: 01058 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 01059 eap_aka_state(data, NOTIFICATION); 01060 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 01061 data->reauth = NULL; 01062 os_free(decrypted); 01063 } 01064 01065 01066 static void eap_aka_process_client_error(struct eap_sm *sm, 01067 struct eap_aka_data *data, 01068 struct wpabuf *respData, 01069 struct eap_sim_attrs *attr) 01070 { 01071 wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", 01072 attr->client_error_code); 01073 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 01074 eap_aka_state(data, SUCCESS); 01075 else 01076 eap_aka_state(data, FAILURE); 01077 } 01078 01079 01080 static void eap_aka_process_authentication_reject( 01081 struct eap_sm *sm, struct eap_aka_data *data, 01082 struct wpabuf *respData, struct eap_sim_attrs *attr) 01083 { 01084 wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); 01085 eap_aka_state(data, FAILURE); 01086 } 01087 01088 01089 static void eap_aka_process_notification(struct eap_sm *sm, 01090 struct eap_aka_data *data, 01091 struct wpabuf *respData, 01092 struct eap_sim_attrs *attr) 01093 { 01094 wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); 01095 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 01096 eap_aka_state(data, SUCCESS); 01097 else 01098 eap_aka_state(data, FAILURE); 01099 } 01100 01101 01102 static void eap_aka_process(struct eap_sm *sm, void *priv, 01103 struct wpabuf *respData) 01104 { 01105 struct eap_aka_data *data = priv; 01106 const u8 *pos, *end; 01107 u8 subtype; 01108 size_t len; 01109 struct eap_sim_attrs attr; 01110 01111 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 01112 &len); 01113 if (pos == NULL || len < 3) 01114 return; 01115 01116 end = pos + len; 01117 subtype = *pos; 01118 pos += 3; 01119 01120 if (eap_aka_subtype_ok(data, subtype)) { 01121 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " 01122 "EAP-AKA Subtype in EAP Response"); 01123 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 01124 eap_aka_state(data, NOTIFICATION); 01125 return; 01126 } 01127 01128 if (eap_sim_parse_attr(pos, end, &attr, 01129 data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, 01130 0)) { 01131 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); 01132 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 01133 eap_aka_state(data, NOTIFICATION); 01134 return; 01135 } 01136 01137 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { 01138 eap_aka_process_client_error(sm, data, respData, &attr); 01139 return; 01140 } 01141 01142 if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { 01143 eap_aka_process_authentication_reject(sm, data, respData, 01144 &attr); 01145 return; 01146 } 01147 01148 switch (data->state) { 01149 case IDENTITY: 01150 eap_aka_process_identity(sm, data, respData, &attr); 01151 break; 01152 case CHALLENGE: 01153 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 01154 eap_aka_process_sync_failure(sm, data, respData, 01155 &attr); 01156 } else { 01157 eap_aka_process_challenge(sm, data, respData, &attr); 01158 } 01159 break; 01160 case REAUTH: 01161 eap_aka_process_reauth(sm, data, respData, &attr); 01162 break; 01163 case NOTIFICATION: 01164 eap_aka_process_notification(sm, data, respData, &attr); 01165 break; 01166 default: 01167 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 01168 "process", data->state); 01169 break; 01170 } 01171 } 01172 01173 01174 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) 01175 { 01176 struct eap_aka_data *data = priv; 01177 return data->state == SUCCESS || data->state == FAILURE; 01178 } 01179 01180 01181 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) 01182 { 01183 struct eap_aka_data *data = priv; 01184 u8 *key; 01185 01186 if (data->state != SUCCESS) 01187 return NULL; 01188 01189 key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 01190 if (key == NULL) 01191 return NULL; 01192 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 01193 *len = EAP_SIM_KEYING_DATA_LEN; 01194 return key; 01195 } 01196 01197 01198 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 01199 { 01200 struct eap_aka_data *data = priv; 01201 u8 *key; 01202 01203 if (data->state != SUCCESS) 01204 return NULL; 01205 01206 key = os_malloc(EAP_EMSK_LEN); 01207 if (key == NULL) 01208 return NULL; 01209 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 01210 *len = EAP_EMSK_LEN; 01211 return key; 01212 } 01213 01214 01215 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) 01216 { 01217 struct eap_aka_data *data = priv; 01218 return data->state == SUCCESS; 01219 } 01220 01221 01222 int eap_server_aka_register(void) 01223 { 01224 struct eap_method *eap; 01225 int ret; 01226 01227 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 01228 EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); 01229 if (eap == NULL) 01230 return -1; 01231 01232 eap->init = eap_aka_init; 01233 eap->reset = eap_aka_reset; 01234 eap->buildReq = eap_aka_buildReq; 01235 eap->check = eap_aka_check; 01236 eap->process = eap_aka_process; 01237 eap->isDone = eap_aka_isDone; 01238 eap->getKey = eap_aka_getKey; 01239 eap->isSuccess = eap_aka_isSuccess; 01240 eap->get_emsk = eap_aka_get_emsk; 01241 01242 ret = eap_server_method_register(eap); 01243 if (ret) 01244 eap_server_method_free(eap); 01245 return ret; 01246 } 01247 01248 01249 #ifdef EAP_SERVER_AKA_PRIME 01250 int eap_server_aka_prime_register(void) 01251 { 01252 struct eap_method *eap; 01253 int ret; 01254 01255 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 01256 EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, 01257 "AKA'"); 01258 if (eap == NULL) 01259 return -1; 01260 01261 eap->init = eap_aka_prime_init; 01262 eap->reset = eap_aka_reset; 01263 eap->buildReq = eap_aka_buildReq; 01264 eap->check = eap_aka_check; 01265 eap->process = eap_aka_process; 01266 eap->isDone = eap_aka_isDone; 01267 eap->getKey = eap_aka_getKey; 01268 eap->isSuccess = eap_aka_isSuccess; 01269 eap->get_emsk = eap_aka_get_emsk; 01270 01271 ret = eap_server_method_register(eap); 01272 if (ret) 01273 eap_server_method_free(eap); 01274 01275 return ret; 01276 } 01277 #endif /* EAP_SERVER_AKA_PRIME */