00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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];
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;
00047
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
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
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
00195
00196
00197 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0);
00198 return;
00199 }
00200
00201
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
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
00280
00281
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
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
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
00680
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
00706
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
00713
00714 data->reauth = NULL;
00715 data->counter = 0;
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
00812
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
00827
00828 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
00829 return;
00830 }
00831 #endif
00832 #endif
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
00854
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
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
00931
00932
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
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
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