eap_server_aka.c revision 04949598a23f501be6eec21697465fd46a28840a
1/* 2 * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) 3 * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "crypto/sha256.h" 13#include "crypto/crypto.h" 14#include "crypto/random.h" 15#include "eap_common/eap_sim_common.h" 16#include "eap_server/eap_i.h" 17#include "eap_server/eap_sim_db.h" 18 19 20struct eap_aka_data { 21 u8 mk[EAP_SIM_MK_LEN]; 22 u8 nonce_s[EAP_SIM_NONCE_S_LEN]; 23 u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; 24 u8 k_encr[EAP_SIM_K_ENCR_LEN]; 25 u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ 26 u8 msk[EAP_SIM_KEYING_DATA_LEN]; 27 u8 emsk[EAP_EMSK_LEN]; 28 u8 rand[EAP_AKA_RAND_LEN]; 29 u8 autn[EAP_AKA_AUTN_LEN]; 30 u8 ck[EAP_AKA_CK_LEN]; 31 u8 ik[EAP_AKA_IK_LEN]; 32 u8 res[EAP_AKA_RES_MAX_LEN]; 33 size_t res_len; 34 enum { 35 IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE 36 } state; 37 char *next_pseudonym; 38 char *next_reauth_id; 39 u16 counter; 40 struct eap_sim_reauth *reauth; 41 int auts_reported; /* whether the current AUTS has been reported to the 42 * eap_sim_db */ 43 u16 notification; 44 int use_result_ind; 45 46 struct wpabuf *id_msgs; 47 int pending_id; 48 u8 eap_method; 49 u8 *network_name; 50 size_t network_name_len; 51 u16 kdf; 52}; 53 54 55static void eap_aka_determine_identity(struct eap_sm *sm, 56 struct eap_aka_data *data, 57 int before_identity, int after_reauth); 58 59 60static const char * eap_aka_state_txt(int state) 61{ 62 switch (state) { 63 case IDENTITY: 64 return "IDENTITY"; 65 case CHALLENGE: 66 return "CHALLENGE"; 67 case REAUTH: 68 return "REAUTH"; 69 case SUCCESS: 70 return "SUCCESS"; 71 case FAILURE: 72 return "FAILURE"; 73 case NOTIFICATION: 74 return "NOTIFICATION"; 75 default: 76 return "Unknown?!"; 77 } 78} 79 80 81static void eap_aka_state(struct eap_aka_data *data, int state) 82{ 83 wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", 84 eap_aka_state_txt(data->state), 85 eap_aka_state_txt(state)); 86 data->state = state; 87} 88 89 90static void * eap_aka_init(struct eap_sm *sm) 91{ 92 struct eap_aka_data *data; 93 94 if (sm->eap_sim_db_priv == NULL) { 95 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 96 return NULL; 97 } 98 99 data = os_zalloc(sizeof(*data)); 100 if (data == NULL) 101 return NULL; 102 103 data->eap_method = EAP_TYPE_AKA; 104 105 data->state = IDENTITY; 106 eap_aka_determine_identity(sm, data, 1, 0); 107 data->pending_id = -1; 108 109 return data; 110} 111 112 113#ifdef EAP_SERVER_AKA_PRIME 114static void * eap_aka_prime_init(struct eap_sm *sm) 115{ 116 struct eap_aka_data *data; 117 /* TODO: make ANID configurable; see 3GPP TS 24.302 */ 118 char *network_name = "WLAN"; 119 120 if (sm->eap_sim_db_priv == NULL) { 121 wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 122 return NULL; 123 } 124 125 data = os_zalloc(sizeof(*data)); 126 if (data == NULL) 127 return NULL; 128 129 data->eap_method = EAP_TYPE_AKA_PRIME; 130 data->network_name = (u8 *) os_strdup(network_name); 131 if (data->network_name == NULL) { 132 os_free(data); 133 return NULL; 134 } 135 136 data->network_name_len = os_strlen(network_name); 137 138 data->state = IDENTITY; 139 eap_aka_determine_identity(sm, data, 1, 0); 140 data->pending_id = -1; 141 142 return data; 143} 144#endif /* EAP_SERVER_AKA_PRIME */ 145 146 147static void eap_aka_reset(struct eap_sm *sm, void *priv) 148{ 149 struct eap_aka_data *data = priv; 150 os_free(data->next_pseudonym); 151 os_free(data->next_reauth_id); 152 wpabuf_free(data->id_msgs); 153 os_free(data->network_name); 154 os_free(data); 155} 156 157 158static int eap_aka_add_id_msg(struct eap_aka_data *data, 159 const struct wpabuf *msg) 160{ 161 if (msg == NULL) 162 return -1; 163 164 if (data->id_msgs == NULL) { 165 data->id_msgs = wpabuf_dup(msg); 166 return data->id_msgs == NULL ? -1 : 0; 167 } 168 169 if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) 170 return -1; 171 wpabuf_put_buf(data->id_msgs, msg); 172 173 return 0; 174} 175 176 177static void eap_aka_add_checkcode(struct eap_aka_data *data, 178 struct eap_sim_msg *msg) 179{ 180 const u8 *addr; 181 size_t len; 182 u8 hash[SHA256_MAC_LEN]; 183 184 wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); 185 186 if (data->id_msgs == NULL) { 187 /* 188 * No EAP-AKA/Identity packets were exchanged - send empty 189 * checkcode. 190 */ 191 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); 192 return; 193 } 194 195 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 196 addr = wpabuf_head(data->id_msgs); 197 len = wpabuf_len(data->id_msgs); 198 wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); 199 if (data->eap_method == EAP_TYPE_AKA_PRIME) 200 sha256_vector(1, &addr, &len, hash); 201 else 202 sha1_vector(1, &addr, &len, hash); 203 204 eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, 205 data->eap_method == EAP_TYPE_AKA_PRIME ? 206 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); 207} 208 209 210static int eap_aka_verify_checkcode(struct eap_aka_data *data, 211 const u8 *checkcode, size_t checkcode_len) 212{ 213 const u8 *addr; 214 size_t len; 215 u8 hash[SHA256_MAC_LEN]; 216 size_t hash_len; 217 218 if (checkcode == NULL) 219 return -1; 220 221 if (data->id_msgs == NULL) { 222 if (checkcode_len != 0) { 223 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " 224 "indicates that AKA/Identity messages were " 225 "used, but they were not"); 226 return -1; 227 } 228 return 0; 229 } 230 231 hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? 232 EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; 233 234 if (checkcode_len != hash_len) { 235 wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates " 236 "that AKA/Identity message were not used, but they " 237 "were"); 238 return -1; 239 } 240 241 /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 242 addr = wpabuf_head(data->id_msgs); 243 len = wpabuf_len(data->id_msgs); 244 if (data->eap_method == EAP_TYPE_AKA_PRIME) 245 sha256_vector(1, &addr, &len, hash); 246 else 247 sha1_vector(1, &addr, &len, hash); 248 249 if (os_memcmp(hash, checkcode, hash_len) != 0) { 250 wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); 251 return -1; 252 } 253 254 return 0; 255} 256 257 258static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, 259 struct eap_aka_data *data, u8 id) 260{ 261 struct eap_sim_msg *msg; 262 struct wpabuf *buf; 263 264 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); 265 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 266 EAP_AKA_SUBTYPE_IDENTITY); 267 if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 268 sm->identity_len)) { 269 if (sm->identity_len > 0 && 270 (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX || 271 sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) { 272 /* Reauth id may have expired - try fullauth */ 273 wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); 274 eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, 275 NULL, 0); 276 } else { 277 wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); 278 eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, 279 NULL, 0); 280 } 281 } else { 282 /* 283 * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is 284 * ignored and the AKA/Identity is used to request the 285 * identity. 286 */ 287 wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); 288 eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); 289 } 290 buf = eap_sim_msg_finish(msg, NULL, NULL, 0); 291 if (eap_aka_add_id_msg(data, buf) < 0) { 292 wpabuf_free(buf); 293 return NULL; 294 } 295 data->pending_id = id; 296 return buf; 297} 298 299 300static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, 301 struct eap_sim_msg *msg, u16 counter, 302 const u8 *nonce_s) 303{ 304 os_free(data->next_pseudonym); 305 if (nonce_s == NULL) { 306 data->next_pseudonym = 307 eap_sim_db_get_next_pseudonym( 308 sm->eap_sim_db_priv, 309 data->eap_method == EAP_TYPE_AKA_PRIME ? 310 EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); 311 } else { 312 /* Do not update pseudonym during re-authentication */ 313 data->next_pseudonym = NULL; 314 } 315 os_free(data->next_reauth_id); 316 if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { 317 data->next_reauth_id = 318 eap_sim_db_get_next_reauth_id( 319 sm->eap_sim_db_priv, 320 data->eap_method == EAP_TYPE_AKA_PRIME ? 321 EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); 322 } else { 323 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " 324 "count exceeded - force full authentication"); 325 data->next_reauth_id = NULL; 326 } 327 328 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 329 counter == 0 && nonce_s == NULL) 330 return 0; 331 332 wpa_printf(MSG_DEBUG, " AT_IV"); 333 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 334 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 335 336 if (counter > 0) { 337 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 338 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 339 } 340 341 if (nonce_s) { 342 wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 343 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 344 EAP_SIM_NONCE_S_LEN); 345 } 346 347 if (data->next_pseudonym) { 348 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 349 data->next_pseudonym); 350 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 351 os_strlen(data->next_pseudonym), 352 (u8 *) data->next_pseudonym, 353 os_strlen(data->next_pseudonym)); 354 } 355 356 if (data->next_reauth_id) { 357 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 358 data->next_reauth_id); 359 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 360 os_strlen(data->next_reauth_id), 361 (u8 *) data->next_reauth_id, 362 os_strlen(data->next_reauth_id)); 363 } 364 365 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 366 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " 367 "AT_ENCR_DATA"); 368 return -1; 369 } 370 371 return 0; 372} 373 374 375static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, 376 struct eap_aka_data *data, 377 u8 id) 378{ 379 struct eap_sim_msg *msg; 380 381 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); 382 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 383 EAP_AKA_SUBTYPE_CHALLENGE); 384 wpa_printf(MSG_DEBUG, " AT_RAND"); 385 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); 386 wpa_printf(MSG_DEBUG, " AT_AUTN"); 387 eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); 388 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 389 if (data->kdf) { 390 /* Add the selected KDF into the beginning */ 391 wpa_printf(MSG_DEBUG, " AT_KDF"); 392 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, 393 NULL, 0); 394 } 395 wpa_printf(MSG_DEBUG, " AT_KDF"); 396 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, 397 NULL, 0); 398 wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); 399 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, 400 data->network_name_len, 401 data->network_name, data->network_name_len); 402 } 403 404 if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { 405 eap_sim_msg_free(msg); 406 return NULL; 407 } 408 409 eap_aka_add_checkcode(data, msg); 410 411 if (sm->eap_sim_aka_result_ind) { 412 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 413 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 414 } 415 416#ifdef EAP_SERVER_AKA_PRIME 417 if (data->eap_method == EAP_TYPE_AKA) { 418 u16 flags = 0; 419 int i; 420 int aka_prime_preferred = 0; 421 422 i = 0; 423 while (sm->user && i < EAP_MAX_METHODS && 424 (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 425 sm->user->methods[i].method != EAP_TYPE_NONE)) { 426 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { 427 if (sm->user->methods[i].method == 428 EAP_TYPE_AKA) 429 break; 430 if (sm->user->methods[i].method == 431 EAP_TYPE_AKA_PRIME) { 432 aka_prime_preferred = 1; 433 break; 434 } 435 } 436 i++; 437 } 438 439 if (aka_prime_preferred) 440 flags |= EAP_AKA_BIDDING_FLAG_D; 441 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); 442 } 443#endif /* EAP_SERVER_AKA_PRIME */ 444 445 wpa_printf(MSG_DEBUG, " AT_MAC"); 446 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 447 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 448} 449 450 451static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, 452 struct eap_aka_data *data, u8 id) 453{ 454 struct eap_sim_msg *msg; 455 456 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); 457 458 if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 459 return NULL; 460 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", 461 data->nonce_s, EAP_SIM_NONCE_S_LEN); 462 463 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 464 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, 465 sm->identity, 466 sm->identity_len, 467 data->nonce_s, 468 data->msk, data->emsk); 469 } else { 470 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 471 data->msk, data->emsk); 472 eap_sim_derive_keys_reauth(data->counter, sm->identity, 473 sm->identity_len, data->nonce_s, 474 data->mk, data->msk, data->emsk); 475 } 476 477 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 478 EAP_AKA_SUBTYPE_REAUTHENTICATION); 479 480 if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 481 eap_sim_msg_free(msg); 482 return NULL; 483 } 484 485 eap_aka_add_checkcode(data, msg); 486 487 if (sm->eap_sim_aka_result_ind) { 488 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 489 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 490 } 491 492 wpa_printf(MSG_DEBUG, " AT_MAC"); 493 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 494 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 495} 496 497 498static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, 499 struct eap_aka_data *data, 500 u8 id) 501{ 502 struct eap_sim_msg *msg; 503 504 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); 505 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 506 EAP_AKA_SUBTYPE_NOTIFICATION); 507 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 508 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 509 NULL, 0); 510 if (data->use_result_ind) { 511 if (data->reauth) { 512 wpa_printf(MSG_DEBUG, " AT_IV"); 513 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 514 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 515 EAP_SIM_AT_ENCR_DATA); 516 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 517 data->counter); 518 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 519 NULL, 0); 520 521 if (eap_sim_msg_add_encr_end(msg, data->k_encr, 522 EAP_SIM_AT_PADDING)) { 523 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " 524 "encrypt AT_ENCR_DATA"); 525 eap_sim_msg_free(msg); 526 return NULL; 527 } 528 } 529 530 wpa_printf(MSG_DEBUG, " AT_MAC"); 531 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 532 } 533 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 534} 535 536 537static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) 538{ 539 struct eap_aka_data *data = priv; 540 541 data->auts_reported = 0; 542 switch (data->state) { 543 case IDENTITY: 544 return eap_aka_build_identity(sm, data, id); 545 case CHALLENGE: 546 return eap_aka_build_challenge(sm, data, id); 547 case REAUTH: 548 return eap_aka_build_reauth(sm, data, id); 549 case NOTIFICATION: 550 return eap_aka_build_notification(sm, data, id); 551 default: 552 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 553 "buildReq", data->state); 554 break; 555 } 556 return NULL; 557} 558 559 560static Boolean eap_aka_check(struct eap_sm *sm, void *priv, 561 struct wpabuf *respData) 562{ 563 struct eap_aka_data *data = priv; 564 const u8 *pos; 565 size_t len; 566 567 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 568 &len); 569 if (pos == NULL || len < 3) { 570 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); 571 return TRUE; 572 } 573 574 return FALSE; 575} 576 577 578static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) 579{ 580 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || 581 subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) 582 return FALSE; 583 584 switch (data->state) { 585 case IDENTITY: 586 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { 587 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 588 "subtype %d", subtype); 589 return TRUE; 590 } 591 break; 592 case CHALLENGE: 593 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && 594 subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 595 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 596 "subtype %d", subtype); 597 return TRUE; 598 } 599 break; 600 case REAUTH: 601 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { 602 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 603 "subtype %d", subtype); 604 return TRUE; 605 } 606 break; 607 case NOTIFICATION: 608 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { 609 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 610 "subtype %d", subtype); 611 return TRUE; 612 } 613 break; 614 default: 615 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " 616 "processing a response", data->state); 617 return TRUE; 618 } 619 620 return FALSE; 621} 622 623 624static void eap_aka_determine_identity(struct eap_sm *sm, 625 struct eap_aka_data *data, 626 int before_identity, int after_reauth) 627{ 628 const u8 *identity; 629 size_t identity_len; 630 int res; 631 632 identity = NULL; 633 identity_len = 0; 634 635 if (after_reauth && data->reauth) { 636 identity = data->reauth->identity; 637 identity_len = data->reauth->identity_len; 638 } else if (sm->identity && sm->identity_len > 0 && 639 (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX || 640 sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) { 641 identity = sm->identity; 642 identity_len = sm->identity_len; 643 } else { 644 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, 645 sm->identity, 646 sm->identity_len, 647 &identity_len); 648 if (identity == NULL) { 649 data->reauth = eap_sim_db_get_reauth_entry( 650 sm->eap_sim_db_priv, sm->identity, 651 sm->identity_len); 652 if (data->reauth && 653 data->reauth->aka_prime != 654 (data->eap_method == EAP_TYPE_AKA_PRIME)) { 655 wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " 656 "was for different AKA version"); 657 data->reauth = NULL; 658 } 659 if (data->reauth) { 660 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " 661 "re-authentication"); 662 identity = data->reauth->identity; 663 identity_len = data->reauth->identity_len; 664 data->counter = data->reauth->counter; 665 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 666 os_memcpy(data->k_encr, 667 data->reauth->k_encr, 668 EAP_SIM_K_ENCR_LEN); 669 os_memcpy(data->k_aut, 670 data->reauth->k_aut, 671 EAP_AKA_PRIME_K_AUT_LEN); 672 os_memcpy(data->k_re, 673 data->reauth->k_re, 674 EAP_AKA_PRIME_K_RE_LEN); 675 } else { 676 os_memcpy(data->mk, data->reauth->mk, 677 EAP_SIM_MK_LEN); 678 } 679 } 680 } 681 } 682 683 if (identity == NULL || 684 eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 685 sm->identity_len) < 0) { 686 if (before_identity) { 687 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " 688 "not known - send AKA-Identity request"); 689 eap_aka_state(data, IDENTITY); 690 return; 691 } else { 692 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " 693 "permanent user name is known; try to use " 694 "it"); 695 /* eap_sim_db_get_aka_auth() will report failure, if 696 * this identity is not known. */ 697 } 698 } 699 700 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", 701 identity, identity_len); 702 703 if (!after_reauth && data->reauth) { 704 eap_aka_state(data, REAUTH); 705 return; 706 } 707 708 res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, 709 identity_len, data->rand, data->autn, 710 data->ik, data->ck, data->res, 711 &data->res_len, sm); 712 if (res == EAP_SIM_DB_PENDING) { 713 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 714 "not yet available - pending request"); 715 sm->method_pending = METHOD_PENDING_WAIT; 716 return; 717 } 718 719#ifdef EAP_SERVER_AKA_PRIME 720 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 721 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the 722 * needed 6-octet SQN ^AK for CK',IK' derivation */ 723 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, 724 data->autn, 725 data->network_name, 726 data->network_name_len); 727 } 728#endif /* EAP_SERVER_AKA_PRIME */ 729 730 data->reauth = NULL; 731 data->counter = 0; /* reset re-auth counter since this is full auth */ 732 733 if (res != 0) { 734 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " 735 "authentication data for the peer"); 736 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 737 eap_aka_state(data, NOTIFICATION); 738 return; 739 } 740 if (sm->method_pending == METHOD_PENDING_WAIT) { 741 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 742 "available - abort pending wait"); 743 sm->method_pending = METHOD_PENDING_NONE; 744 } 745 746 identity_len = sm->identity_len; 747 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 748 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " 749 "character from identity"); 750 identity_len--; 751 } 752 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", 753 sm->identity, identity_len); 754 755 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 756 eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik, 757 data->ck, data->k_encr, data->k_aut, 758 data->k_re, data->msk, data->emsk); 759 } else { 760 eap_aka_derive_mk(sm->identity, identity_len, data->ik, 761 data->ck, data->mk); 762 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 763 data->msk, data->emsk); 764 } 765 766 eap_aka_state(data, CHALLENGE); 767} 768 769 770static void eap_aka_process_identity(struct eap_sm *sm, 771 struct eap_aka_data *data, 772 struct wpabuf *respData, 773 struct eap_sim_attrs *attr) 774{ 775 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); 776 777 if (attr->mac || attr->iv || attr->encr_data) { 778 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " 779 "received in EAP-Response/AKA-Identity"); 780 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 781 eap_aka_state(data, NOTIFICATION); 782 return; 783 } 784 785 if (attr->identity) { 786 os_free(sm->identity); 787 sm->identity = os_malloc(attr->identity_len); 788 if (sm->identity) { 789 os_memcpy(sm->identity, attr->identity, 790 attr->identity_len); 791 sm->identity_len = attr->identity_len; 792 } 793 } 794 795 eap_aka_determine_identity(sm, data, 0, 0); 796 if (eap_get_id(respData) == data->pending_id) { 797 data->pending_id = -1; 798 eap_aka_add_id_msg(data, respData); 799 } 800} 801 802 803static int eap_aka_verify_mac(struct eap_aka_data *data, 804 const struct wpabuf *req, 805 const u8 *mac, const u8 *extra, 806 size_t extra_len) 807{ 808 if (data->eap_method == EAP_TYPE_AKA_PRIME) 809 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, 810 extra_len); 811 return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); 812} 813 814 815static void eap_aka_process_challenge(struct eap_sm *sm, 816 struct eap_aka_data *data, 817 struct wpabuf *respData, 818 struct eap_sim_attrs *attr) 819{ 820 const u8 *identity; 821 size_t identity_len; 822 823 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); 824 825#ifdef EAP_SERVER_AKA_PRIME 826#if 0 827 /* KDF negotiation; to be enabled only after more than one KDF is 828 * supported */ 829 if (data->eap_method == EAP_TYPE_AKA_PRIME && 830 attr->kdf_count == 1 && attr->mac == NULL) { 831 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { 832 wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " 833 "unknown KDF"); 834 data->notification = 835 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 836 eap_aka_state(data, NOTIFICATION); 837 return; 838 } 839 840 data->kdf = attr->kdf[0]; 841 842 /* Allow negotiation to continue with the selected KDF by 843 * sending another Challenge message */ 844 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); 845 return; 846 } 847#endif 848#endif /* EAP_SERVER_AKA_PRIME */ 849 850 if (attr->checkcode && 851 eap_aka_verify_checkcode(data, attr->checkcode, 852 attr->checkcode_len)) { 853 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " 854 "message"); 855 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 856 eap_aka_state(data, NOTIFICATION); 857 return; 858 } 859 if (attr->mac == NULL || 860 eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { 861 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " 862 "did not include valid AT_MAC"); 863 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 864 eap_aka_state(data, NOTIFICATION); 865 return; 866 } 867 868 /* 869 * AT_RES is padded, so verify that there is enough room for RES and 870 * that the RES length in bits matches with the expected RES. 871 */ 872 if (attr->res == NULL || attr->res_len < data->res_len || 873 attr->res_len_bits != data->res_len * 8 || 874 os_memcmp(attr->res, data->res, data->res_len) != 0) { 875 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " 876 "include valid AT_RES (attr len=%lu, res len=%lu " 877 "bits, expected %lu bits)", 878 (unsigned long) attr->res_len, 879 (unsigned long) attr->res_len_bits, 880 (unsigned long) data->res_len * 8); 881 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 882 eap_aka_state(data, NOTIFICATION); 883 return; 884 } 885 886 wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " 887 "correct AT_MAC"); 888 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 889 data->use_result_ind = 1; 890 data->notification = EAP_SIM_SUCCESS; 891 eap_aka_state(data, NOTIFICATION); 892 } else 893 eap_aka_state(data, SUCCESS); 894 895 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, 896 sm->identity_len, &identity_len); 897 if (identity == NULL) { 898 identity = sm->identity; 899 identity_len = sm->identity_len; 900 } 901 902 if (data->next_pseudonym) { 903 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 904 identity_len, 905 data->next_pseudonym); 906 data->next_pseudonym = NULL; 907 } 908 if (data->next_reauth_id) { 909 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 910#ifdef EAP_SERVER_AKA_PRIME 911 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 912 identity, 913 identity_len, 914 data->next_reauth_id, 915 data->counter + 1, 916 data->k_encr, data->k_aut, 917 data->k_re); 918#endif /* EAP_SERVER_AKA_PRIME */ 919 } else { 920 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 921 identity_len, 922 data->next_reauth_id, 923 data->counter + 1, 924 data->mk); 925 } 926 data->next_reauth_id = NULL; 927 } 928} 929 930 931static void eap_aka_process_sync_failure(struct eap_sm *sm, 932 struct eap_aka_data *data, 933 struct wpabuf *respData, 934 struct eap_sim_attrs *attr) 935{ 936 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); 937 938 if (attr->auts == NULL) { 939 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " 940 "message did not include valid AT_AUTS"); 941 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 942 eap_aka_state(data, NOTIFICATION); 943 return; 944 } 945 946 /* Avoid re-reporting AUTS when processing pending EAP packet by 947 * maintaining a local flag stating whether this AUTS has already been 948 * reported. */ 949 if (!data->auts_reported && 950 eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity, 951 sm->identity_len, attr->auts, 952 data->rand)) { 953 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); 954 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 955 eap_aka_state(data, NOTIFICATION); 956 return; 957 } 958 data->auts_reported = 1; 959 960 /* Try again after resynchronization */ 961 eap_aka_determine_identity(sm, data, 0, 0); 962} 963 964 965static void eap_aka_process_reauth(struct eap_sm *sm, 966 struct eap_aka_data *data, 967 struct wpabuf *respData, 968 struct eap_sim_attrs *attr) 969{ 970 struct eap_sim_attrs eattr; 971 u8 *decrypted = NULL; 972 const u8 *identity, *id2; 973 size_t identity_len, id2_len; 974 975 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); 976 977 if (attr->mac == NULL || 978 eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, 979 EAP_SIM_NONCE_S_LEN)) { 980 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 981 "did not include valid AT_MAC"); 982 goto fail; 983 } 984 985 if (attr->encr_data == NULL || attr->iv == NULL) { 986 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " 987 "message did not include encrypted data"); 988 goto fail; 989 } 990 991 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 992 attr->encr_data_len, attr->iv, &eattr, 993 0); 994 if (decrypted == NULL) { 995 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " 996 "data from reauthentication message"); 997 goto fail; 998 } 999 1000 if (eattr.counter != data->counter) { 1001 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 1002 "used incorrect counter %u, expected %u", 1003 eattr.counter, data->counter); 1004 goto fail; 1005 } 1006 os_free(decrypted); 1007 decrypted = NULL; 1008 1009 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " 1010 "the correct AT_MAC"); 1011 1012 if (eattr.counter_too_small) { 1013 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 1014 "included AT_COUNTER_TOO_SMALL - starting full " 1015 "authentication"); 1016 eap_aka_determine_identity(sm, data, 0, 1); 1017 return; 1018 } 1019 1020 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 1021 data->use_result_ind = 1; 1022 data->notification = EAP_SIM_SUCCESS; 1023 eap_aka_state(data, NOTIFICATION); 1024 } else 1025 eap_aka_state(data, SUCCESS); 1026 1027 if (data->reauth) { 1028 identity = data->reauth->identity; 1029 identity_len = data->reauth->identity_len; 1030 } else { 1031 identity = sm->identity; 1032 identity_len = sm->identity_len; 1033 } 1034 1035 id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, 1036 identity_len, &id2_len); 1037 if (id2) { 1038 identity = id2; 1039 identity_len = id2_len; 1040 } 1041 1042 if (data->next_reauth_id) { 1043 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 1044#ifdef EAP_SERVER_AKA_PRIME 1045 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 1046 identity, 1047 identity_len, 1048 data->next_reauth_id, 1049 data->counter + 1, 1050 data->k_encr, data->k_aut, 1051 data->k_re); 1052#endif /* EAP_SERVER_AKA_PRIME */ 1053 } else { 1054 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 1055 identity_len, 1056 data->next_reauth_id, 1057 data->counter + 1, 1058 data->mk); 1059 } 1060 data->next_reauth_id = NULL; 1061 } else { 1062 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1063 data->reauth = NULL; 1064 } 1065 1066 return; 1067 1068fail: 1069 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1070 eap_aka_state(data, NOTIFICATION); 1071 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1072 data->reauth = NULL; 1073 os_free(decrypted); 1074} 1075 1076 1077static void eap_aka_process_client_error(struct eap_sm *sm, 1078 struct eap_aka_data *data, 1079 struct wpabuf *respData, 1080 struct eap_sim_attrs *attr) 1081{ 1082 wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", 1083 attr->client_error_code); 1084 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1085 eap_aka_state(data, SUCCESS); 1086 else 1087 eap_aka_state(data, FAILURE); 1088} 1089 1090 1091static void eap_aka_process_authentication_reject( 1092 struct eap_sm *sm, struct eap_aka_data *data, 1093 struct wpabuf *respData, struct eap_sim_attrs *attr) 1094{ 1095 wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); 1096 eap_aka_state(data, FAILURE); 1097} 1098 1099 1100static void eap_aka_process_notification(struct eap_sm *sm, 1101 struct eap_aka_data *data, 1102 struct wpabuf *respData, 1103 struct eap_sim_attrs *attr) 1104{ 1105 wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); 1106 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1107 eap_aka_state(data, SUCCESS); 1108 else 1109 eap_aka_state(data, FAILURE); 1110} 1111 1112 1113static void eap_aka_process(struct eap_sm *sm, void *priv, 1114 struct wpabuf *respData) 1115{ 1116 struct eap_aka_data *data = priv; 1117 const u8 *pos, *end; 1118 u8 subtype; 1119 size_t len; 1120 struct eap_sim_attrs attr; 1121 1122 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 1123 &len); 1124 if (pos == NULL || len < 3) 1125 return; 1126 1127 end = pos + len; 1128 subtype = *pos; 1129 pos += 3; 1130 1131 if (eap_aka_subtype_ok(data, subtype)) { 1132 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " 1133 "EAP-AKA Subtype in EAP Response"); 1134 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1135 eap_aka_state(data, NOTIFICATION); 1136 return; 1137 } 1138 1139 if (eap_sim_parse_attr(pos, end, &attr, 1140 data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, 1141 0)) { 1142 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); 1143 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1144 eap_aka_state(data, NOTIFICATION); 1145 return; 1146 } 1147 1148 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { 1149 eap_aka_process_client_error(sm, data, respData, &attr); 1150 return; 1151 } 1152 1153 if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { 1154 eap_aka_process_authentication_reject(sm, data, respData, 1155 &attr); 1156 return; 1157 } 1158 1159 switch (data->state) { 1160 case IDENTITY: 1161 eap_aka_process_identity(sm, data, respData, &attr); 1162 break; 1163 case CHALLENGE: 1164 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 1165 eap_aka_process_sync_failure(sm, data, respData, 1166 &attr); 1167 } else { 1168 eap_aka_process_challenge(sm, data, respData, &attr); 1169 } 1170 break; 1171 case REAUTH: 1172 eap_aka_process_reauth(sm, data, respData, &attr); 1173 break; 1174 case NOTIFICATION: 1175 eap_aka_process_notification(sm, data, respData, &attr); 1176 break; 1177 default: 1178 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 1179 "process", data->state); 1180 break; 1181 } 1182} 1183 1184 1185static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) 1186{ 1187 struct eap_aka_data *data = priv; 1188 return data->state == SUCCESS || data->state == FAILURE; 1189} 1190 1191 1192static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) 1193{ 1194 struct eap_aka_data *data = priv; 1195 u8 *key; 1196 1197 if (data->state != SUCCESS) 1198 return NULL; 1199 1200 key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 1201 if (key == NULL) 1202 return NULL; 1203 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 1204 *len = EAP_SIM_KEYING_DATA_LEN; 1205 return key; 1206} 1207 1208 1209static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1210{ 1211 struct eap_aka_data *data = priv; 1212 u8 *key; 1213 1214 if (data->state != SUCCESS) 1215 return NULL; 1216 1217 key = os_malloc(EAP_EMSK_LEN); 1218 if (key == NULL) 1219 return NULL; 1220 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1221 *len = EAP_EMSK_LEN; 1222 return key; 1223} 1224 1225 1226static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) 1227{ 1228 struct eap_aka_data *data = priv; 1229 return data->state == SUCCESS; 1230} 1231 1232 1233int eap_server_aka_register(void) 1234{ 1235 struct eap_method *eap; 1236 int ret; 1237 1238 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1239 EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); 1240 if (eap == NULL) 1241 return -1; 1242 1243 eap->init = eap_aka_init; 1244 eap->reset = eap_aka_reset; 1245 eap->buildReq = eap_aka_buildReq; 1246 eap->check = eap_aka_check; 1247 eap->process = eap_aka_process; 1248 eap->isDone = eap_aka_isDone; 1249 eap->getKey = eap_aka_getKey; 1250 eap->isSuccess = eap_aka_isSuccess; 1251 eap->get_emsk = eap_aka_get_emsk; 1252 1253 ret = eap_server_method_register(eap); 1254 if (ret) 1255 eap_server_method_free(eap); 1256 return ret; 1257} 1258 1259 1260#ifdef EAP_SERVER_AKA_PRIME 1261int eap_server_aka_prime_register(void) 1262{ 1263 struct eap_method *eap; 1264 int ret; 1265 1266 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1267 EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, 1268 "AKA'"); 1269 if (eap == NULL) 1270 return -1; 1271 1272 eap->init = eap_aka_prime_init; 1273 eap->reset = eap_aka_reset; 1274 eap->buildReq = eap_aka_buildReq; 1275 eap->check = eap_aka_check; 1276 eap->process = eap_aka_process; 1277 eap->isDone = eap_aka_isDone; 1278 eap->getKey = eap_aka_getKey; 1279 eap->isSuccess = eap_aka_isSuccess; 1280 eap->get_emsk = eap_aka_get_emsk; 1281 1282 ret = eap_server_method_register(eap); 1283 if (ret) 1284 eap_server_method_free(eap); 1285 1286 return ret; 1287} 1288#endif /* EAP_SERVER_AKA_PRIME */ 1289