From f534ee0804dc8d77434d2b534a118e86bd597694 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Jun 2014 21:16:30 +0300 Subject: [PATCH] EAP peer: Clear keying material on deinit Reduce the amount of time keying material (MSK, EMSK, temporary private data) remains in memory in EAP methods. This provides additional protection should there be any issues that could expose process memory to external observers. Signed-off-by: Jouni Malinen --- src/eap_peer/eap.c | 17 ++++++++++++----- src/eap_peer/eap_aka.c | 17 +++++++++++++++++ src/eap_peer/eap_eke.c | 2 +- src/eap_peer/eap_fast.c | 4 ++++ src/eap_peer/eap_gpsk.c | 7 +++++-- src/eap_peer/eap_ikev2.c | 2 +- src/eap_peer/eap_leap.c | 3 +++ src/eap_peer/eap_mschapv2.c | 10 ++++++---- src/eap_peer/eap_pax.c | 2 +- src/eap_peer/eap_peap.c | 16 ++++++++++++---- src/eap_peer/eap_psk.c | 2 +- src/eap_peer/eap_pwd.c | 4 ++-- src/eap_peer/eap_sake.c | 2 +- src/eap_peer/eap_sim.c | 16 ++++++++++++++++ src/eap_peer/eap_tls.c | 16 ++++++++++++---- src/eap_peer/eap_ttls.c | 16 ++++++++++++---- 16 files changed, 106 insertions(+), 30 deletions(-) diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 47cbbeed1..a2faeb2d2 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -92,6 +92,15 @@ static void eap_notify_status(struct eap_sm *sm, const char *status, } +static void eap_sm_free_key(struct eap_sm *sm) +{ + if (sm->eapKeyData) { + bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen); + sm->eapKeyData = NULL; + } +} + + static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) { ext_password_free(sm->ext_pw_buf); @@ -159,8 +168,7 @@ SM_STATE(EAP, INITIALIZE) eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); eapol_set_bool(sm, EAPOL_eapFail, FALSE); - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; + eap_sm_free_key(sm); os_free(sm->eapSessionId); sm->eapSessionId = NULL; sm->eapKeyAvailable = FALSE; @@ -404,7 +412,7 @@ SM_STATE(EAP, METHOD) if (sm->m->isKeyAvailable && sm->m->getKey && sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { - os_free(sm->eapKeyData); + eap_sm_free_key(sm); sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, &sm->eapKeyDataLen); os_free(sm->eapSessionId); @@ -1488,8 +1496,7 @@ void eap_sm_abort(struct eap_sm *sm) sm->lastRespData = NULL; wpabuf_free(sm->eapRespData); sm->eapRespData = NULL; - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; + eap_sm_free_key(sm); os_free(sm->eapSessionId); sm->eapSessionId = NULL; diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index 41361c019..0662ae738 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -126,6 +126,21 @@ static void * eap_aka_prime_init(struct eap_sm *sm) #endif /* EAP_AKA_PRIME */ +static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth) +{ + if (!reauth) { + os_memset(data->mk, 0, EAP_SIM_MK_LEN); + os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN); + os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN); + os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN); + } + os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); + os_memset(data->autn, 0, EAP_AKA_AUTN_LEN); + os_memset(data->auts, 0, EAP_AKA_AUTS_LEN); +} + + static void eap_aka_deinit(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; @@ -135,6 +150,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) os_free(data->last_eap_identity); wpabuf_free(data->id_msgs); os_free(data->network_name); + eap_aka_clear_keys(data, 0); os_free(data); } } @@ -1373,6 +1389,7 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) data->id_msgs = NULL; data->use_result_ind = 0; data->kdf_negotiation = 0; + eap_aka_clear_keys(data, 1); } diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c index 0f4e53504..9fec66c06 100644 --- a/src/eap_peer/eap_eke.c +++ b/src/eap_peer/eap_eke.c @@ -138,7 +138,7 @@ static void eap_eke_deinit(struct eap_sm *sm, void *priv) os_free(data->serverid); os_free(data->peerid); wpabuf_free(data->msgs); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index 127a0d9ed..0739187c1 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -250,6 +250,8 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv) pac = pac->next; eap_fast_free_pac(prev); } + os_memset(data->key_data, 0, EAP_FAST_KEY_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -1636,6 +1638,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv) os_free(data); return NULL; } + os_memset(data->key_data, 0, EAP_FAST_KEY_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); os_free(data->session_id); data->session_id = NULL; if (data->phase2_priv && data->phase2_method && diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c index 998ea06ef..c54bf1164 100644 --- a/src/eap_peer/eap_gpsk.c +++ b/src/eap_peer/eap_gpsk.c @@ -134,8 +134,11 @@ static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) struct eap_gpsk_data *data = priv; os_free(data->id_server); os_free(data->id_peer); - os_free(data->psk); - os_free(data); + if (data->psk) { + os_memset(data->psk, 0, data->psk_len); + os_free(data->psk); + } + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c index 568a44804..c12b51933 100644 --- a/src/eap_peer/eap_ikev2.c +++ b/src/eap_peer/eap_ikev2.c @@ -113,7 +113,7 @@ static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) wpabuf_free(data->in_buf); wpabuf_free(data->out_buf); ikev2_responder_deinit(&data->ikev2); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c index f4cd1250d..e0f8bcf6b 100644 --- a/src/eap_peer/eap_leap.c +++ b/src/eap_peer/eap_leap.c @@ -383,6 +383,9 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; + os_memset(pw_hash, 0, sizeof(pw_hash)); + os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash)); + return key; } diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c index f2fcc3710..430c501bb 100644 --- a/src/eap_peer/eap_mschapv2.c +++ b/src/eap_peer/eap_mschapv2.c @@ -140,7 +140,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv) os_free(data->peer_challenge); os_free(data->auth_challenge); wpabuf_free(data->prev_challenge); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -303,7 +303,7 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm, WPA_EVENT_PASSWORD_CHANGED "EAP-MSCHAPV2: Password changed successfully"); data->prev_error = 0; - os_free(config->password); + bin_clear_free(config->password, config->password_len); if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { /* TODO: update external storage */ } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { @@ -313,11 +313,13 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm, nt_password_hash(config->new_password, config->new_password_len, config->password)) { - os_free(config->password); + bin_clear_free(config->password, + config->password_len); config->password = NULL; config->password_len = 0; } - os_free(config->new_password); + bin_clear_free(config->new_password, + config->new_password_len); } else { config->password = config->new_password; config->password_len = config->new_password_len; diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c index f10a15b5a..1c111c28d 100644 --- a/src/eap_peer/eap_pax.c +++ b/src/eap_peer/eap_pax.c @@ -86,7 +86,7 @@ static void eap_pax_deinit(struct eap_sm *sm, void *priv) { struct eap_pax_data *data = priv; os_free(data->cid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 7740cf99f..472e861b0 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -170,6 +170,15 @@ static void * eap_peap_init(struct eap_sm *sm) } +static void eap_peap_free_key(struct eap_peap_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN); + data->key_data = NULL; + } +} + + static void eap_peap_deinit(struct eap_sm *sm, void *priv) { struct eap_peap_data *data = priv; @@ -179,7 +188,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv) data->phase2_method->deinit(sm, data->phase2_priv); os_free(data->phase2_types); eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_peap_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -1005,7 +1014,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, char *label; wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS done, proceed to Phase 2"); - os_free(data->key_data); + eap_peap_free_key(data); /* draft-josefsson-ppext-eap-tls-eap-05.txt * specifies that PEAPv1 would use "client PEAP * encryption" as the label. However, most existing @@ -1115,8 +1124,7 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_peap_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_peap_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c index fc2a1b909..f01266354 100644 --- a/src/eap_peer/eap_psk.c +++ b/src/eap_peer/eap_psk.c @@ -76,7 +76,7 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv) struct eap_psk_data *data = priv; os_free(data->id_s); os_free(data->id_p); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index fec3224c5..bdcca0b81 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -157,7 +157,7 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv) EC_POINT_free(data->server_element); os_free(data->id_peer); os_free(data->id_server); - os_free(data->password); + bin_clear_free(data->password, data->password_len); if (data->grp) { EC_GROUP_free(data->grp->group); EC_POINT_free(data->grp->pwe); @@ -167,7 +167,7 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv) } wpabuf_free(data->inbuf); wpabuf_free(data->outbuf); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c index 85fe860c4..7d1490743 100644 --- a/src/eap_peer/eap_sake.c +++ b/src/eap_peer/eap_sake.c @@ -108,7 +108,7 @@ static void eap_sake_deinit(struct eap_sm *sm, void *priv) struct eap_sake_data *data = priv; os_free(data->serverid); os_free(data->peerid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 9e0c08fa5..bd06df78d 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -130,6 +130,20 @@ static void * eap_sim_init(struct eap_sm *sm) } +static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth) +{ + if (!reauth) { + os_memset(data->mk, 0, EAP_SIM_MK_LEN); + os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN); + os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN); + } + os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN); + os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN); + os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); +} + + static void eap_sim_deinit(struct eap_sm *sm, void *priv) { struct eap_sim_data *data = priv; @@ -138,6 +152,7 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) os_free(data->pseudonym); os_free(data->reauth_id); os_free(data->last_eap_identity); + eap_sim_clear_keys(data, 0); os_free(data); } } @@ -1110,6 +1125,7 @@ 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); data->use_result_ind = 0; + eap_sim_clear_keys(data, 1); } diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c index bb9f3f261..5aa3fd591 100644 --- a/src/eap_peer/eap_tls.c +++ b/src/eap_peer/eap_tls.c @@ -125,13 +125,22 @@ static void * eap_wfa_unauth_tls_init(struct eap_sm *sm) #endif /* CONFIG_HS20 */ +static void eap_tls_free_key(struct eap_tls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); + data->key_data = NULL; + } +} + + static void eap_tls_deinit(struct eap_sm *sm, void *priv) { struct eap_tls_data *data = priv; if (data == NULL) return; eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_tls_free_key(data); os_free(data->session_id); os_free(data); } @@ -181,7 +190,7 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; - os_free(data->key_data); + eap_tls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "client EAP encryption", EAP_TLS_KEY_LEN + @@ -267,8 +276,7 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_tls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_tls_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index 5091bf084..e110236ad 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -133,6 +133,15 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, } +static void eap_ttls_free_key(struct eap_ttls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN); + data->key_data = NULL; + } +} + + static void eap_ttls_deinit(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; @@ -141,7 +150,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv) eap_ttls_phase2_eap_deinit(sm, data); os_free(data->phase2_eap_types); eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_ttls_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -213,7 +222,7 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { - os_free(data->key_data); + eap_ttls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "ttls keying material", EAP_TLS_KEY_LEN); @@ -1540,8 +1549,7 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_ttls_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) {