static void eap_sim_process_challenge(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, (u8 *) data->sres, data->num_chal * EAP_SIM_SRES_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " "did not include valid AT_MAC"); eap_sim_state(data, FAILURE); return; } wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " "correct AT_MAC"); if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_sim_state(data, NOTIFICATION); } else eap_sim_state(data, SUCCESS); identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { identity = sm->identity; identity_len = sm->identity_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } }
static void eap_aka_check_identity(struct eap_sm *sm, struct eap_aka_data *data) { char *username; /* Check if we already know the identity from EAP-Response/Identity */ username = sim_get_username(sm->identity, sm->identity_len); if (username == NULL) return; if (eap_aka_check_identity_reauth(sm, data, username) > 0) { os_free(username); /* * Since re-auth username was recognized, skip AKA/Identity * exchange. */ return; } if ((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || (data->eap_method == EAP_TYPE_AKA && username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { const char *permanent; wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", username); permanent = eap_sim_db_get_permanent( sm->eap_sim_db_priv, username); if (permanent == NULL) { os_free(username); wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " "identity - request permanent identity"); /* Remain in IDENTITY state for another round */ return; } os_strlcpy(data->permanent, permanent, sizeof(data->permanent)); /* * Since pseudonym username was recognized, skip AKA/Identity * exchange. */ eap_aka_fullauth(sm, data); } os_free(username); }
static void eap_aka_process_reauth(struct eap_sm *sm, struct eap_aka_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted = NULL; const u8 *identity, *id2; size_t identity_len, id2_len; wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); if (attr->mac == NULL || eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, EAP_SIM_NONCE_S_LEN)) { wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " "did not include valid AT_MAC"); goto fail; } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " "message did not include encrypted data"); goto fail; } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " "data from reauthentication message"); goto fail; } if (eattr.counter != data->counter) { wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " "used incorrect counter %u, expected %u", eattr.counter, data->counter); goto fail; } os_free(decrypted); decrypted = NULL; wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " "the correct AT_MAC"); if (eattr.counter_too_small) { wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " "included AT_COUNTER_TOO_SMALL - starting full " "authentication"); eap_aka_determine_identity(sm, data, 0, 1); return; } if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_aka_state(data, NOTIFICATION); } else eap_aka_state(data, SUCCESS); if (data->reauth) { identity = data->reauth->identity; identity_len = data->reauth->identity_len; } else { identity = sm->identity; identity_len = sm->identity_len; } id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, identity_len, &id2_len); if (id2) { identity = id2; identity_len = id2_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { if (data->eap_method == EAP_TYPE_AKA_PRIME) { #ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->k_encr, data->k_aut, data->k_re); #endif /* EAP_SERVER_AKA_PRIME */ } else { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); } data->next_reauth_id = NULL; } else { eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; } return; fail: data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; os_free(decrypted); }
static void eap_aka_process_challenge(struct eap_sm *sm, struct eap_aka_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); #ifdef EAP_SERVER_AKA_PRIME #if 0 /* KDF negotiation; to be enabled only after more than one KDF is * supported */ if (data->eap_method == EAP_TYPE_AKA_PRIME && attr->kdf_count == 1 && attr->mac == NULL) { if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " "unknown KDF"); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } data->kdf = attr->kdf[0]; /* Allow negotiation to continue with the selected KDF by * sending another Challenge message */ wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); return; } #endif #endif /* EAP_SERVER_AKA_PRIME */ if (attr->checkcode && eap_aka_verify_checkcode(data, attr->checkcode, attr->checkcode_len)) { wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " "message"); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } if (attr->mac == NULL || eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " "did not include valid AT_MAC"); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } /* * AT_RES is padded, so verify that there is enough room for RES and * that the RES length in bits matches with the expected RES. */ if (attr->res == NULL || attr->res_len < data->res_len || attr->res_len_bits != data->res_len * 8 || os_memcmp(attr->res, data->res, data->res_len) != 0) { wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " "include valid AT_RES (attr len=%lu, res len=%lu " "bits, expected %lu bits)", (unsigned long) attr->res_len, (unsigned long) attr->res_len_bits, (unsigned long) data->res_len * 8); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " "correct AT_MAC"); if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_aka_state(data, NOTIFICATION); } else eap_aka_state(data, SUCCESS); identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { identity = sm->identity; identity_len = sm->identity_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { if (data->eap_method == EAP_TYPE_AKA_PRIME) { #ifdef EAP_SERVER_AKA_PRIME eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->k_encr, data->k_aut, data->k_re); #endif /* EAP_SERVER_AKA_PRIME */ } else { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); } data->next_reauth_id = NULL; } }
static void eap_aka_determine_identity(struct eap_sm *sm, struct eap_aka_data *data, int before_identity, int after_reauth) { const u8 *identity; size_t identity_len; int res; identity = NULL; identity_len = 0; if (after_reauth && data->reauth) { identity = data->reauth->identity; identity_len = data->reauth->identity_len; } else if (sm->identity && sm->identity_len > 0 && sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { identity = sm->identity; identity_len = sm->identity_len; } else { identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { data->reauth = eap_sim_db_get_reauth_entry( sm->eap_sim_db_priv, sm->identity, sm->identity_len); if (data->reauth && data->reauth->aka_prime != (data->eap_method == EAP_TYPE_AKA_PRIME)) { wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " "was for different AKA version"); data->reauth = NULL; } if (data->reauth) { wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " "re-authentication"); identity = data->reauth->identity; identity_len = data->reauth->identity_len; data->counter = data->reauth->counter; if (data->eap_method == EAP_TYPE_AKA_PRIME) { os_memcpy(data->k_encr, data->reauth->k_encr, EAP_SIM_K_ENCR_LEN); os_memcpy(data->k_aut, data->reauth->k_aut, EAP_AKA_PRIME_K_AUT_LEN); os_memcpy(data->k_re, data->reauth->k_re, EAP_AKA_PRIME_K_RE_LEN); } else { os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); } } } } if (identity == NULL || eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, sm->identity_len) < 0) { if (before_identity) { wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " "not known - send AKA-Identity request"); eap_aka_state(data, IDENTITY); return; } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " "permanent user name is known; try to use " "it"); /* eap_sim_db_get_aka_auth() will report failure, if * this identity is not known. */ } } wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", identity, identity_len); if (!after_reauth && data->reauth) { eap_aka_state(data, REAUTH); return; } res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, identity_len, data->rand, data->autn, data->ik, data->ck, data->res, &data->res_len, sm); if (res == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " "not yet available - pending request"); sm->method_pending = METHOD_PENDING_WAIT; return; } #ifdef EAP_SERVER_AKA_PRIME if (data->eap_method == EAP_TYPE_AKA_PRIME) { /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the * needed 6-octet SQN ^AK for CK',IK' derivation */ eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, data->autn, data->network_name, data->network_name_len); } #endif /* EAP_SERVER_AKA_PRIME */ data->reauth = NULL; data->counter = 0; /* reset re-auth counter since this is full auth */ if (res != 0) { wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " "authentication data for the peer"); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " "available - abort pending wait"); sm->method_pending = METHOD_PENDING_NONE; } identity_len = sm->identity_len; while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " "character from identity"); identity_len--; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", sm->identity, identity_len); if (data->eap_method == EAP_TYPE_AKA_PRIME) { eap_aka_prime_derive_keys(identity, identity_len, data->ik, data->ck, data->k_encr, data->k_aut, data->k_re, data->msk, data->emsk); } else { eap_aka_derive_mk(sm->identity, identity_len, data->ik, data->ck, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); } eap_aka_state(data, CHALLENGE); }
static void eap_sim_process_reauth(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { struct eap_sim_attrs eattr; u8 *decrypted = NULL; const u8 *identity, *id2; size_t identity_len, id2_len; if (attr->mac == NULL || eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, EAP_SIM_NONCE_S_LEN)) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "did not include valid AT_MAC"); goto fail; } if (attr->encr_data == NULL || attr->iv == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " "message did not include encrypted data"); goto fail; } decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, attr->encr_data_len, attr->iv, &eattr, 0); if (decrypted == NULL) { wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " "data from reauthentication message"); goto fail; } if (eattr.counter != data->counter) { wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " "used incorrect counter %u, expected %u", eattr.counter, data->counter); goto fail; } os_free(decrypted); decrypted = NULL; wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " "the correct AT_MAC"); if (sm->eap_sim_aka_result_ind && attr->result_ind) { data->use_result_ind = 1; data->notification = EAP_SIM_SUCCESS; eap_sim_state(data, NOTIFICATION); } else eap_sim_state(data, SUCCESS); if (data->reauth) { identity = data->reauth->identity; identity_len = data->reauth->identity_len; } else { identity = sm->identity; identity_len = sm->identity_len; } id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, identity_len, &id2_len); if (id2) { identity = id2; identity_len = id2_len; } if (data->next_pseudonym) { eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, identity_len, data->next_pseudonym); data->next_pseudonym = NULL; } if (data->next_reauth_id) { eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, identity_len, data->next_reauth_id, data->counter + 1, data->mk); data->next_reauth_id = NULL; } else { eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; } return; fail: eap_sim_state(data, FAILURE); eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); data->reauth = NULL; os_free(decrypted); }
static void eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { const u8 *identity; size_t identity_len; u8 ver_list[2]; wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); if (attr->identity) { os_free(sm->identity); sm->identity = os_malloc(attr->identity_len); if (sm->identity) { os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; } } identity = NULL; identity_len = 0; if (sm->identity && sm->identity_len > 0 && sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) { identity = sm->identity; identity_len = sm->identity_len; } else { identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, sm->identity_len, &identity_len); if (identity == NULL) { data->reauth = eap_sim_db_get_reauth_entry( sm->eap_sim_db_priv, sm->identity, sm->identity_len); if (data->reauth) { wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast " "re-authentication"); identity = data->reauth->identity; identity_len = data->reauth->identity_len; data->counter = data->reauth->counter; os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); } } } if (identity == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent" " user name"); eap_sim_state(data, FAILURE); return; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", identity, identity_len); if (data->reauth) { eap_sim_state(data, REAUTH); return; } if (attr->nonce_mt == NULL || attr->selected_version < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " "required attributes"); eap_sim_state(data, FAILURE); return; } if (!eap_sim_supported_ver(data, attr->selected_version)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " "version %d", attr->selected_version); eap_sim_state(data, FAILURE); return; } data->counter = 0; /* reset re-auth counter since this is full auth */ data->reauth = NULL; data->num_chal = eap_sim_db_get_gsm_triplets( sm->eap_sim_db_priv, identity, identity_len, EAP_SIM_MAX_CHAL, (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); if (data->num_chal == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " "not yet available - pending request"); sm->method_pending = METHOD_PENDING_WAIT; return; } if (data->num_chal < 2) { wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " "authentication triplets for the peer"); eap_sim_state(data, FAILURE); return; } identity_len = sm->identity_len; while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " "character from identity"); identity_len--; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", sm->identity, identity_len); os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, attr->selected_version, ver_list, sizeof(ver_list), data->num_chal, (const u8 *) data->kc, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); eap_sim_state(data, CHALLENGE); }
static void eap_aka_determine_identity(struct eap_sm *sm, struct eap_aka_data *data) { char *username; wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", sm->identity, sm->identity_len); username = sim_get_username(sm->identity, sm->identity_len); if (username == NULL) { data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } if (eap_aka_check_identity_reauth(sm, data, username) > 0) { os_free(username); return; } if (((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) || (data->eap_method == EAP_TYPE_AKA && username[0] == EAP_AKA_REAUTH_ID_PREFIX)) && data->identity_round == 1) { /* Remain in IDENTITY state for another round to request full * auth identity since we did not recognize reauth id */ os_free(username); return; } if ((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || (data->eap_method == EAP_TYPE_AKA && username[0] == EAP_AKA_PSEUDONYM_PREFIX)) { const char *permanent; wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'", username); permanent = eap_sim_db_get_permanent( sm->eap_sim_db_priv, username); os_free(username); if (permanent == NULL) { wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym " "identity - request permanent identity"); /* Remain in IDENTITY state for another round */ return; } os_strlcpy(data->permanent, permanent, sizeof(data->permanent)); } else if ((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) || (data->eap_method == EAP_TYPE_AKA && username[0] == EAP_AKA_PERMANENT_PREFIX)) { wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'", username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", username); os_free(username); data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_aka_state(data, NOTIFICATION); return; } eap_aka_fullauth(sm, data); }
static void eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data, struct wpabuf *respData, struct eap_sim_attrs *attr) { size_t identity_len; u8 ver_list[2]; u8 *new_identity; char *username; wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); if (data->start_round == 0) { /* * Special case for AT_COUNTER_TOO_SMALL recovery - no identity * was requested since we already know it. */ goto skip_id_update; } /* * We always request identity in SIM/Start, so the peer is required to * have replied with one. */ if (!attr->identity || attr->identity_len == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " "identity"); goto failed; } new_identity = os_malloc(attr->identity_len); if (new_identity == NULL) goto failed; os_free(sm->identity); sm->identity = new_identity; os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", sm->identity, sm->identity_len); username = sim_get_username(sm->identity, sm->identity_len); if (username == NULL) goto failed; if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) { wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'", username); data->reauth = eap_sim_db_get_reauth_entry( sm->eap_sim_db_priv, username); os_free(username); if (data->reauth == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth " "identity - request full auth identity"); /* Remain in START state for another round */ return; } wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); os_strlcpy(data->permanent, data->reauth->permanent, sizeof(data->permanent)); data->counter = data->reauth->counter; os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN); eap_sim_state(data, REAUTH); return; } if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) { const char *permanent; wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'", username); permanent = eap_sim_db_get_permanent( sm->eap_sim_db_priv, username); os_free(username); if (permanent == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym " "identity - request permanent identity"); /* Remain in START state for another round */ return; } os_strlcpy(data->permanent, permanent, sizeof(data->permanent)); } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) { wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'", username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", username); os_free(username); goto failed; } skip_id_update: /* Full authentication */ if (attr->nonce_mt == NULL || attr->selected_version < 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " "required attributes"); goto failed; } if (!eap_sim_supported_ver(data, attr->selected_version)) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " "version %d", attr->selected_version); goto failed; } data->counter = 0; /* reset re-auth counter since this is full auth */ data->reauth = NULL; data->num_chal = eap_sim_db_get_gsm_triplets( sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL, (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); if (data->num_chal == EAP_SIM_DB_PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " "not yet available - pending request"); sm->method_pending = METHOD_PENDING_WAIT; return; } if (data->num_chal < 2) { wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " "authentication triplets for the peer"); goto failed; } identity_len = sm->identity_len; while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " "character from identity"); identity_len--; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", sm->identity, identity_len); os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, attr->selected_version, ver_list, sizeof(ver_list), data->num_chal, (const u8 *) data->kc, data->mk); eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, data->emsk); eap_sim_state(data, CHALLENGE); return; failed: data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; eap_sim_state(data, NOTIFICATION); }