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