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