1214501Srpaulo/* 2252726Srpaulo * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) 3252726Srpaulo * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "crypto/sha256.h" 13214501Srpaulo#include "crypto/crypto.h" 14252726Srpaulo#include "crypto/random.h" 15214501Srpaulo#include "eap_common/eap_sim_common.h" 16214501Srpaulo#include "eap_server/eap_i.h" 17214501Srpaulo#include "eap_server/eap_sim_db.h" 18214501Srpaulo 19214501Srpaulo 20214501Srpaulostruct eap_aka_data { 21214501Srpaulo u8 mk[EAP_SIM_MK_LEN]; 22214501Srpaulo u8 nonce_s[EAP_SIM_NONCE_S_LEN]; 23214501Srpaulo u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; 24214501Srpaulo u8 k_encr[EAP_SIM_K_ENCR_LEN]; 25214501Srpaulo u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ 26214501Srpaulo u8 msk[EAP_SIM_KEYING_DATA_LEN]; 27214501Srpaulo u8 emsk[EAP_EMSK_LEN]; 28214501Srpaulo u8 rand[EAP_AKA_RAND_LEN]; 29214501Srpaulo u8 autn[EAP_AKA_AUTN_LEN]; 30214501Srpaulo u8 ck[EAP_AKA_CK_LEN]; 31214501Srpaulo u8 ik[EAP_AKA_IK_LEN]; 32214501Srpaulo u8 res[EAP_AKA_RES_MAX_LEN]; 33214501Srpaulo size_t res_len; 34214501Srpaulo enum { 35214501Srpaulo IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE 36214501Srpaulo } state; 37214501Srpaulo char *next_pseudonym; 38214501Srpaulo char *next_reauth_id; 39214501Srpaulo u16 counter; 40214501Srpaulo struct eap_sim_reauth *reauth; 41214501Srpaulo int auts_reported; /* whether the current AUTS has been reported to the 42214501Srpaulo * eap_sim_db */ 43214501Srpaulo u16 notification; 44214501Srpaulo int use_result_ind; 45214501Srpaulo 46214501Srpaulo struct wpabuf *id_msgs; 47214501Srpaulo int pending_id; 48214501Srpaulo u8 eap_method; 49214501Srpaulo u8 *network_name; 50214501Srpaulo size_t network_name_len; 51214501Srpaulo u16 kdf; 52252726Srpaulo int identity_round; 53252726Srpaulo char permanent[20]; /* Permanent username */ 54214501Srpaulo}; 55214501Srpaulo 56214501Srpaulo 57252726Srpaulostatic void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data); 58214501Srpaulo 59214501Srpaulo 60214501Srpaulostatic const char * eap_aka_state_txt(int state) 61214501Srpaulo{ 62214501Srpaulo switch (state) { 63214501Srpaulo case IDENTITY: 64214501Srpaulo return "IDENTITY"; 65214501Srpaulo case CHALLENGE: 66214501Srpaulo return "CHALLENGE"; 67214501Srpaulo case REAUTH: 68214501Srpaulo return "REAUTH"; 69214501Srpaulo case SUCCESS: 70214501Srpaulo return "SUCCESS"; 71214501Srpaulo case FAILURE: 72214501Srpaulo return "FAILURE"; 73214501Srpaulo case NOTIFICATION: 74214501Srpaulo return "NOTIFICATION"; 75214501Srpaulo default: 76214501Srpaulo return "Unknown?!"; 77214501Srpaulo } 78214501Srpaulo} 79214501Srpaulo 80214501Srpaulo 81214501Srpaulostatic void eap_aka_state(struct eap_aka_data *data, int state) 82214501Srpaulo{ 83214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", 84214501Srpaulo eap_aka_state_txt(data->state), 85214501Srpaulo eap_aka_state_txt(state)); 86214501Srpaulo data->state = state; 87214501Srpaulo} 88214501Srpaulo 89214501Srpaulo 90252726Srpaulostatic int eap_aka_check_identity_reauth(struct eap_sm *sm, 91252726Srpaulo struct eap_aka_data *data, 92252726Srpaulo const char *username) 93252726Srpaulo{ 94252726Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME && 95252726Srpaulo username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX) 96252726Srpaulo return 0; 97252726Srpaulo if (data->eap_method == EAP_TYPE_AKA && 98252726Srpaulo username[0] != EAP_AKA_REAUTH_ID_PREFIX) 99252726Srpaulo return 0; 100252726Srpaulo 101252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username); 102252726Srpaulo data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv, 103252726Srpaulo username); 104252726Srpaulo if (data->reauth == NULL) { 105252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - " 106252726Srpaulo "request full auth identity"); 107252726Srpaulo /* Remain in IDENTITY state for another round */ 108252726Srpaulo return 0; 109252726Srpaulo } 110252726Srpaulo 111252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication"); 112252726Srpaulo os_strlcpy(data->permanent, data->reauth->permanent, 113252726Srpaulo sizeof(data->permanent)); 114252726Srpaulo data->counter = data->reauth->counter; 115252726Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 116252726Srpaulo os_memcpy(data->k_encr, data->reauth->k_encr, 117252726Srpaulo EAP_SIM_K_ENCR_LEN); 118252726Srpaulo os_memcpy(data->k_aut, data->reauth->k_aut, 119252726Srpaulo EAP_AKA_PRIME_K_AUT_LEN); 120252726Srpaulo os_memcpy(data->k_re, data->reauth->k_re, 121252726Srpaulo EAP_AKA_PRIME_K_RE_LEN); 122252726Srpaulo } else { 123252726Srpaulo os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); 124252726Srpaulo } 125252726Srpaulo 126252726Srpaulo eap_aka_state(data, REAUTH); 127252726Srpaulo return 1; 128252726Srpaulo} 129252726Srpaulo 130252726Srpaulo 131252726Srpaulostatic void eap_aka_check_identity(struct eap_sm *sm, 132252726Srpaulo struct eap_aka_data *data) 133252726Srpaulo{ 134252726Srpaulo char *username; 135252726Srpaulo 136252726Srpaulo /* Check if we already know the identity from EAP-Response/Identity */ 137252726Srpaulo 138252726Srpaulo username = sim_get_username(sm->identity, sm->identity_len); 139252726Srpaulo if (username == NULL) 140252726Srpaulo return; 141252726Srpaulo 142252726Srpaulo if (eap_aka_check_identity_reauth(sm, data, username) > 0) { 143252726Srpaulo os_free(username); 144252726Srpaulo /* 145252726Srpaulo * Since re-auth username was recognized, skip AKA/Identity 146252726Srpaulo * exchange. 147252726Srpaulo */ 148252726Srpaulo return; 149252726Srpaulo } 150252726Srpaulo 151252726Srpaulo if ((data->eap_method == EAP_TYPE_AKA_PRIME && 152252726Srpaulo username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || 153252726Srpaulo (data->eap_method == EAP_TYPE_AKA && 154252726Srpaulo username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { 155252726Srpaulo const char *permanent; 156252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", 157252726Srpaulo username); 158252726Srpaulo permanent = eap_sim_db_get_permanent( 159252726Srpaulo sm->eap_sim_db_priv, username); 160252726Srpaulo if (permanent == NULL) { 161252726Srpaulo os_free(username); 162252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " 163252726Srpaulo "identity - request permanent identity"); 164252726Srpaulo /* Remain in IDENTITY state for another round */ 165252726Srpaulo return; 166252726Srpaulo } 167252726Srpaulo os_strlcpy(data->permanent, permanent, 168252726Srpaulo sizeof(data->permanent)); 169252726Srpaulo /* 170252726Srpaulo * Since pseudonym username was recognized, skip AKA/Identity 171252726Srpaulo * exchange. 172252726Srpaulo */ 173252726Srpaulo eap_aka_fullauth(sm, data); 174252726Srpaulo } 175252726Srpaulo 176252726Srpaulo os_free(username); 177252726Srpaulo} 178252726Srpaulo 179252726Srpaulo 180214501Srpaulostatic void * eap_aka_init(struct eap_sm *sm) 181214501Srpaulo{ 182214501Srpaulo struct eap_aka_data *data; 183214501Srpaulo 184214501Srpaulo if (sm->eap_sim_db_priv == NULL) { 185214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 186214501Srpaulo return NULL; 187214501Srpaulo } 188214501Srpaulo 189214501Srpaulo data = os_zalloc(sizeof(*data)); 190214501Srpaulo if (data == NULL) 191214501Srpaulo return NULL; 192214501Srpaulo 193214501Srpaulo data->eap_method = EAP_TYPE_AKA; 194214501Srpaulo 195214501Srpaulo data->state = IDENTITY; 196214501Srpaulo data->pending_id = -1; 197252726Srpaulo eap_aka_check_identity(sm, data); 198214501Srpaulo 199214501Srpaulo return data; 200214501Srpaulo} 201214501Srpaulo 202214501Srpaulo 203214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 204214501Srpaulostatic void * eap_aka_prime_init(struct eap_sm *sm) 205214501Srpaulo{ 206214501Srpaulo struct eap_aka_data *data; 207214501Srpaulo /* TODO: make ANID configurable; see 3GPP TS 24.302 */ 208214501Srpaulo char *network_name = "WLAN"; 209214501Srpaulo 210214501Srpaulo if (sm->eap_sim_db_priv == NULL) { 211214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); 212214501Srpaulo return NULL; 213214501Srpaulo } 214214501Srpaulo 215214501Srpaulo data = os_zalloc(sizeof(*data)); 216214501Srpaulo if (data == NULL) 217214501Srpaulo return NULL; 218214501Srpaulo 219214501Srpaulo data->eap_method = EAP_TYPE_AKA_PRIME; 220252726Srpaulo data->network_name = (u8 *) os_strdup(network_name); 221214501Srpaulo if (data->network_name == NULL) { 222214501Srpaulo os_free(data); 223214501Srpaulo return NULL; 224214501Srpaulo } 225214501Srpaulo 226214501Srpaulo data->network_name_len = os_strlen(network_name); 227214501Srpaulo 228214501Srpaulo data->state = IDENTITY; 229214501Srpaulo data->pending_id = -1; 230252726Srpaulo eap_aka_check_identity(sm, data); 231214501Srpaulo 232214501Srpaulo return data; 233214501Srpaulo} 234214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 235214501Srpaulo 236214501Srpaulo 237214501Srpaulostatic void eap_aka_reset(struct eap_sm *sm, void *priv) 238214501Srpaulo{ 239214501Srpaulo struct eap_aka_data *data = priv; 240214501Srpaulo os_free(data->next_pseudonym); 241214501Srpaulo os_free(data->next_reauth_id); 242214501Srpaulo wpabuf_free(data->id_msgs); 243214501Srpaulo os_free(data->network_name); 244214501Srpaulo os_free(data); 245214501Srpaulo} 246214501Srpaulo 247214501Srpaulo 248214501Srpaulostatic int eap_aka_add_id_msg(struct eap_aka_data *data, 249214501Srpaulo const struct wpabuf *msg) 250214501Srpaulo{ 251214501Srpaulo if (msg == NULL) 252214501Srpaulo return -1; 253214501Srpaulo 254214501Srpaulo if (data->id_msgs == NULL) { 255214501Srpaulo data->id_msgs = wpabuf_dup(msg); 256214501Srpaulo return data->id_msgs == NULL ? -1 : 0; 257214501Srpaulo } 258214501Srpaulo 259214501Srpaulo if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) 260214501Srpaulo return -1; 261214501Srpaulo wpabuf_put_buf(data->id_msgs, msg); 262214501Srpaulo 263214501Srpaulo return 0; 264214501Srpaulo} 265214501Srpaulo 266214501Srpaulo 267214501Srpaulostatic void eap_aka_add_checkcode(struct eap_aka_data *data, 268214501Srpaulo struct eap_sim_msg *msg) 269214501Srpaulo{ 270214501Srpaulo const u8 *addr; 271214501Srpaulo size_t len; 272214501Srpaulo u8 hash[SHA256_MAC_LEN]; 273214501Srpaulo 274214501Srpaulo wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); 275214501Srpaulo 276214501Srpaulo if (data->id_msgs == NULL) { 277214501Srpaulo /* 278214501Srpaulo * No EAP-AKA/Identity packets were exchanged - send empty 279214501Srpaulo * checkcode. 280214501Srpaulo */ 281214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); 282214501Srpaulo return; 283214501Srpaulo } 284214501Srpaulo 285214501Srpaulo /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 286214501Srpaulo addr = wpabuf_head(data->id_msgs); 287214501Srpaulo len = wpabuf_len(data->id_msgs); 288214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); 289214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) 290214501Srpaulo sha256_vector(1, &addr, &len, hash); 291214501Srpaulo else 292214501Srpaulo sha1_vector(1, &addr, &len, hash); 293214501Srpaulo 294214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, 295214501Srpaulo data->eap_method == EAP_TYPE_AKA_PRIME ? 296214501Srpaulo EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); 297214501Srpaulo} 298214501Srpaulo 299214501Srpaulo 300214501Srpaulostatic int eap_aka_verify_checkcode(struct eap_aka_data *data, 301214501Srpaulo const u8 *checkcode, size_t checkcode_len) 302214501Srpaulo{ 303214501Srpaulo const u8 *addr; 304214501Srpaulo size_t len; 305214501Srpaulo u8 hash[SHA256_MAC_LEN]; 306214501Srpaulo size_t hash_len; 307214501Srpaulo 308214501Srpaulo if (checkcode == NULL) 309214501Srpaulo return -1; 310214501Srpaulo 311214501Srpaulo if (data->id_msgs == NULL) { 312214501Srpaulo if (checkcode_len != 0) { 313214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " 314214501Srpaulo "indicates that AKA/Identity messages were " 315214501Srpaulo "used, but they were not"); 316214501Srpaulo return -1; 317214501Srpaulo } 318214501Srpaulo return 0; 319214501Srpaulo } 320214501Srpaulo 321214501Srpaulo hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? 322214501Srpaulo EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; 323214501Srpaulo 324214501Srpaulo if (checkcode_len != hash_len) { 325214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates " 326214501Srpaulo "that AKA/Identity message were not used, but they " 327214501Srpaulo "were"); 328214501Srpaulo return -1; 329214501Srpaulo } 330214501Srpaulo 331214501Srpaulo /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ 332214501Srpaulo addr = wpabuf_head(data->id_msgs); 333214501Srpaulo len = wpabuf_len(data->id_msgs); 334214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) 335214501Srpaulo sha256_vector(1, &addr, &len, hash); 336214501Srpaulo else 337214501Srpaulo sha1_vector(1, &addr, &len, hash); 338214501Srpaulo 339214501Srpaulo if (os_memcmp(hash, checkcode, hash_len) != 0) { 340214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); 341214501Srpaulo return -1; 342214501Srpaulo } 343214501Srpaulo 344214501Srpaulo return 0; 345214501Srpaulo} 346214501Srpaulo 347214501Srpaulo 348214501Srpaulostatic struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, 349214501Srpaulo struct eap_aka_data *data, u8 id) 350214501Srpaulo{ 351214501Srpaulo struct eap_sim_msg *msg; 352214501Srpaulo struct wpabuf *buf; 353214501Srpaulo 354214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); 355214501Srpaulo msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 356214501Srpaulo EAP_AKA_SUBTYPE_IDENTITY); 357252726Srpaulo data->identity_round++; 358252726Srpaulo if (data->identity_round == 1) { 359214501Srpaulo /* 360214501Srpaulo * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is 361214501Srpaulo * ignored and the AKA/Identity is used to request the 362214501Srpaulo * identity. 363214501Srpaulo */ 364214501Srpaulo wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); 365214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); 366252726Srpaulo } else if (data->identity_round > 3) { 367252726Srpaulo /* Cannot use more than three rounds of Identity messages */ 368252726Srpaulo eap_sim_msg_free(msg); 369252726Srpaulo return NULL; 370252726Srpaulo } else if (sm->identity && sm->identity_len > 0 && 371252726Srpaulo (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX || 372252726Srpaulo sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) { 373252726Srpaulo /* Reauth id may have expired - try fullauth */ 374252726Srpaulo wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ"); 375252726Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0); 376252726Srpaulo } else { 377252726Srpaulo wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); 378252726Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); 379214501Srpaulo } 380214501Srpaulo buf = eap_sim_msg_finish(msg, NULL, NULL, 0); 381214501Srpaulo if (eap_aka_add_id_msg(data, buf) < 0) { 382214501Srpaulo wpabuf_free(buf); 383214501Srpaulo return NULL; 384214501Srpaulo } 385214501Srpaulo data->pending_id = id; 386214501Srpaulo return buf; 387214501Srpaulo} 388214501Srpaulo 389214501Srpaulo 390214501Srpaulostatic int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, 391214501Srpaulo struct eap_sim_msg *msg, u16 counter, 392214501Srpaulo const u8 *nonce_s) 393214501Srpaulo{ 394214501Srpaulo os_free(data->next_pseudonym); 395252726Srpaulo if (nonce_s == NULL) { 396252726Srpaulo data->next_pseudonym = 397252726Srpaulo eap_sim_db_get_next_pseudonym( 398252726Srpaulo sm->eap_sim_db_priv, 399252726Srpaulo data->eap_method == EAP_TYPE_AKA_PRIME ? 400252726Srpaulo EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); 401252726Srpaulo } else { 402252726Srpaulo /* Do not update pseudonym during re-authentication */ 403252726Srpaulo data->next_pseudonym = NULL; 404252726Srpaulo } 405214501Srpaulo os_free(data->next_reauth_id); 406214501Srpaulo if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { 407214501Srpaulo data->next_reauth_id = 408252726Srpaulo eap_sim_db_get_next_reauth_id( 409252726Srpaulo sm->eap_sim_db_priv, 410252726Srpaulo data->eap_method == EAP_TYPE_AKA_PRIME ? 411252726Srpaulo EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); 412214501Srpaulo } else { 413214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " 414214501Srpaulo "count exceeded - force full authentication"); 415214501Srpaulo data->next_reauth_id = NULL; 416214501Srpaulo } 417214501Srpaulo 418214501Srpaulo if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 419214501Srpaulo counter == 0 && nonce_s == NULL) 420214501Srpaulo return 0; 421214501Srpaulo 422214501Srpaulo wpa_printf(MSG_DEBUG, " AT_IV"); 423214501Srpaulo wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 424214501Srpaulo eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 425214501Srpaulo 426214501Srpaulo if (counter > 0) { 427214501Srpaulo wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 428214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 429214501Srpaulo } 430214501Srpaulo 431214501Srpaulo if (nonce_s) { 432214501Srpaulo wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 433214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 434214501Srpaulo EAP_SIM_NONCE_S_LEN); 435214501Srpaulo } 436214501Srpaulo 437214501Srpaulo if (data->next_pseudonym) { 438214501Srpaulo wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 439214501Srpaulo data->next_pseudonym); 440214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 441214501Srpaulo os_strlen(data->next_pseudonym), 442214501Srpaulo (u8 *) data->next_pseudonym, 443214501Srpaulo os_strlen(data->next_pseudonym)); 444214501Srpaulo } 445214501Srpaulo 446214501Srpaulo if (data->next_reauth_id) { 447214501Srpaulo wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 448214501Srpaulo data->next_reauth_id); 449214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 450214501Srpaulo os_strlen(data->next_reauth_id), 451214501Srpaulo (u8 *) data->next_reauth_id, 452214501Srpaulo os_strlen(data->next_reauth_id)); 453214501Srpaulo } 454214501Srpaulo 455214501Srpaulo if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 456214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " 457214501Srpaulo "AT_ENCR_DATA"); 458214501Srpaulo return -1; 459214501Srpaulo } 460214501Srpaulo 461214501Srpaulo return 0; 462214501Srpaulo} 463214501Srpaulo 464214501Srpaulo 465214501Srpaulostatic struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, 466214501Srpaulo struct eap_aka_data *data, 467214501Srpaulo u8 id) 468214501Srpaulo{ 469214501Srpaulo struct eap_sim_msg *msg; 470214501Srpaulo 471214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); 472214501Srpaulo msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 473214501Srpaulo EAP_AKA_SUBTYPE_CHALLENGE); 474214501Srpaulo wpa_printf(MSG_DEBUG, " AT_RAND"); 475214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); 476214501Srpaulo wpa_printf(MSG_DEBUG, " AT_AUTN"); 477214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); 478214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 479214501Srpaulo if (data->kdf) { 480214501Srpaulo /* Add the selected KDF into the beginning */ 481214501Srpaulo wpa_printf(MSG_DEBUG, " AT_KDF"); 482214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, 483214501Srpaulo NULL, 0); 484214501Srpaulo } 485214501Srpaulo wpa_printf(MSG_DEBUG, " AT_KDF"); 486214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, 487214501Srpaulo NULL, 0); 488214501Srpaulo wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); 489214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, 490214501Srpaulo data->network_name_len, 491214501Srpaulo data->network_name, data->network_name_len); 492214501Srpaulo } 493214501Srpaulo 494214501Srpaulo if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { 495214501Srpaulo eap_sim_msg_free(msg); 496214501Srpaulo return NULL; 497214501Srpaulo } 498214501Srpaulo 499214501Srpaulo eap_aka_add_checkcode(data, msg); 500214501Srpaulo 501214501Srpaulo if (sm->eap_sim_aka_result_ind) { 502214501Srpaulo wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 503214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 504214501Srpaulo } 505214501Srpaulo 506214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 507214501Srpaulo if (data->eap_method == EAP_TYPE_AKA) { 508214501Srpaulo u16 flags = 0; 509214501Srpaulo int i; 510214501Srpaulo int aka_prime_preferred = 0; 511214501Srpaulo 512214501Srpaulo i = 0; 513214501Srpaulo while (sm->user && i < EAP_MAX_METHODS && 514214501Srpaulo (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 515214501Srpaulo sm->user->methods[i].method != EAP_TYPE_NONE)) { 516214501Srpaulo if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { 517214501Srpaulo if (sm->user->methods[i].method == 518214501Srpaulo EAP_TYPE_AKA) 519214501Srpaulo break; 520214501Srpaulo if (sm->user->methods[i].method == 521214501Srpaulo EAP_TYPE_AKA_PRIME) { 522214501Srpaulo aka_prime_preferred = 1; 523214501Srpaulo break; 524214501Srpaulo } 525214501Srpaulo } 526214501Srpaulo i++; 527214501Srpaulo } 528214501Srpaulo 529214501Srpaulo if (aka_prime_preferred) 530214501Srpaulo flags |= EAP_AKA_BIDDING_FLAG_D; 531214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); 532214501Srpaulo } 533214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 534214501Srpaulo 535214501Srpaulo wpa_printf(MSG_DEBUG, " AT_MAC"); 536214501Srpaulo eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 537214501Srpaulo return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 538214501Srpaulo} 539214501Srpaulo 540214501Srpaulo 541214501Srpaulostatic struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, 542214501Srpaulo struct eap_aka_data *data, u8 id) 543214501Srpaulo{ 544214501Srpaulo struct eap_sim_msg *msg; 545214501Srpaulo 546214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); 547214501Srpaulo 548252726Srpaulo if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 549214501Srpaulo return NULL; 550214501Srpaulo wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", 551214501Srpaulo data->nonce_s, EAP_SIM_NONCE_S_LEN); 552214501Srpaulo 553214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 554214501Srpaulo eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, 555214501Srpaulo sm->identity, 556214501Srpaulo sm->identity_len, 557214501Srpaulo data->nonce_s, 558214501Srpaulo data->msk, data->emsk); 559214501Srpaulo } else { 560214501Srpaulo eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 561214501Srpaulo data->msk, data->emsk); 562214501Srpaulo eap_sim_derive_keys_reauth(data->counter, sm->identity, 563214501Srpaulo sm->identity_len, data->nonce_s, 564214501Srpaulo data->mk, data->msk, data->emsk); 565214501Srpaulo } 566214501Srpaulo 567214501Srpaulo msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 568214501Srpaulo EAP_AKA_SUBTYPE_REAUTHENTICATION); 569214501Srpaulo 570214501Srpaulo if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 571214501Srpaulo eap_sim_msg_free(msg); 572214501Srpaulo return NULL; 573214501Srpaulo } 574214501Srpaulo 575214501Srpaulo eap_aka_add_checkcode(data, msg); 576214501Srpaulo 577214501Srpaulo if (sm->eap_sim_aka_result_ind) { 578214501Srpaulo wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 579214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 580214501Srpaulo } 581214501Srpaulo 582214501Srpaulo wpa_printf(MSG_DEBUG, " AT_MAC"); 583214501Srpaulo eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 584214501Srpaulo return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 585214501Srpaulo} 586214501Srpaulo 587214501Srpaulo 588214501Srpaulostatic struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, 589214501Srpaulo struct eap_aka_data *data, 590214501Srpaulo u8 id) 591214501Srpaulo{ 592214501Srpaulo struct eap_sim_msg *msg; 593214501Srpaulo 594214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); 595214501Srpaulo msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, 596214501Srpaulo EAP_AKA_SUBTYPE_NOTIFICATION); 597214501Srpaulo wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 598214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 599214501Srpaulo NULL, 0); 600214501Srpaulo if (data->use_result_ind) { 601214501Srpaulo if (data->reauth) { 602214501Srpaulo wpa_printf(MSG_DEBUG, " AT_IV"); 603214501Srpaulo wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 604214501Srpaulo eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 605214501Srpaulo EAP_SIM_AT_ENCR_DATA); 606214501Srpaulo wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 607214501Srpaulo data->counter); 608214501Srpaulo eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 609214501Srpaulo NULL, 0); 610214501Srpaulo 611214501Srpaulo if (eap_sim_msg_add_encr_end(msg, data->k_encr, 612214501Srpaulo EAP_SIM_AT_PADDING)) { 613214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " 614214501Srpaulo "encrypt AT_ENCR_DATA"); 615214501Srpaulo eap_sim_msg_free(msg); 616214501Srpaulo return NULL; 617214501Srpaulo } 618214501Srpaulo } 619214501Srpaulo 620214501Srpaulo wpa_printf(MSG_DEBUG, " AT_MAC"); 621214501Srpaulo eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 622214501Srpaulo } 623214501Srpaulo return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 624214501Srpaulo} 625214501Srpaulo 626214501Srpaulo 627214501Srpaulostatic struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) 628214501Srpaulo{ 629214501Srpaulo struct eap_aka_data *data = priv; 630214501Srpaulo 631214501Srpaulo data->auts_reported = 0; 632214501Srpaulo switch (data->state) { 633214501Srpaulo case IDENTITY: 634214501Srpaulo return eap_aka_build_identity(sm, data, id); 635214501Srpaulo case CHALLENGE: 636214501Srpaulo return eap_aka_build_challenge(sm, data, id); 637214501Srpaulo case REAUTH: 638214501Srpaulo return eap_aka_build_reauth(sm, data, id); 639214501Srpaulo case NOTIFICATION: 640214501Srpaulo return eap_aka_build_notification(sm, data, id); 641214501Srpaulo default: 642214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 643214501Srpaulo "buildReq", data->state); 644214501Srpaulo break; 645214501Srpaulo } 646214501Srpaulo return NULL; 647214501Srpaulo} 648214501Srpaulo 649214501Srpaulo 650214501Srpaulostatic Boolean eap_aka_check(struct eap_sm *sm, void *priv, 651214501Srpaulo struct wpabuf *respData) 652214501Srpaulo{ 653214501Srpaulo struct eap_aka_data *data = priv; 654214501Srpaulo const u8 *pos; 655214501Srpaulo size_t len; 656214501Srpaulo 657214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 658214501Srpaulo &len); 659214501Srpaulo if (pos == NULL || len < 3) { 660214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); 661214501Srpaulo return TRUE; 662214501Srpaulo } 663214501Srpaulo 664214501Srpaulo return FALSE; 665214501Srpaulo} 666214501Srpaulo 667214501Srpaulo 668214501Srpaulostatic Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) 669214501Srpaulo{ 670214501Srpaulo if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || 671214501Srpaulo subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) 672214501Srpaulo return FALSE; 673214501Srpaulo 674214501Srpaulo switch (data->state) { 675214501Srpaulo case IDENTITY: 676214501Srpaulo if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { 677214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 678214501Srpaulo "subtype %d", subtype); 679214501Srpaulo return TRUE; 680214501Srpaulo } 681214501Srpaulo break; 682214501Srpaulo case CHALLENGE: 683214501Srpaulo if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && 684214501Srpaulo subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 685214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 686214501Srpaulo "subtype %d", subtype); 687214501Srpaulo return TRUE; 688214501Srpaulo } 689214501Srpaulo break; 690214501Srpaulo case REAUTH: 691214501Srpaulo if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { 692214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 693214501Srpaulo "subtype %d", subtype); 694214501Srpaulo return TRUE; 695214501Srpaulo } 696214501Srpaulo break; 697214501Srpaulo case NOTIFICATION: 698214501Srpaulo if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { 699214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " 700214501Srpaulo "subtype %d", subtype); 701214501Srpaulo return TRUE; 702214501Srpaulo } 703214501Srpaulo break; 704214501Srpaulo default: 705214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " 706214501Srpaulo "processing a response", data->state); 707214501Srpaulo return TRUE; 708214501Srpaulo } 709214501Srpaulo 710214501Srpaulo return FALSE; 711214501Srpaulo} 712214501Srpaulo 713214501Srpaulo 714214501Srpaulostatic void eap_aka_determine_identity(struct eap_sm *sm, 715252726Srpaulo struct eap_aka_data *data) 716214501Srpaulo{ 717252726Srpaulo char *username; 718214501Srpaulo 719252726Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", 720252726Srpaulo sm->identity, sm->identity_len); 721214501Srpaulo 722252726Srpaulo username = sim_get_username(sm->identity, sm->identity_len); 723252726Srpaulo if (username == NULL) { 724252726Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 725252726Srpaulo eap_aka_state(data, NOTIFICATION); 726252726Srpaulo return; 727214501Srpaulo } 728214501Srpaulo 729252726Srpaulo if (eap_aka_check_identity_reauth(sm, data, username) > 0) { 730252726Srpaulo os_free(username); 731252726Srpaulo return; 732214501Srpaulo } 733214501Srpaulo 734252726Srpaulo if (((data->eap_method == EAP_TYPE_AKA_PRIME && 735252726Srpaulo username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) || 736252726Srpaulo (data->eap_method == EAP_TYPE_AKA && 737252726Srpaulo username[0] == EAP_AKA_REAUTH_ID_PREFIX)) && 738252726Srpaulo data->identity_round == 1) { 739252726Srpaulo /* Remain in IDENTITY state for another round to request full 740252726Srpaulo * auth identity since we did not recognize reauth id */ 741252726Srpaulo os_free(username); 742252726Srpaulo return; 743252726Srpaulo } 744214501Srpaulo 745252726Srpaulo if ((data->eap_method == EAP_TYPE_AKA_PRIME && 746252726Srpaulo username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || 747252726Srpaulo (data->eap_method == EAP_TYPE_AKA && 748252726Srpaulo username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { 749252726Srpaulo const char *permanent; 750252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", 751252726Srpaulo username); 752252726Srpaulo permanent = eap_sim_db_get_permanent( 753252726Srpaulo sm->eap_sim_db_priv, username); 754252726Srpaulo os_free(username); 755252726Srpaulo if (permanent == NULL) { 756252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " 757252726Srpaulo "identity - request permanent identity"); 758252726Srpaulo /* Remain in IDENTITY state for another round */ 759252726Srpaulo return; 760252726Srpaulo } 761252726Srpaulo os_strlcpy(data->permanent, permanent, 762252726Srpaulo sizeof(data->permanent)); 763252726Srpaulo } else if ((data->eap_method == EAP_TYPE_AKA_PRIME && 764252726Srpaulo username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) || 765252726Srpaulo (data->eap_method == EAP_TYPE_AKA && 766252726Srpaulo username[0] == EAP_AKA_PERMANENT_PREFIX)) { 767252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'", 768252726Srpaulo username); 769252726Srpaulo os_strlcpy(data->permanent, username, sizeof(data->permanent)); 770252726Srpaulo os_free(username); 771252726Srpaulo } else { 772252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", 773252726Srpaulo username); 774252726Srpaulo os_free(username); 775252726Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 776252726Srpaulo eap_aka_state(data, NOTIFICATION); 777214501Srpaulo return; 778214501Srpaulo } 779214501Srpaulo 780252726Srpaulo eap_aka_fullauth(sm, data); 781252726Srpaulo} 782252726Srpaulo 783252726Srpaulo 784252726Srpaulostatic void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data) 785252726Srpaulo{ 786252726Srpaulo size_t identity_len; 787252726Srpaulo int res; 788252726Srpaulo 789252726Srpaulo res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent, 790252726Srpaulo data->rand, data->autn, data->ik, 791252726Srpaulo data->ck, data->res, &data->res_len, sm); 792214501Srpaulo if (res == EAP_SIM_DB_PENDING) { 793214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 794214501Srpaulo "not yet available - pending request"); 795214501Srpaulo sm->method_pending = METHOD_PENDING_WAIT; 796214501Srpaulo return; 797214501Srpaulo } 798214501Srpaulo 799214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 800214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 801214501Srpaulo /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the 802214501Srpaulo * needed 6-octet SQN ^AK for CK',IK' derivation */ 803214501Srpaulo eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, 804214501Srpaulo data->autn, 805214501Srpaulo data->network_name, 806214501Srpaulo data->network_name_len); 807214501Srpaulo } 808214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 809214501Srpaulo 810214501Srpaulo data->reauth = NULL; 811214501Srpaulo data->counter = 0; /* reset re-auth counter since this is full auth */ 812214501Srpaulo 813214501Srpaulo if (res != 0) { 814214501Srpaulo wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " 815214501Srpaulo "authentication data for the peer"); 816214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 817214501Srpaulo eap_aka_state(data, NOTIFICATION); 818214501Srpaulo return; 819214501Srpaulo } 820214501Srpaulo if (sm->method_pending == METHOD_PENDING_WAIT) { 821214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " 822214501Srpaulo "available - abort pending wait"); 823214501Srpaulo sm->method_pending = METHOD_PENDING_NONE; 824214501Srpaulo } 825214501Srpaulo 826214501Srpaulo identity_len = sm->identity_len; 827214501Srpaulo while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 828214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " 829214501Srpaulo "character from identity"); 830214501Srpaulo identity_len--; 831214501Srpaulo } 832214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", 833214501Srpaulo sm->identity, identity_len); 834214501Srpaulo 835214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 836252726Srpaulo eap_aka_prime_derive_keys(sm->identity, identity_len, data->ik, 837214501Srpaulo data->ck, data->k_encr, data->k_aut, 838214501Srpaulo data->k_re, data->msk, data->emsk); 839214501Srpaulo } else { 840214501Srpaulo eap_aka_derive_mk(sm->identity, identity_len, data->ik, 841214501Srpaulo data->ck, data->mk); 842214501Srpaulo eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, 843214501Srpaulo data->msk, data->emsk); 844214501Srpaulo } 845214501Srpaulo 846214501Srpaulo eap_aka_state(data, CHALLENGE); 847214501Srpaulo} 848214501Srpaulo 849214501Srpaulo 850214501Srpaulostatic void eap_aka_process_identity(struct eap_sm *sm, 851214501Srpaulo struct eap_aka_data *data, 852214501Srpaulo struct wpabuf *respData, 853214501Srpaulo struct eap_sim_attrs *attr) 854214501Srpaulo{ 855252726Srpaulo u8 *new_identity; 856252726Srpaulo 857214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); 858214501Srpaulo 859214501Srpaulo if (attr->mac || attr->iv || attr->encr_data) { 860214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " 861214501Srpaulo "received in EAP-Response/AKA-Identity"); 862214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 863214501Srpaulo eap_aka_state(data, NOTIFICATION); 864214501Srpaulo return; 865214501Srpaulo } 866214501Srpaulo 867252726Srpaulo /* 868252726Srpaulo * We always request identity with AKA/Identity, so the peer is 869252726Srpaulo * required to have replied with one. 870252726Srpaulo */ 871252726Srpaulo if (!attr->identity || attr->identity_len == 0) { 872252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any " 873252726Srpaulo "identity"); 874252726Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 875252726Srpaulo eap_aka_state(data, NOTIFICATION); 876252726Srpaulo return; 877214501Srpaulo } 878214501Srpaulo 879252726Srpaulo new_identity = os_malloc(attr->identity_len); 880252726Srpaulo if (new_identity == NULL) { 881252726Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 882252726Srpaulo eap_aka_state(data, NOTIFICATION); 883252726Srpaulo return; 884252726Srpaulo } 885252726Srpaulo os_free(sm->identity); 886252726Srpaulo sm->identity = new_identity; 887252726Srpaulo os_memcpy(sm->identity, attr->identity, attr->identity_len); 888252726Srpaulo sm->identity_len = attr->identity_len; 889252726Srpaulo 890252726Srpaulo eap_aka_determine_identity(sm, data); 891214501Srpaulo if (eap_get_id(respData) == data->pending_id) { 892214501Srpaulo data->pending_id = -1; 893214501Srpaulo eap_aka_add_id_msg(data, respData); 894214501Srpaulo } 895214501Srpaulo} 896214501Srpaulo 897214501Srpaulo 898214501Srpaulostatic int eap_aka_verify_mac(struct eap_aka_data *data, 899214501Srpaulo const struct wpabuf *req, 900214501Srpaulo const u8 *mac, const u8 *extra, 901214501Srpaulo size_t extra_len) 902214501Srpaulo{ 903214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) 904214501Srpaulo return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, 905214501Srpaulo extra_len); 906214501Srpaulo return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); 907214501Srpaulo} 908214501Srpaulo 909214501Srpaulo 910214501Srpaulostatic void eap_aka_process_challenge(struct eap_sm *sm, 911214501Srpaulo struct eap_aka_data *data, 912214501Srpaulo struct wpabuf *respData, 913214501Srpaulo struct eap_sim_attrs *attr) 914214501Srpaulo{ 915214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); 916214501Srpaulo 917214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 918214501Srpaulo#if 0 919214501Srpaulo /* KDF negotiation; to be enabled only after more than one KDF is 920214501Srpaulo * supported */ 921214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME && 922214501Srpaulo attr->kdf_count == 1 && attr->mac == NULL) { 923214501Srpaulo if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { 924214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " 925214501Srpaulo "unknown KDF"); 926214501Srpaulo data->notification = 927214501Srpaulo EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 928214501Srpaulo eap_aka_state(data, NOTIFICATION); 929214501Srpaulo return; 930214501Srpaulo } 931214501Srpaulo 932214501Srpaulo data->kdf = attr->kdf[0]; 933214501Srpaulo 934214501Srpaulo /* Allow negotiation to continue with the selected KDF by 935214501Srpaulo * sending another Challenge message */ 936214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); 937214501Srpaulo return; 938214501Srpaulo } 939214501Srpaulo#endif 940214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 941214501Srpaulo 942214501Srpaulo if (attr->checkcode && 943214501Srpaulo eap_aka_verify_checkcode(data, attr->checkcode, 944214501Srpaulo attr->checkcode_len)) { 945214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " 946214501Srpaulo "message"); 947214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 948214501Srpaulo eap_aka_state(data, NOTIFICATION); 949214501Srpaulo return; 950214501Srpaulo } 951214501Srpaulo if (attr->mac == NULL || 952214501Srpaulo eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { 953214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " 954214501Srpaulo "did not include valid AT_MAC"); 955214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 956214501Srpaulo eap_aka_state(data, NOTIFICATION); 957214501Srpaulo return; 958214501Srpaulo } 959214501Srpaulo 960214501Srpaulo /* 961214501Srpaulo * AT_RES is padded, so verify that there is enough room for RES and 962214501Srpaulo * that the RES length in bits matches with the expected RES. 963214501Srpaulo */ 964214501Srpaulo if (attr->res == NULL || attr->res_len < data->res_len || 965214501Srpaulo attr->res_len_bits != data->res_len * 8 || 966214501Srpaulo os_memcmp(attr->res, data->res, data->res_len) != 0) { 967214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " 968214501Srpaulo "include valid AT_RES (attr len=%lu, res len=%lu " 969214501Srpaulo "bits, expected %lu bits)", 970214501Srpaulo (unsigned long) attr->res_len, 971214501Srpaulo (unsigned long) attr->res_len_bits, 972214501Srpaulo (unsigned long) data->res_len * 8); 973214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 974214501Srpaulo eap_aka_state(data, NOTIFICATION); 975214501Srpaulo return; 976214501Srpaulo } 977214501Srpaulo 978214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " 979214501Srpaulo "correct AT_MAC"); 980214501Srpaulo if (sm->eap_sim_aka_result_ind && attr->result_ind) { 981214501Srpaulo data->use_result_ind = 1; 982214501Srpaulo data->notification = EAP_SIM_SUCCESS; 983214501Srpaulo eap_aka_state(data, NOTIFICATION); 984214501Srpaulo } else 985214501Srpaulo eap_aka_state(data, SUCCESS); 986214501Srpaulo 987214501Srpaulo if (data->next_pseudonym) { 988252726Srpaulo eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent, 989214501Srpaulo data->next_pseudonym); 990214501Srpaulo data->next_pseudonym = NULL; 991214501Srpaulo } 992214501Srpaulo if (data->next_reauth_id) { 993214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 994214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 995214501Srpaulo eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 996252726Srpaulo data->permanent, 997214501Srpaulo data->next_reauth_id, 998214501Srpaulo data->counter + 1, 999214501Srpaulo data->k_encr, data->k_aut, 1000214501Srpaulo data->k_re); 1001214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 1002214501Srpaulo } else { 1003252726Srpaulo eap_sim_db_add_reauth(sm->eap_sim_db_priv, 1004252726Srpaulo data->permanent, 1005214501Srpaulo data->next_reauth_id, 1006214501Srpaulo data->counter + 1, 1007214501Srpaulo data->mk); 1008214501Srpaulo } 1009214501Srpaulo data->next_reauth_id = NULL; 1010214501Srpaulo } 1011214501Srpaulo} 1012214501Srpaulo 1013214501Srpaulo 1014214501Srpaulostatic void eap_aka_process_sync_failure(struct eap_sm *sm, 1015214501Srpaulo struct eap_aka_data *data, 1016214501Srpaulo struct wpabuf *respData, 1017214501Srpaulo struct eap_sim_attrs *attr) 1018214501Srpaulo{ 1019214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); 1020214501Srpaulo 1021214501Srpaulo if (attr->auts == NULL) { 1022214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " 1023214501Srpaulo "message did not include valid AT_AUTS"); 1024214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1025214501Srpaulo eap_aka_state(data, NOTIFICATION); 1026214501Srpaulo return; 1027214501Srpaulo } 1028214501Srpaulo 1029214501Srpaulo /* Avoid re-reporting AUTS when processing pending EAP packet by 1030214501Srpaulo * maintaining a local flag stating whether this AUTS has already been 1031214501Srpaulo * reported. */ 1032214501Srpaulo if (!data->auts_reported && 1033252726Srpaulo eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent, 1034252726Srpaulo attr->auts, data->rand)) { 1035214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); 1036214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1037214501Srpaulo eap_aka_state(data, NOTIFICATION); 1038214501Srpaulo return; 1039214501Srpaulo } 1040214501Srpaulo data->auts_reported = 1; 1041214501Srpaulo 1042252726Srpaulo /* Remain in CHALLENGE state to re-try after resynchronization */ 1043214501Srpaulo} 1044214501Srpaulo 1045214501Srpaulo 1046214501Srpaulostatic void eap_aka_process_reauth(struct eap_sm *sm, 1047214501Srpaulo struct eap_aka_data *data, 1048214501Srpaulo struct wpabuf *respData, 1049214501Srpaulo struct eap_sim_attrs *attr) 1050214501Srpaulo{ 1051214501Srpaulo struct eap_sim_attrs eattr; 1052214501Srpaulo u8 *decrypted = NULL; 1053214501Srpaulo 1054214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); 1055214501Srpaulo 1056214501Srpaulo if (attr->mac == NULL || 1057214501Srpaulo eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, 1058214501Srpaulo EAP_SIM_NONCE_S_LEN)) { 1059214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 1060214501Srpaulo "did not include valid AT_MAC"); 1061214501Srpaulo goto fail; 1062214501Srpaulo } 1063214501Srpaulo 1064214501Srpaulo if (attr->encr_data == NULL || attr->iv == NULL) { 1065214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " 1066214501Srpaulo "message did not include encrypted data"); 1067214501Srpaulo goto fail; 1068214501Srpaulo } 1069214501Srpaulo 1070214501Srpaulo decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 1071214501Srpaulo attr->encr_data_len, attr->iv, &eattr, 1072214501Srpaulo 0); 1073214501Srpaulo if (decrypted == NULL) { 1074214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " 1075214501Srpaulo "data from reauthentication message"); 1076214501Srpaulo goto fail; 1077214501Srpaulo } 1078214501Srpaulo 1079214501Srpaulo if (eattr.counter != data->counter) { 1080214501Srpaulo wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " 1081214501Srpaulo "used incorrect counter %u, expected %u", 1082214501Srpaulo eattr.counter, data->counter); 1083214501Srpaulo goto fail; 1084214501Srpaulo } 1085214501Srpaulo os_free(decrypted); 1086214501Srpaulo decrypted = NULL; 1087214501Srpaulo 1088214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " 1089214501Srpaulo "the correct AT_MAC"); 1090214501Srpaulo 1091214501Srpaulo if (eattr.counter_too_small) { 1092214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " 1093214501Srpaulo "included AT_COUNTER_TOO_SMALL - starting full " 1094214501Srpaulo "authentication"); 1095252726Srpaulo eap_aka_fullauth(sm, data); 1096214501Srpaulo return; 1097214501Srpaulo } 1098214501Srpaulo 1099214501Srpaulo if (sm->eap_sim_aka_result_ind && attr->result_ind) { 1100214501Srpaulo data->use_result_ind = 1; 1101214501Srpaulo data->notification = EAP_SIM_SUCCESS; 1102214501Srpaulo eap_aka_state(data, NOTIFICATION); 1103214501Srpaulo } else 1104214501Srpaulo eap_aka_state(data, SUCCESS); 1105214501Srpaulo 1106214501Srpaulo if (data->next_reauth_id) { 1107214501Srpaulo if (data->eap_method == EAP_TYPE_AKA_PRIME) { 1108214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 1109214501Srpaulo eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, 1110252726Srpaulo data->permanent, 1111214501Srpaulo data->next_reauth_id, 1112214501Srpaulo data->counter + 1, 1113214501Srpaulo data->k_encr, data->k_aut, 1114214501Srpaulo data->k_re); 1115214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 1116214501Srpaulo } else { 1117252726Srpaulo eap_sim_db_add_reauth(sm->eap_sim_db_priv, 1118252726Srpaulo data->permanent, 1119214501Srpaulo data->next_reauth_id, 1120214501Srpaulo data->counter + 1, 1121214501Srpaulo data->mk); 1122214501Srpaulo } 1123214501Srpaulo data->next_reauth_id = NULL; 1124214501Srpaulo } else { 1125214501Srpaulo eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1126214501Srpaulo data->reauth = NULL; 1127214501Srpaulo } 1128214501Srpaulo 1129214501Srpaulo return; 1130214501Srpaulo 1131214501Srpaulofail: 1132214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1133214501Srpaulo eap_aka_state(data, NOTIFICATION); 1134214501Srpaulo eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 1135214501Srpaulo data->reauth = NULL; 1136214501Srpaulo os_free(decrypted); 1137214501Srpaulo} 1138214501Srpaulo 1139214501Srpaulo 1140214501Srpaulostatic void eap_aka_process_client_error(struct eap_sm *sm, 1141214501Srpaulo struct eap_aka_data *data, 1142214501Srpaulo struct wpabuf *respData, 1143214501Srpaulo struct eap_sim_attrs *attr) 1144214501Srpaulo{ 1145214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", 1146214501Srpaulo attr->client_error_code); 1147214501Srpaulo if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1148214501Srpaulo eap_aka_state(data, SUCCESS); 1149214501Srpaulo else 1150214501Srpaulo eap_aka_state(data, FAILURE); 1151214501Srpaulo} 1152214501Srpaulo 1153214501Srpaulo 1154214501Srpaulostatic void eap_aka_process_authentication_reject( 1155214501Srpaulo struct eap_sm *sm, struct eap_aka_data *data, 1156214501Srpaulo struct wpabuf *respData, struct eap_sim_attrs *attr) 1157214501Srpaulo{ 1158214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); 1159214501Srpaulo eap_aka_state(data, FAILURE); 1160214501Srpaulo} 1161214501Srpaulo 1162214501Srpaulo 1163214501Srpaulostatic void eap_aka_process_notification(struct eap_sm *sm, 1164214501Srpaulo struct eap_aka_data *data, 1165214501Srpaulo struct wpabuf *respData, 1166214501Srpaulo struct eap_sim_attrs *attr) 1167214501Srpaulo{ 1168214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); 1169214501Srpaulo if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 1170214501Srpaulo eap_aka_state(data, SUCCESS); 1171214501Srpaulo else 1172214501Srpaulo eap_aka_state(data, FAILURE); 1173214501Srpaulo} 1174214501Srpaulo 1175214501Srpaulo 1176214501Srpaulostatic void eap_aka_process(struct eap_sm *sm, void *priv, 1177214501Srpaulo struct wpabuf *respData) 1178214501Srpaulo{ 1179214501Srpaulo struct eap_aka_data *data = priv; 1180214501Srpaulo const u8 *pos, *end; 1181214501Srpaulo u8 subtype; 1182214501Srpaulo size_t len; 1183214501Srpaulo struct eap_sim_attrs attr; 1184214501Srpaulo 1185214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, 1186214501Srpaulo &len); 1187214501Srpaulo if (pos == NULL || len < 3) 1188214501Srpaulo return; 1189214501Srpaulo 1190214501Srpaulo end = pos + len; 1191214501Srpaulo subtype = *pos; 1192214501Srpaulo pos += 3; 1193214501Srpaulo 1194214501Srpaulo if (eap_aka_subtype_ok(data, subtype)) { 1195214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " 1196214501Srpaulo "EAP-AKA Subtype in EAP Response"); 1197214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1198214501Srpaulo eap_aka_state(data, NOTIFICATION); 1199214501Srpaulo return; 1200214501Srpaulo } 1201214501Srpaulo 1202214501Srpaulo if (eap_sim_parse_attr(pos, end, &attr, 1203214501Srpaulo data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, 1204214501Srpaulo 0)) { 1205214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); 1206214501Srpaulo data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; 1207214501Srpaulo eap_aka_state(data, NOTIFICATION); 1208214501Srpaulo return; 1209214501Srpaulo } 1210214501Srpaulo 1211214501Srpaulo if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { 1212214501Srpaulo eap_aka_process_client_error(sm, data, respData, &attr); 1213214501Srpaulo return; 1214214501Srpaulo } 1215214501Srpaulo 1216214501Srpaulo if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { 1217214501Srpaulo eap_aka_process_authentication_reject(sm, data, respData, 1218214501Srpaulo &attr); 1219214501Srpaulo return; 1220214501Srpaulo } 1221214501Srpaulo 1222214501Srpaulo switch (data->state) { 1223214501Srpaulo case IDENTITY: 1224214501Srpaulo eap_aka_process_identity(sm, data, respData, &attr); 1225214501Srpaulo break; 1226214501Srpaulo case CHALLENGE: 1227214501Srpaulo if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { 1228214501Srpaulo eap_aka_process_sync_failure(sm, data, respData, 1229214501Srpaulo &attr); 1230214501Srpaulo } else { 1231214501Srpaulo eap_aka_process_challenge(sm, data, respData, &attr); 1232214501Srpaulo } 1233214501Srpaulo break; 1234214501Srpaulo case REAUTH: 1235214501Srpaulo eap_aka_process_reauth(sm, data, respData, &attr); 1236214501Srpaulo break; 1237214501Srpaulo case NOTIFICATION: 1238214501Srpaulo eap_aka_process_notification(sm, data, respData, &attr); 1239214501Srpaulo break; 1240214501Srpaulo default: 1241214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " 1242214501Srpaulo "process", data->state); 1243214501Srpaulo break; 1244214501Srpaulo } 1245214501Srpaulo} 1246214501Srpaulo 1247214501Srpaulo 1248214501Srpaulostatic Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) 1249214501Srpaulo{ 1250214501Srpaulo struct eap_aka_data *data = priv; 1251214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 1252214501Srpaulo} 1253214501Srpaulo 1254214501Srpaulo 1255214501Srpaulostatic u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) 1256214501Srpaulo{ 1257214501Srpaulo struct eap_aka_data *data = priv; 1258214501Srpaulo u8 *key; 1259214501Srpaulo 1260214501Srpaulo if (data->state != SUCCESS) 1261214501Srpaulo return NULL; 1262214501Srpaulo 1263214501Srpaulo key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 1264214501Srpaulo if (key == NULL) 1265214501Srpaulo return NULL; 1266214501Srpaulo os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 1267214501Srpaulo *len = EAP_SIM_KEYING_DATA_LEN; 1268214501Srpaulo return key; 1269214501Srpaulo} 1270214501Srpaulo 1271214501Srpaulo 1272214501Srpaulostatic u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1273214501Srpaulo{ 1274214501Srpaulo struct eap_aka_data *data = priv; 1275214501Srpaulo u8 *key; 1276214501Srpaulo 1277214501Srpaulo if (data->state != SUCCESS) 1278214501Srpaulo return NULL; 1279214501Srpaulo 1280214501Srpaulo key = os_malloc(EAP_EMSK_LEN); 1281214501Srpaulo if (key == NULL) 1282214501Srpaulo return NULL; 1283214501Srpaulo os_memcpy(key, data->emsk, EAP_EMSK_LEN); 1284214501Srpaulo *len = EAP_EMSK_LEN; 1285214501Srpaulo return key; 1286214501Srpaulo} 1287214501Srpaulo 1288214501Srpaulo 1289214501Srpaulostatic Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) 1290214501Srpaulo{ 1291214501Srpaulo struct eap_aka_data *data = priv; 1292214501Srpaulo return data->state == SUCCESS; 1293214501Srpaulo} 1294214501Srpaulo 1295214501Srpaulo 1296214501Srpauloint eap_server_aka_register(void) 1297214501Srpaulo{ 1298214501Srpaulo struct eap_method *eap; 1299214501Srpaulo int ret; 1300214501Srpaulo 1301214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1302214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); 1303214501Srpaulo if (eap == NULL) 1304214501Srpaulo return -1; 1305214501Srpaulo 1306214501Srpaulo eap->init = eap_aka_init; 1307214501Srpaulo eap->reset = eap_aka_reset; 1308214501Srpaulo eap->buildReq = eap_aka_buildReq; 1309214501Srpaulo eap->check = eap_aka_check; 1310214501Srpaulo eap->process = eap_aka_process; 1311214501Srpaulo eap->isDone = eap_aka_isDone; 1312214501Srpaulo eap->getKey = eap_aka_getKey; 1313214501Srpaulo eap->isSuccess = eap_aka_isSuccess; 1314214501Srpaulo eap->get_emsk = eap_aka_get_emsk; 1315214501Srpaulo 1316214501Srpaulo ret = eap_server_method_register(eap); 1317214501Srpaulo if (ret) 1318214501Srpaulo eap_server_method_free(eap); 1319214501Srpaulo return ret; 1320214501Srpaulo} 1321214501Srpaulo 1322214501Srpaulo 1323214501Srpaulo#ifdef EAP_SERVER_AKA_PRIME 1324214501Srpauloint eap_server_aka_prime_register(void) 1325214501Srpaulo{ 1326214501Srpaulo struct eap_method *eap; 1327214501Srpaulo int ret; 1328214501Srpaulo 1329214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1330214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, 1331214501Srpaulo "AKA'"); 1332214501Srpaulo if (eap == NULL) 1333214501Srpaulo return -1; 1334214501Srpaulo 1335214501Srpaulo eap->init = eap_aka_prime_init; 1336214501Srpaulo eap->reset = eap_aka_reset; 1337214501Srpaulo eap->buildReq = eap_aka_buildReq; 1338214501Srpaulo eap->check = eap_aka_check; 1339214501Srpaulo eap->process = eap_aka_process; 1340214501Srpaulo eap->isDone = eap_aka_isDone; 1341214501Srpaulo eap->getKey = eap_aka_getKey; 1342214501Srpaulo eap->isSuccess = eap_aka_isSuccess; 1343214501Srpaulo eap->get_emsk = eap_aka_get_emsk; 1344214501Srpaulo 1345214501Srpaulo ret = eap_server_method_register(eap); 1346214501Srpaulo if (ret) 1347214501Srpaulo eap_server_method_free(eap); 1348214501Srpaulo 1349214501Srpaulo return ret; 1350214501Srpaulo} 1351214501Srpaulo#endif /* EAP_SERVER_AKA_PRIME */ 1352