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.
This commit is contained in:
Jouni Malinen 2008-11-06 19:57:21 +02:00 committed by Jouni Malinen
parent 81eec387dd
commit 581a8cde77
15 changed files with 83 additions and 2 deletions

View file

@ -1,5 +1,10 @@
ChangeLog for hostapd 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 2008-11-01 - v0.6.5
* added support for SHA-256 as X.509 certificate digest when using the * added support for SHA-256 as X.509 certificate digest when using the
internal X.509/TLSv1 implementation internal X.509/TLSv1 implementation

View file

@ -1697,6 +1697,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
bss->wpa_strict_rekey = atoi(pos); bss->wpa_strict_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
bss->wpa_gmk_rekey = atoi(pos); 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) { } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
int len = os_strlen(pos); int len = os_strlen(pos);
if (len < 8 || len > 63) { if (len < 8 || len > 63) {

View file

@ -223,6 +223,7 @@ struct hostapd_bss_config {
int wpa_group_rekey; int wpa_group_rekey;
int wpa_strict_rekey; int wpa_strict_rekey;
int wpa_gmk_rekey; int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise; int rsn_pairwise;
int rsn_preauth; int rsn_preauth;
char *rsn_preauth_interfaces; char *rsn_preauth_interfaces;

View file

@ -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_group_rekey = conf->wpa_group_rekey;
wconf->wpa_strict_rekey = conf->wpa_strict_rekey; wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_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_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth; wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version; wconf->eapol_version = conf->eapol_version;

View file

@ -710,6 +710,10 @@ own_ip_addr=127.0.0.1
# (in seconds). # (in seconds).
#wpa_gmk_rekey=86400 #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 # 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 # roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
# authentication and key handshake before actually associating with a new AP. # authentication and key handshake before actually associating with a new AP.

View file

@ -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_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group); 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 /* Default timeouts are 100 ms, but this seems to be a bit too fast for most
* WPA Supplicants, so use a bit longer timeout. */ * 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) static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
{ {
if (sm->pmksa == 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_send_eapol_timeout, sm->wpa_auth, sm);
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
if (sm->in_step_loop) { if (sm->in_step_loop) {
/* Must not free state machine while wpa_sm_step() is running. /* Must not free state machine while wpa_sm_step() is running.
* Freeing will be completed in the end of wpa_sm_step(). */ * 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)); os_memset(&sm->PTK, 0, sizeof(sm->PTK));
wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0); wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0);
sm->pairwise_set = FALSE; 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) */ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE; 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)) { if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
wpa_auth_set_eapol(sm->wpa_auth, sm->addr, wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
WPA_EAPOL_authorized, 1); WPA_EAPOL_authorized, 1);

View file

@ -136,6 +136,7 @@ struct wpa_auth_config {
int wpa_group_rekey; int wpa_group_rekey;
int wpa_strict_rekey; int wpa_strict_rekey;
int wpa_gmk_rekey; int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise; int rsn_pairwise;
int rsn_preauth; int rsn_preauth;
int eapol_version; int eapol_version;

View file

@ -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() * @sm: Pointer to WPA state machine data from wpa_sm_init()
* @error: Indicate whether this is an Michael MIC error report * @error: Indicate whether this is an Michael MIC error report
* @pairwise: 1 = error report for pairwise packet, 0 = for group packet * @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 * 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 * 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, static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
const struct wpa_eapol_key *key) const struct wpa_eapol_key *key)
{ {
@ -533,6 +540,13 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
"driver."); "driver.");
return -1; 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; return 0;
} }
@ -1849,6 +1863,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
return; return;
pmksa_cache_deinit(sm->pmksa); pmksa_cache_deinit(sm->pmksa);
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL); 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->assoc_wpa_ie);
os_free(sm->ap_wpa_ie); os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_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; sm->ssid_len = config->ssid_len;
} else } else
sm->ssid_len = 0; sm->ssid_len = 0;
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
} else { } else {
sm->network_ctx = NULL; sm->network_ctx = NULL;
sm->peerkey_enabled = 0; 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_workaround = 0;
sm->eap_conf_ctx = NULL; sm->eap_conf_ctx = NULL;
sm->ssid_len = 0; sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
} }
if (config == NULL || config->network_ctx != sm->network_ctx) if (config == NULL || config->network_ctx != sm->network_ctx)
pmksa_cache_notify_reconfig(sm->pmksa); pmksa_cache_notify_reconfig(sm->pmksa);

View file

@ -85,6 +85,7 @@ struct rsn_supp_config {
void *eap_conf_ctx; void *eap_conf_ctx;
const u8 *ssid; const u8 *ssid;
size_t ssid_len; size_t ssid_len;
int wpa_ptk_rekey;
}; };
#ifndef CONFIG_NO_WPA #ifndef CONFIG_NO_WPA

View file

@ -60,6 +60,7 @@ struct wpa_sm {
void *eap_conf_ctx; void *eap_conf_ctx;
u8 ssid[32]; u8 ssid[32];
size_t ssid_len; size_t ssid_len;
int wpa_ptk_rekey;
u8 own_addr[ETH_ALEN]; u8 own_addr[ETH_ALEN];
const char *ifname; const char *ifname;

View file

@ -5,6 +5,9 @@ ChangeLog for wpa_supplicant
(can be used to simulate test SIM/USIM card with a known private key; (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 enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config
and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration) 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 2008-11-01 - v0.6.5
* added support for SHA-256 as X.509 certificate digest when using the * added support for SHA-256 as X.509 certificate digest when using the

View file

@ -1357,7 +1357,8 @@ static const struct parse_data ssid_fields[] = {
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
{ INT_RANGE(peerkey, 0, 1) }, { INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 10000) } { INT_RANGE(frequency, 0, 10000) },
{ INT(wpa_ptk_rekey) }
}; };
#undef OFFSET #undef OFFSET

View file

@ -334,6 +334,14 @@ struct wpa_ssid {
* will be used instead of this configured value. * will be used instead of this configured value.
*/ */
int frequency; 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 */ #endif /* CONFIG_SSID_H */

View file

@ -276,6 +276,9 @@ fast_reauth=1
# 1 = enabled # 1 = enabled
#peerkey=1 #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. # Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods # eap: space-separated list of accepted EAP methods
# MD5 = EAP-MD5 (unsecure and does not generate keying material -> # MD5 = EAP-MD5 (unsecure and does not generate keying material ->
@ -475,6 +478,17 @@ network={
priority=2 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 # 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. # or WEP40 as the group cipher will not be accepted.
network={ network={

View file

@ -626,6 +626,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
#endif /* IEEE8021X_EAPOL */ #endif /* IEEE8021X_EAPOL */
conf.ssid = ssid->ssid; conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len; conf.ssid_len = ssid->ssid_len;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
} }
wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
} }