From 581a8cde77670ba7de2cce57f4a723ba435df9b7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 6 Nov 2008 19:57:21 +0200 Subject: [PATCH] Added support for enforcing frequent PTK rekeying Added a new configuration option, wpa_ptk_rekey, that can be used to enforce frequent PTK rekeying, e.g., to mitigate some attacks against TKIP deficiencies. This can be set either by the Authenticator (to initiate periodic 4-way handshake to rekey PTK) or by the Supplicant (to request Authenticator to rekey PTK). With both wpa_ptk_rekey and wpa_group_rekey (in hostapd) set to 600, TKIP keys will not be used for more than 10 minutes which may make some attacks against TKIP more difficult to implement. --- hostapd/ChangeLog | 5 +++++ hostapd/config.c | 2 ++ hostapd/config.h | 1 + hostapd/hostapd.c | 1 + hostapd/hostapd.conf | 4 ++++ hostapd/wpa.c | 21 +++++++++++++++++++++ hostapd/wpa.h | 1 + src/rsn_supp/wpa.c | 19 ++++++++++++++++++- src/rsn_supp/wpa.h | 1 + src/rsn_supp/wpa_i.h | 1 + wpa_supplicant/ChangeLog | 3 +++ wpa_supplicant/config.c | 3 ++- wpa_supplicant/config_ssid.h | 8 ++++++++ wpa_supplicant/wpa_supplicant.conf | 14 ++++++++++++++ wpa_supplicant/wpas_glue.c | 1 + 15 files changed, 83 insertions(+), 2 deletions(-) diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index a8e7f4eb4..b2cfb5bfe 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -1,5 +1,10 @@ ChangeLog for hostapd +????-??-?? - v0.6.6 + * added a new configuration option, wpa_ptk_rekey, that can be used to + enforce frequent PTK rekeying, e.g., to mitigate some attacks against + TKIP deficiencies + 2008-11-01 - v0.6.5 * added support for SHA-256 as X.509 certificate digest when using the internal X.509/TLSv1 implementation diff --git a/hostapd/config.c b/hostapd/config.c index 7fceacbb8..d10d64f28 100644 --- a/hostapd/config.c +++ b/hostapd/config.c @@ -1697,6 +1697,8 @@ struct hostapd_config * hostapd_config_read(const char *fname) bss->wpa_strict_rekey = atoi(pos); } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { bss->wpa_gmk_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { + bss->wpa_ptk_rekey = atoi(pos); } else if (os_strcmp(buf, "wpa_passphrase") == 0) { int len = os_strlen(pos); if (len < 8 || len > 63) { diff --git a/hostapd/config.h b/hostapd/config.h index 5c7d04068..212e09967 100644 --- a/hostapd/config.h +++ b/hostapd/config.h @@ -223,6 +223,7 @@ struct hostapd_bss_config { int wpa_group_rekey; int wpa_strict_rekey; int wpa_gmk_rekey; + int wpa_ptk_rekey; int rsn_pairwise; int rsn_preauth; char *rsn_preauth_interfaces; diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c index e80446a7b..889f81e12 100644 --- a/hostapd/hostapd.c +++ b/hostapd/hostapd.c @@ -293,6 +293,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->wpa_group_rekey = conf->wpa_group_rekey; wconf->wpa_strict_rekey = conf->wpa_strict_rekey; wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; + wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; wconf->rsn_pairwise = conf->rsn_pairwise; wconf->rsn_preauth = conf->rsn_preauth; wconf->eapol_version = conf->eapol_version; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 898a3a3bc..599d7f1a2 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -710,6 +710,10 @@ own_ip_addr=127.0.0.1 # (in seconds). #wpa_gmk_rekey=86400 +# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of +# PTK to mitigate some attacks against TKIP deficiencies. +#wpa_ptk_rekey=600 + # Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN # authentication and key handshake before actually associating with a new AP. diff --git a/hostapd/wpa.c b/hostapd/wpa.c index c7bcac82a..cc01f0282 100644 --- a/hostapd/wpa.c +++ b/hostapd/wpa.c @@ -43,6 +43,7 @@ static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len); static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx); static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, struct wpa_group *group); +static void wpa_request_new_ptk(struct wpa_state_machine *sm); /* Default timeouts are 100 ms, but this seems to be a bit too fast for most * WPA Supplicants, so use a bit longer timeout. */ @@ -260,6 +261,17 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) } +static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct wpa_state_machine *sm = timeout_ctx; + + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK"); + wpa_request_new_ptk(sm); + wpa_sm_step(sm); +} + + static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx) { if (sm->pmksa == ctx) @@ -528,6 +540,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ @@ -1086,6 +1099,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) os_memset(&sm->PTK, 0, sizeof(sm->PTK)); wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0); sm->pairwise_set = FALSE; + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); } @@ -1553,6 +1567,13 @@ SM_STATE(WPA_PTK, PTKINITDONE) /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = TRUE; + if (sm->wpa_auth->conf.wpa_ptk_rekey) { + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); + eloop_register_timeout(sm->wpa_auth->conf. + wpa_ptk_rekey, 0, wpa_rekey_ptk, + sm->wpa_auth, sm); + } + if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_authorized, 1); diff --git a/hostapd/wpa.h b/hostapd/wpa.h index 567a8bfed..153106e1f 100644 --- a/hostapd/wpa.h +++ b/hostapd/wpa.h @@ -136,6 +136,7 @@ struct wpa_auth_config { int wpa_group_rekey; int wpa_strict_rekey; int wpa_gmk_rekey; + int wpa_ptk_rekey; int rsn_pairwise; int rsn_preauth; int eapol_version; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 5ec1dabdc..1da54f296 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -133,7 +133,6 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, * @sm: Pointer to WPA state machine data from wpa_sm_init() * @error: Indicate whether this is an Michael MIC error report * @pairwise: 1 = error report for pairwise packet, 0 = for group packet - * Returns: Pointer to the current network structure or %NULL on failure * * Send an EAPOL-Key Request to the current authenticator. This function is * used to request rekeying and it is usually called when a local Michael MIC @@ -489,6 +488,14 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, } +static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_sm *sm = eloop_ctx; + wpa_printf(MSG_DEBUG, "WPA: Request PTK rekeying"); + wpa_sm_key_request(sm, 0, 1); +} + + static int wpa_supplicant_install_ptk(struct wpa_sm *sm, const struct wpa_eapol_key *key) { @@ -533,6 +540,13 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, "driver."); return -1; } + + if (sm->wpa_ptk_rekey) { + eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); + eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, + sm, NULL); + } + return 0; } @@ -1849,6 +1863,7 @@ void wpa_sm_deinit(struct wpa_sm *sm) return; pmksa_cache_deinit(sm->pmksa); eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL); + eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); os_free(sm->assoc_wpa_ie); os_free(sm->ap_wpa_ie); os_free(sm->ap_rsn_ie); @@ -2018,6 +2033,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->ssid_len = config->ssid_len; } else sm->ssid_len = 0; + sm->wpa_ptk_rekey = config->wpa_ptk_rekey; } else { sm->network_ctx = NULL; sm->peerkey_enabled = 0; @@ -2026,6 +2042,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->eap_workaround = 0; sm->eap_conf_ctx = NULL; sm->ssid_len = 0; + sm->wpa_ptk_rekey = 0; } if (config == NULL || config->network_ctx != sm->network_ctx) pmksa_cache_notify_reconfig(sm->pmksa); diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 650e75f2c..bdf778544 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -85,6 +85,7 @@ struct rsn_supp_config { void *eap_conf_ctx; const u8 *ssid; size_t ssid_len; + int wpa_ptk_rekey; }; #ifndef CONFIG_NO_WPA diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 150515541..95348da8a 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -60,6 +60,7 @@ struct wpa_sm { void *eap_conf_ctx; u8 ssid[32]; size_t ssid_len; + int wpa_ptk_rekey; u8 own_addr[ETH_ALEN]; const char *ifname; diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog index 251e95a06..4f213fa23 100644 --- a/wpa_supplicant/ChangeLog +++ b/wpa_supplicant/ChangeLog @@ -5,6 +5,9 @@ ChangeLog for wpa_supplicant (can be used to simulate test SIM/USIM card with a known private key; enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration) + * added a new network configuration option, wpa_ptk_rekey, that can be + used to enforce frequent PTK rekeying, e.g., to mitigate some attacks + against TKIP deficiencies 2008-11-01 - v0.6.5 * added support for SHA-256 as X.509 certificate digest when using the diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index fc64be1f2..70b02c4ef 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1357,7 +1357,8 @@ static const struct parse_data ssid_fields[] = { #endif /* CONFIG_IEEE80211W */ { INT_RANGE(peerkey, 0, 1) }, { INT_RANGE(mixed_cell, 0, 1) }, - { INT_RANGE(frequency, 0, 10000) } + { INT_RANGE(frequency, 0, 10000) }, + { INT(wpa_ptk_rekey) } }; #undef OFFSET diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 5e57bc162..5510639c1 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -334,6 +334,14 @@ struct wpa_ssid { * will be used instead of this configured value. */ int frequency; + + /** + * wpa_ptk_rekey - Maximum lifetime for PTK in seconds + * + * This value can be used to enforce rekeying of PTK to mitigate some + * attacks against TKIP deficiencies. + */ + int wpa_ptk_rekey; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index b639d39f4..44dc3a17a 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -276,6 +276,9 @@ fast_reauth=1 # 1 = enabled #peerkey=1 # +# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to +# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies. +# # Following fields are only used with internal EAP implementation. # eap: space-separated list of accepted EAP methods # MD5 = EAP-MD5 (unsecure and does not generate keying material -> @@ -475,6 +478,17 @@ network={ priority=2 } +# WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying +network={ + ssid="example" + proto=WPA + key_mgmt=WPA-PSK + pairwise=TKIP + group=TKIP + psk="not so secure passphrase" + wpa_ptk_rekey=600 +} + # Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104 # or WEP40 as the group cipher will not be accepted. network={ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index f0c1cdabc..d5e31ebb0 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -626,6 +626,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, #endif /* IEEE8021X_EAPOL */ conf.ssid = ssid->ssid; conf.ssid_len = ssid->ssid_len; + conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); }