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