1 /* 2 * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) 3 * Copyright (c) 2005-2008, 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(sm->eap_sim_db_priv, 1); 304 } else { 305 /* Do not update pseudonym during re-authentication */ 306 data->next_pseudonym = NULL; 307 } 308 os_free(data->next_reauth_id); 309 if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { 310 data->next_reauth_id = 311 eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); 312 } else { 313 wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " 314 "count exceeded - force full authentication"); 315 data->next_reauth_id = NULL; 316 } 317 318 if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 319 counter == 0 && nonce_s == NULL) 320 return 0; 321 322 wpa_printf(MSG_DEBUG, " AT_IV"); 323 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 324 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 325 326 if (counter > 0) { 327 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 328 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 329 } 330 331 if (nonce_s) { 332 wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 333 eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 334 EAP_SIM_NONCE_S_LEN); 335 } 336 337 if (data->next_pseudonym) { 338 wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 339 data->next_pseudonym); 340 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 341 os_strlen(data->next_pseudonym), 342 (u8 *) data->next_pseudonym, 343 os_strlen(data->next_pseudonym)); 344 } 345 346 if (data->next_reauth_id) { 347 wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 348 data->next_reauth_id); 349 eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 350 os_strlen(data->next_reauth_id), 351 (u8 *) data->next_reauth_id, 352 os_strlen(data->next_reauth_id)); 353 } 354 355 if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 356 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " 357 "AT_ENCR_DATA"); 358 return -1; 359 } 360 361 return 0; 362 } 363 364 365 static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, 366 struct eap_aka_data *data, 367 u8 id) 368 { 369 struct eap_sim_msg *msg; 370 371 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); 372 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 373 EAP_AKA_SUBTYPE_CHALLENGE); 374 wpa_printf(MSG_DEBUG, " AT_RAND"); 375 eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); 376 wpa_printf(MSG_DEBUG, " AT_AUTN"); 377 eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); 378 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 379 if (data->kdf) { 380 /* Add the selected KDF into the beginning */ 381 wpa_printf(MSG_DEBUG, " AT_KDF"); 382 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, 383 NULL, 0); 384 } 385 wpa_printf(MSG_DEBUG, " AT_KDF"); 386 eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, 387 NULL, 0); 388 wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); 389 eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, 390 data->network_name_len, 391 data->network_name, data->network_name_len); 392 } 393 394 if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { 395 eap_sim_msg_free(msg); 396 return NULL; 397 } 398 399 eap_aka_add_checkcode(data, msg); 400 401 if (sm->eap_sim_aka_result_ind) { 402 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 403 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 404 } 405 406 #ifdef EAP_SERVER_AKA_PRIME 407 if (data->eap_method == EAP_TYPE_AKA) { 408 u16 flags = 0; 409 int i; 410 int aka_prime_preferred = 0; 411 412 i = 0; 413 while (sm->user && i < EAP_MAX_METHODS && 414 (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 415 sm->user->methods[i].method != EAP_TYPE_NONE)) { 416 if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { 417 if (sm->user->methods[i].method == 418 EAP_TYPE_AKA) 419 break; 420 if (sm->user->methods[i].method == 421 EAP_TYPE_AKA_PRIME) { 422 aka_prime_preferred = 1; 423 break; 424 } 425 } 426 i++; 427 } 428 429 if (aka_prime_preferred) 430 flags |= EAP_AKA_BIDDING_FLAG_D; 431 eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); 432 } 433 #endif /* EAP_SERVER_AKA_PRIME */ 434 435 wpa_printf(MSG_DEBUG, " AT_MAC"); 436 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 437 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 438 } 439 440 441 static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, 442 struct eap_aka_data *data, u8 id) 443 { 444 struct eap_sim_msg *msg; 445 446 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); 447 448 if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 449 return NULL; 450 wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", 451 data->nonce_s, EAP_SIM_NONCE_S_LEN); 452 453 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 454 eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, 455 sm->identity, 456 sm->identity_len, 457 data->nonce_s, 458 data->msk, data->emsk); 459 } else { 460 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 461 data->msk, data->emsk); 462 eap_sim_derive_keys_reauth(data->counter, sm->identity, 463 sm->identity_len, data->nonce_s, 464 data->mk, data->msk, data->emsk); 465 } 466 467 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 468 EAP_AKA_SUBTYPE_REAUTHENTICATION); 469 470 if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 471 eap_sim_msg_free(msg); 472 return NULL; 473 } 474 475 eap_aka_add_checkcode(data, msg); 476 477 if (sm->eap_sim_aka_result_ind) { 478 wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 479 eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 480 } 481 482 wpa_printf(MSG_DEBUG, " AT_MAC"); 483 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 484 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 485 } 486 487 488 static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, 489 struct eap_aka_data *data, 490 u8 id) 491 { 492 struct eap_sim_msg *msg; 493 494 wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); 495 msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 496 EAP_AKA_SUBTYPE_NOTIFICATION); 497 wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 498 eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 499 NULL, 0); 500 if (data->use_result_ind) { 501 if (data->reauth) { 502 wpa_printf(MSG_DEBUG, " AT_IV"); 503 wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 504 eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 505 EAP_SIM_AT_ENCR_DATA); 506 wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 507 data->counter); 508 eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 509 NULL, 0); 510 511 if (eap_sim_msg_add_encr_end(msg, data->k_encr, 512 EAP_SIM_AT_PADDING)) { 513 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " 514 "encrypt AT_ENCR_DATA"); 515 eap_sim_msg_free(msg); 516 return NULL; 517 } 518 } 519 520 wpa_printf(MSG_DEBUG, " AT_MAC"); 521 eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 522 } 523 return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 524 } 525 526 527 static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) 528 { 529 struct eap_aka_data *data = priv; 530 531 data->auts_reported = 0; 532 switch (data->state) { 533 case IDENTITY: 534 return eap_aka_build_identity(sm, data, id); 535 case CHALLENGE: 536 return eap_aka_build_challenge(sm, data, id); 537 case REAUTH: 538 return eap_aka_build_reauth(sm, data, id); 539 case NOTIFICATION: 540 return eap_aka_build_notification(sm, data, id); 541 default: 542 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 543 "buildReq", data->state); 544 break; 545 } 546 return NULL; 547 } 548 549 550 static Boolean eap_aka_check(struct eap_sm *sm, void *priv, 551 struct wpabuf *respData) 552 { 553 struct eap_aka_data *data = priv; 554 const u8 *pos; 555 size_t len; 556 557 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 558 &len); 559 if (pos == NULL || len < 3) { 560 wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); 561 return TRUE; 562 } 563 564 return FALSE; 565 } 566 567 568 static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) 569 { 570 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || 571 subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) 572 return FALSE; 573 574 switch (data->state) { 575 case IDENTITY: 576 if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { 577 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 578 "subtype %d", subtype); 579 return TRUE; 580 } 581 break; 582 case CHALLENGE: 583 if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && 584 subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 585 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 586 "subtype %d", subtype); 587 return TRUE; 588 } 589 break; 590 case REAUTH: 591 if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { 592 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 593 "subtype %d", subtype); 594 return TRUE; 595 } 596 break; 597 case NOTIFICATION: 598 if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { 599 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 600 "subtype %d", subtype); 601 return TRUE; 602 } 603 break; 604 default: 605 wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " 606 "processing a response", data->state); 607 return TRUE; 608 } 609 610 return FALSE; 611 } 612 613 614 static void eap_aka_determine_identity(struct eap_sm *sm, 615 struct eap_aka_data *data, 616 int before_identity, int after_reauth) 617 { 618 const u8 *identity; 619 size_t identity_len; 620 int res; 621 622 identity = NULL; 623 identity_len = 0; 624 625 if (after_reauth && data->reauth) { 626 identity = data->reauth->identity; 627 identity_len = data->reauth->identity_len; 628 } else if (sm->identity && sm->identity_len > 0 && 629 sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { 630 identity = sm->identity; 631 identity_len = sm->identity_len; 632 } else { 633 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, 634 sm->identity, 635 sm->identity_len, 636 &identity_len); 637 if (identity == NULL) { 638 data->reauth = eap_sim_db_get_reauth_entry( 639 sm->eap_sim_db_priv, sm->identity, 640 sm->identity_len); 641 if (data->reauth && 642 data->reauth->aka_prime != 643 (data->eap_method == EAP_TYPE_AKA_PRIME)) { 644 wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " 645 "was for different AKA version"); 646 data->reauth = NULL; 647 } 648 if (data->reauth) { 649 wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " 650 "re-authentication"); 651 identity = data->reauth->identity; 652 identity_len = data->reauth->identity_len; 653 data->counter = data->reauth->counter; 654 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 655 os_memcpy(data->k_encr, 656 data->reauth->k_encr, 657 EAP_SIM_K_ENCR_LEN); 658 os_memcpy(data->k_aut, 659 data->reauth->k_aut, 660 EAP_AKA_PRIME_K_AUT_LEN); 661 os_memcpy(data->k_re, 662 data->reauth->k_re, 663 EAP_AKA_PRIME_K_RE_LEN); 664 } else { 665 os_memcpy(data->mk, data->reauth->mk, 666 EAP_SIM_MK_LEN); 667 } 668 } 669 } 670 } 671 672 if (identity == NULL || 673 eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 674 sm->identity_len) < 0) { 675 if (before_identity) { 676 wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " 677 "not known - send AKA-Identity request"); 678 eap_aka_state(data, IDENTITY); 679 return; 680 } else { 681 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " 682 "permanent user name is known; try to use " 683 "it"); 684 /* eap_sim_db_get_aka_auth() will report failure, if 685 * this identity is not known. */ 686 } 687 } 688 689 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", 690 identity, identity_len); 691 692 if (!after_reauth && data->reauth) { 693 eap_aka_state(data, REAUTH); 694 return; 695 } 696 697 res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, 698 identity_len, data->rand, data->autn, 699 data->ik, data->ck, data->res, 700 &data->res_len, sm); 701 if (res == EAP_SIM_DB_PENDING) { 702 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 703 "not yet available - pending request"); 704 sm->method_pending = METHOD_PENDING_WAIT; 705 return; 706 } 707 708 #ifdef EAP_SERVER_AKA_PRIME 709 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 710 /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the 711 * needed 6-octet SQN ^AK for CK',IK' derivation */ 712 eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, 713 data->autn, 714 data->network_name, 715 data->network_name_len); 716 } 717 #endif /* EAP_SERVER_AKA_PRIME */ 718 719 data->reauth = NULL; 720 data->counter = 0; /* reset re-auth counter since this is full auth */ 721 722 if (res != 0) { 723 wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " 724 "authentication data for the peer"); 725 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 726 eap_aka_state(data, NOTIFICATION); 727 return; 728 } 729 if (sm->method_pending == METHOD_PENDING_WAIT) { 730 wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 731 "available - abort pending wait"); 732 sm->method_pending = METHOD_PENDING_NONE; 733 } 734 735 identity_len = sm->identity_len; 736 while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 737 wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " 738 "character from identity"); 739 identity_len--; 740 } 741 wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", 742 sm->identity, identity_len); 743 744 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 745 eap_aka_prime_derive_keys(identity, identity_len, data->ik, 746 data->ck, data->k_encr, data->k_aut, 747 data->k_re, data->msk, data->emsk); 748 } else { 749 eap_aka_derive_mk(sm->identity, identity_len, data->ik, 750 data->ck, data->mk); 751 eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 752 data->msk, data->emsk); 753 } 754 755 eap_aka_state(data, CHALLENGE); 756 } 757 758 759 static void eap_aka_process_identity(struct eap_sm *sm, 760 struct eap_aka_data *data, 761 struct wpabuf *respData, 762 struct eap_sim_attrs *attr) 763 { 764 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); 765 766 if (attr->mac || attr->iv || attr->encr_data) { 767 wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " 768 "received in EAP-Response/AKA-Identity"); 769 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 770 eap_aka_state(data, NOTIFICATION); 771 return; 772 } 773 774 if (attr->identity) { 775 os_free(sm->identity); 776 sm->identity = os_malloc(attr->identity_len); 777 if (sm->identity) { 778 os_memcpy(sm->identity, attr->identity, 779 attr->identity_len); 780 sm->identity_len = attr->identity_len; 781 } 782 } 783 784 eap_aka_determine_identity(sm, data, 0, 0); 785 if (eap_get_id(respData) == data->pending_id) { 786 data->pending_id = -1; 787 eap_aka_add_id_msg(data, respData); 788 } 789 } 790 791 792 static int eap_aka_verify_mac(struct eap_aka_data *data, 793 const struct wpabuf *req, 794 const u8 *mac, const u8 *extra, 795 size_t extra_len) 796 { 797 if (data->eap_method == EAP_TYPE_AKA_PRIME) 798 return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, 799 extra_len); 800 return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); 801 } 802 803 804 static void eap_aka_process_challenge(struct eap_sm *sm, 805 struct eap_aka_data *data, 806 struct wpabuf *respData, 807 struct eap_sim_attrs *attr) 808 { 809 const u8 *identity; 810 size_t identity_len; 811 812 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); 813 814 #ifdef EAP_SERVER_AKA_PRIME 815 #if 0 816 /* KDF negotiation; to be enabled only after more than one KDF is 817 * supported */ 818 if (data->eap_method == EAP_TYPE_AKA_PRIME && 819 attr->kdf_count == 1 && attr->mac == NULL) { 820 if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { 821 wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " 822 "unknown KDF"); 823 data->notification = 824 EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 825 eap_aka_state(data, NOTIFICATION); 826 return; 827 } 828 829 data->kdf = attr->kdf[0]; 830 831 /* Allow negotiation to continue with the selected KDF by 832 * sending another Challenge message */ 833 wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); 834 return; 835 } 836 #endif 837 #endif /* EAP_SERVER_AKA_PRIME */ 838 839 if (attr->checkcode && 840 eap_aka_verify_checkcode(data, attr->checkcode, 841 attr->checkcode_len)) { 842 wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " 843 "message"); 844 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 845 eap_aka_state(data, NOTIFICATION); 846 return; 847 } 848 if (attr->mac == NULL || 849 eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { 850 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " 851 "did not include valid AT_MAC"); 852 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 853 eap_aka_state(data, NOTIFICATION); 854 return; 855 } 856 857 /* 858 * AT_RES is padded, so verify that there is enough room for RES and 859 * that the RES length in bits matches with the expected RES. 860 */ 861 if (attr->res == NULL || attr->res_len < data->res_len || 862 attr->res_len_bits != data->res_len * 8 || 863 os_memcmp(attr->res, data->res, data->res_len) != 0) { 864 wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " 865 "include valid AT_RES (attr len=%lu, res len=%lu " 866 "bits, expected %lu bits)", 867 (unsigned long) attr->res_len, 868 (unsigned long) attr->res_len_bits, 869 (unsigned long) data->res_len * 8); 870 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 871 eap_aka_state(data, NOTIFICATION); 872 return; 873 } 874 875 wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " 876 "correct AT_MAC"); 877 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 878 data->use_result_ind = 1; 879 data->notification = EAP_SIM_SUCCESS; 880 eap_aka_state(data, NOTIFICATION); 881 } else 882 eap_aka_state(data, SUCCESS); 883 884 identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, 885 sm->identity_len, &identity_len); 886 if (identity == NULL) { 887 identity = sm->identity; 888 identity_len = sm->identity_len; 889 } 890 891 if (data->next_pseudonym) { 892 eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 893 identity_len, 894 data->next_pseudonym); 895 data->next_pseudonym = NULL; 896 } 897 if (data->next_reauth_id) { 898 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 899 #ifdef EAP_SERVER_AKA_PRIME 900 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 901 identity, 902 identity_len, 903 data->next_reauth_id, 904 data->counter + 1, 905 data->k_encr, data->k_aut, 906 data->k_re); 907 #endif /* EAP_SERVER_AKA_PRIME */ 908 } else { 909 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 910 identity_len, 911 data->next_reauth_id, 912 data->counter + 1, 913 data->mk); 914 } 915 data->next_reauth_id = NULL; 916 } 917 } 918 919 920 static void eap_aka_process_sync_failure(struct eap_sm *sm, 921 struct eap_aka_data *data, 922 struct wpabuf *respData, 923 struct eap_sim_attrs *attr) 924 { 925 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); 926 927 if (attr->auts == NULL) { 928 wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " 929 "message did not include valid AT_AUTS"); 930 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 931 eap_aka_state(data, NOTIFICATION); 932 return; 933 } 934 935 /* Avoid re-reporting AUTS when processing pending EAP packet by 936 * maintaining a local flag stating whether this AUTS has already been 937 * reported. */ 938 if (!data->auts_reported && 939 eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity, 940 sm->identity_len, attr->auts, 941 data->rand)) { 942 wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); 943 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 944 eap_aka_state(data, NOTIFICATION); 945 return; 946 } 947 data->auts_reported = 1; 948 949 /* Try again after resynchronization */ 950 eap_aka_determine_identity(sm, data, 0, 0); 951 } 952 953 954 static void eap_aka_process_reauth(struct eap_sm *sm, 955 struct eap_aka_data *data, 956 struct wpabuf *respData, 957 struct eap_sim_attrs *attr) 958 { 959 struct eap_sim_attrs eattr; 960 u8 *decrypted = NULL; 961 const u8 *identity, *id2; 962 size_t identity_len, id2_len; 963 964 wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); 965 966 if (attr->mac == NULL || 967 eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, 968 EAP_SIM_NONCE_S_LEN)) { 969 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 970 "did not include valid AT_MAC"); 971 goto fail; 972 } 973 974 if (attr->encr_data == NULL || attr->iv == NULL) { 975 wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " 976 "message did not include encrypted data"); 977 goto fail; 978 } 979 980 decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 981 attr->encr_data_len, attr->iv, &eattr, 982 0); 983 if (decrypted == NULL) { 984 wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " 985 "data from reauthentication message"); 986 goto fail; 987 } 988 989 if (eattr.counter != data->counter) { 990 wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 991 "used incorrect counter %u, expected %u", 992 eattr.counter, data->counter); 993 goto fail; 994 } 995 os_free(decrypted); 996 decrypted = NULL; 997 998 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " 999 "the correct AT_MAC"); 1000 1001 if (eattr.counter_too_small) { 1002 wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 1003 "included AT_COUNTER_TOO_SMALL - starting full " 1004 "authentication"); 1005 eap_aka_determine_identity(sm, data, 0, 1); 1006 return; 1007 } 1008 1009 if (sm->eap_sim_aka_result_ind && attr->result_ind) { 1010 data->use_result_ind = 1; 1011 data->notification = EAP_SIM_SUCCESS; 1012 eap_aka_state(data, NOTIFICATION); 1013 } else 1014 eap_aka_state(data, SUCCESS); 1015 1016 if (data->reauth) { 1017 identity = data->reauth->identity; 1018 identity_len = data->reauth->identity_len; 1019 } else { 1020 identity = sm->identity; 1021 identity_len = sm->identity_len; 1022 } 1023 1024 id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, 1025 identity_len, &id2_len); 1026 if (id2) { 1027 identity = id2; 1028 identity_len = id2_len; 1029 } 1030 1031 if (data->next_reauth_id) { 1032 if (data->eap_method == EAP_TYPE_AKA_PRIME) { 1033 #ifdef EAP_SERVER_AKA_PRIME 1034 eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 1035 identity, 1036 identity_len, 1037 data->next_reauth_id, 1038 data->counter + 1, 1039 data->k_encr, data->k_aut, 1040 data->k_re); 1041 #endif /* EAP_SERVER_AKA_PRIME */ 1042 } else { 1043 eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 1044 identity_len, 1045 data->next_reauth_id, 1046 data->counter + 1, 1047 data->mk); 1048 } 1049 data->next_reauth_id = NULL; 1050 } else { 1051 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1052 data->reauth = NULL; 1053 } 1054 1055 return; 1056 1057 fail: 1058 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1059 eap_aka_state(data, NOTIFICATION); 1060 eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1061 data->reauth = NULL; 1062 os_free(decrypted); 1063 } 1064 1065 1066 static void eap_aka_process_client_error(struct eap_sm *sm, 1067 struct eap_aka_data *data, 1068 struct wpabuf *respData, 1069 struct eap_sim_attrs *attr) 1070 { 1071 wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", 1072 attr->client_error_code); 1073 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1074 eap_aka_state(data, SUCCESS); 1075 else 1076 eap_aka_state(data, FAILURE); 1077 } 1078 1079 1080 static void eap_aka_process_authentication_reject( 1081 struct eap_sm *sm, struct eap_aka_data *data, 1082 struct wpabuf *respData, struct eap_sim_attrs *attr) 1083 { 1084 wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); 1085 eap_aka_state(data, FAILURE); 1086 } 1087 1088 1089 static void eap_aka_process_notification(struct eap_sm *sm, 1090 struct eap_aka_data *data, 1091 struct wpabuf *respData, 1092 struct eap_sim_attrs *attr) 1093 { 1094 wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); 1095 if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1096 eap_aka_state(data, SUCCESS); 1097 else 1098 eap_aka_state(data, FAILURE); 1099 } 1100 1101 1102 static void eap_aka_process(struct eap_sm *sm, void *priv, 1103 struct wpabuf *respData) 1104 { 1105 struct eap_aka_data *data = priv; 1106 const u8 *pos, *end; 1107 u8 subtype; 1108 size_t len; 1109 struct eap_sim_attrs attr; 1110 1111 pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 1112 &len); 1113 if (pos == NULL || len < 3) 1114 return; 1115 1116 end = pos + len; 1117 subtype = *pos; 1118 pos += 3; 1119 1120 if (eap_aka_subtype_ok(data, subtype)) { 1121 wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " 1122 "EAP-AKA Subtype in EAP Response"); 1123 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1124 eap_aka_state(data, NOTIFICATION); 1125 return; 1126 } 1127 1128 if (eap_sim_parse_attr(pos, end, &attr, 1129 data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, 1130 0)) { 1131 wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); 1132 data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1133 eap_aka_state(data, NOTIFICATION); 1134 return; 1135 } 1136 1137 if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { 1138 eap_aka_process_client_error(sm, data, respData, &attr); 1139 return; 1140 } 1141 1142 if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { 1143 eap_aka_process_authentication_reject(sm, data, respData, 1144 &attr); 1145 return; 1146 } 1147 1148 switch (data->state) { 1149 case IDENTITY: 1150 eap_aka_process_identity(sm, data, respData, &attr); 1151 break; 1152 case CHALLENGE: 1153 if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 1154 eap_aka_process_sync_failure(sm, data, respData, 1155 &attr); 1156 } else { 1157 eap_aka_process_challenge(sm, data, respData, &attr); 1158 } 1159 break; 1160 case REAUTH: 1161 eap_aka_process_reauth(sm, data, respData, &attr); 1162 break; 1163 case NOTIFICATION: 1164 eap_aka_process_notification(sm, data, respData, &attr); 1165 break; 1166 default: 1167 wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 1168 "process", data->state); 1169 break; 1170 } 1171 } 1172 1173 1174 static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) 1175 { 1176 struct eap_aka_data *data = priv; 1177 return data->state == SUCCESS || data->state == FAILURE; 1178 } 1179 1180 1181 static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) 1182 { 1183 struct eap_aka_data *data = priv; 1184 u8 *key; 1185 1186 if (data->state != SUCCESS) 1187 return NULL; 1188 1189 key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 1190 if (key == NULL) 1191 return NULL; 1192 os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 1193 *len = EAP_SIM_KEYING_DATA_LEN; 1194 return key; 1195 } 1196 1197 1198 static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1199 { 1200 struct eap_aka_data *data = priv; 1201 u8 *key; 1202 1203 if (data->state != SUCCESS) 1204 return NULL; 1205 1206 key = os_malloc(EAP_EMSK_LEN); 1207 if (key == NULL) 1208 return NULL; 1209 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1210 *len = EAP_EMSK_LEN; 1211 return key; 1212 } 1213 1214 1215 static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) 1216 { 1217 struct eap_aka_data *data = priv; 1218 return data->state == SUCCESS; 1219 } 1220 1221 1222 int eap_server_aka_register(void) 1223 { 1224 struct eap_method *eap; 1225 int ret; 1226 1227 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1228 EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); 1229 if (eap == NULL) 1230 return -1; 1231 1232 eap->init = eap_aka_init; 1233 eap->reset = eap_aka_reset; 1234 eap->buildReq = eap_aka_buildReq; 1235 eap->check = eap_aka_check; 1236 eap->process = eap_aka_process; 1237 eap->isDone = eap_aka_isDone; 1238 eap->getKey = eap_aka_getKey; 1239 eap->isSuccess = eap_aka_isSuccess; 1240 eap->get_emsk = eap_aka_get_emsk; 1241 1242 ret = eap_server_method_register(eap); 1243 if (ret) 1244 eap_server_method_free(eap); 1245 return ret; 1246 } 1247 1248 1249 #ifdef EAP_SERVER_AKA_PRIME 1250 int eap_server_aka_prime_register(void) 1251 { 1252 struct eap_method *eap; 1253 int ret; 1254 1255 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1256 EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, 1257 "AKA'"); 1258 if (eap == NULL) 1259 return -1; 1260 1261 eap->init = eap_aka_prime_init; 1262 eap->reset = eap_aka_reset; 1263 eap->buildReq = eap_aka_buildReq; 1264 eap->check = eap_aka_check; 1265 eap->process = eap_aka_process; 1266 eap->isDone = eap_aka_isDone; 1267 eap->getKey = eap_aka_getKey; 1268 eap->isSuccess = eap_aka_isSuccess; 1269 eap->get_emsk = eap_aka_get_emsk; 1270 1271 ret = eap_server_method_register(eap); 1272 if (ret) 1273 eap_server_method_free(eap); 1274 1275 return ret; 1276 } 1277 #endif /* EAP_SERVER_AKA_PRIME */ 1278