diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index d07060213..c8e514ab8 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -1759,6 +1759,10 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) wpabuf_put_data(resp, identity, identity_len); wpabuf_free(privacy_identity); + os_free(sm->identity); + sm->identity = os_memdup(identity, identity_len); + sm->identity_len = identity_len; + return resp; } @@ -2262,6 +2266,7 @@ void eap_peer_sm_deinit(struct eap_sm *sm) tls_deinit(sm->ssl_ctx2); tls_deinit(sm->ssl_ctx); eap_peer_erp_free_keys(sm); + os_free(sm->identity); os_free(sm); } diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index 6fe939b5c..72d4ee505 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -41,8 +41,8 @@ struct eap_aka_data { size_t reauth_id_len; int reauth; unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; + u8 *mk_identity; + size_t mk_identity_len; enum { CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE } state; @@ -140,6 +140,13 @@ static void * eap_aka_init(struct eap_sm *sm) } } + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + return data; } @@ -177,7 +184,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) if (data) { os_free(data->pseudonym); os_free(data->reauth_id); - os_free(data->last_eap_identity); + os_free(data->mk_identity); wpabuf_free(data->id_msgs); os_free(data->network_name); eap_aka_clear_keys(data, 0); @@ -373,7 +380,6 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) #define CLEAR_PSEUDONYM 0x01 #define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 static void eap_aka_clear_identities(struct eap_sm *sm, struct eap_aka_data *data, int id) @@ -392,12 +398,6 @@ static void eap_aka_clear_identities(struct eap_sm *sm, data->reauth_id = NULL; data->reauth_id_len = 0; } - if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id"); - os_free(data->last_eap_identity); - data->last_eap_identity = NULL; - data->last_eap_identity_len = 0; - } } @@ -699,6 +699,8 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, size_t identity_len = 0; struct eap_sim_msg *msg; struct wpabuf *enc_identity = NULL; + struct eap_peer_config *config = NULL; + bool use_imsi_identity = false; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -722,10 +724,13 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, data->pseudonym_len)) ids &= ~CLEAR_PSEUDONYM; eap_aka_clear_identities(sm, data, ids); + + config = eap_get_config(sm); + if (config && config->imsi_identity) + use_imsi_identity = true; } #ifdef CRYPTO_RSA_OAEP_SHA256 if (identity && data->imsi_privacy_key) { - struct eap_peer_config *config; const char *attr = NULL; config = eap_get_config(sm); @@ -741,13 +746,16 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); } + /* Use the real identity, not the encrypted one, in MK + * derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; identity = wpabuf_head(enc_identity); identity_len = wpabuf_len(enc_identity); } #endif /* CRYPTO_RSA_OAEP_SHA256 */ } - if (id_req != NO_ID_REQ) - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, @@ -758,6 +766,22 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, identity, identity_len); eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); + if (use_imsi_identity && config && config->imsi_identity) { + /* Use the IMSI identity override, i.e., the not + * encrypted one, in MK derivation, when using + * externally encrypted identity in configuration. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup( + config->imsi_identity, + config->imsi_identity_len); + data->mk_identity_len = config->imsi_identity_len; + } else if (!enc_identity) { + /* Use the last AT_IDENTITY value as the identity in + * MK derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + } } wpabuf_free(enc_identity); @@ -1147,28 +1171,9 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, data->network_name_len); } #endif /* EAP_AKA_PRIME */ - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->reauth_id) { - identity = data->reauth_id; - identity_len = data->reauth_id_len; - } else if (data->pseudonym && - !eap_sim_anonymous_username(data->pseudonym, - data->pseudonym_len)) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else { - struct eap_peer_config *config; - config = eap_get_config(sm); - if (config && config->imsi_identity) { - identity = config->imsi_identity; - identity_len = config->imsi_identity_len; - } else { - identity = eap_get_config_identity(sm, &identity_len); - } - } + identity = data->mk_identity; + identity_len = data->mk_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " "derivation", identity, identity_len); if (data->eap_method == EAP_TYPE_AKA_PRIME) { @@ -1197,7 +1202,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, * other words, if no new identities are received, full * authentication will be used on next reauthentication (using * pseudonym identity or permanent identity). */ - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); if (attr->encr_data) { u8 *decrypted; @@ -1407,14 +1412,8 @@ static struct wpabuf * eap_aka_process_reauthentication( /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; + */ + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s); os_free(decrypted); @@ -1439,7 +1438,7 @@ static struct wpabuf * eap_aka_process_reauthentication( data->nonce_s, data->mk, data->msk, data->emsk); } - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); eap_aka_learn_ids(sm, data, &eattr); if (data->result_ind && attr->result_ind) @@ -1455,8 +1454,7 @@ static struct wpabuf * eap_aka_process_reauthentication( if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of " "fast reauths performed - force fullauth"); - eap_aka_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); } os_free(decrypted); return eap_aka_response_reauth(data, id, 0, data->nonce_s); @@ -1572,7 +1570,10 @@ static bool eap_aka_has_reauth_data(struct eap_sm *sm, void *priv) static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); + + os_free(data->mk_identity); + data->mk_identity = NULL; + data->mk_identity_len = 0; data->prev_id = -1; wpabuf_free(data->id_msgs); data->id_msgs = NULL; @@ -1585,6 +1586,15 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; + + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + data->num_id_req = 0; data->num_notification = 0; eap_aka_state(data, CONTINUE); diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 08dd569d6..21681658d 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -390,6 +390,10 @@ struct eap_sm { unsigned int use_machine_cred:1; struct dl_list erp_keys; /* struct eap_erp_key */ + + /* Identity used in EAP-Response/Identity */ + u8 *identity; + size_t identity_len; }; const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 71da424d2..b5e324023 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -43,8 +43,8 @@ struct eap_sim_data { size_t reauth_id_len; int reauth; unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; + u8 *mk_identity; + size_t mk_identity_len; enum { CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE } state; @@ -158,6 +158,13 @@ static void * eap_sim_init(struct eap_sm *sm) } } + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + eap_sim_state(data, CONTINUE); return data; @@ -185,7 +192,7 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) os_free(data->ver_list); os_free(data->pseudonym); os_free(data->reauth_id); - os_free(data->last_eap_identity); + os_free(data->mk_identity); eap_sim_clear_keys(data, 0); #ifdef CRYPTO_RSA_OAEP_SHA256 crypto_rsa_key_free(data->imsi_privacy_key); @@ -399,7 +406,6 @@ static int eap_sim_supported_ver(int version) #define CLEAR_PSEUDONYM 0x01 #define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 static void eap_sim_clear_identities(struct eap_sm *sm, struct eap_sim_data *data, int id) @@ -418,12 +424,6 @@ static void eap_sim_clear_identities(struct eap_sm *sm, data->reauth_id = NULL; data->reauth_id_len = 0; } - if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { - wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id"); - os_free(data->last_eap_identity); - data->last_eap_identity = NULL; - data->last_eap_identity_len = 0; - } } @@ -567,6 +567,8 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, struct eap_sim_msg *msg; struct wpabuf *resp; struct wpabuf *enc_identity = NULL; + struct eap_peer_config *config = NULL; + bool use_imsi_identity = false; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -590,10 +592,13 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, data->pseudonym_len)) ids &= ~CLEAR_PSEUDONYM; eap_sim_clear_identities(sm, data, ids); + + config = eap_get_config(sm); + if (config && config->imsi_identity) + use_imsi_identity = true; } #ifdef CRYPTO_RSA_OAEP_SHA256 if (identity && data->imsi_privacy_key) { - struct eap_peer_config *config; const char *attr = NULL; config = eap_get_config(sm); @@ -609,13 +614,16 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } + /* Use the real identity, not the encrypted one, in MK + * derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; identity = wpabuf_head(enc_identity); identity_len = wpabuf_len(enc_identity); } #endif /* CRYPTO_RSA_OAEP_SHA256 */ } - if (id_req != NO_ID_REQ) - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, @@ -625,6 +633,22 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, identity, identity_len); eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); + if (use_imsi_identity && config && config->imsi_identity) { + /* Use the IMSI identity override, i.e., the not + * encrypted one, in MK derivation, when using + * externally encrypted identity in configuration. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup( + config->imsi_identity, + config->imsi_identity_len); + data->mk_identity_len = config->imsi_identity_len; + } else if (!enc_identity) { + /* Use the last AT_IDENTITY value as the identity in + * MK derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + } } wpabuf_free(enc_identity); if (!data->reauth) { @@ -886,28 +910,9 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->reauth_id) { - identity = data->reauth_id; - identity_len = data->reauth_id_len; - } else if (data->pseudonym && - !eap_sim_anonymous_username(data->pseudonym, - data->pseudonym_len)) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else { - struct eap_peer_config *config; - config = eap_get_config(sm); - if (config && config->imsi_identity) { - identity = config->imsi_identity; - identity_len = config->imsi_identity_len; - } else { - identity = eap_get_config_identity(sm, &identity_len); - } - } + identity = data->mk_identity; + identity_len = data->mk_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " "derivation", identity, identity_len); eap_sim_derive_mk(identity, identity_len, data->nonce_mt, @@ -933,7 +938,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, * other words, if no new reauth identity is received, full * authentication will be used on next reauthentication (using * pseudonym identity or permanent identity). */ - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); if (attr->encr_data) { u8 *decrypted; @@ -1143,14 +1148,8 @@ static struct wpabuf * eap_sim_process_reauthentication( /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; + */ + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s); os_free(decrypted); @@ -1167,7 +1166,7 @@ static struct wpabuf * eap_sim_process_reauthentication( data->reauth_id, data->reauth_id_len, data->nonce_s, data->mk, data->msk, data->emsk); - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); eap_sim_learn_ids(sm, data, &eattr); if (data->result_ind && attr->result_ind) @@ -1183,8 +1182,7 @@ static struct wpabuf * eap_sim_process_reauthentication( if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " "fast reauths performed - force fullauth"); - eap_sim_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); } os_free(decrypted); return eap_sim_response_reauth(data, id, 0, data->nonce_s); @@ -1293,7 +1291,10 @@ static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv) static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) { struct eap_sim_data *data = priv; - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); + + os_free(data->mk_identity); + data->mk_identity = NULL; + data->mk_identity_len = 0; data->use_result_ind = 0; eap_sim_clear_keys(data, 1); } @@ -1308,6 +1309,15 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) eap_sim_deinit(sm, data); return NULL; } + + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + data->num_id_req = 0; data->num_notification = 0; eap_sim_state(data, CONTINUE);