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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-06-29 21:16:30 +03:00
parent 19c48da06b
commit f534ee0804
16 changed files with 106 additions and 30 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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 &&

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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));
}

View file

@ -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)) {

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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)) {

View file

@ -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)) {