Added support for enforcing frequent PTK rekeying
authorJouni Malinen <jouni.malinen@atheros.com>
Thu, 6 Nov 2008 17:57:21 +0000 (19:57 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 6 Nov 2008 17:57:21 +0000 (19:57 +0200)
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.

15 files changed:
hostapd/ChangeLog
hostapd/config.c
hostapd/config.h
hostapd/hostapd.c
hostapd/hostapd.conf
hostapd/wpa.c
hostapd/wpa.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
src/rsn_supp/wpa_i.h
wpa_supplicant/ChangeLog
wpa_supplicant/config.c
wpa_supplicant/config_ssid.h
wpa_supplicant/wpa_supplicant.conf
wpa_supplicant/wpas_glue.c

index a8e7f4e..b2cfb5b 100644 (file)
@@ -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
index 7fceacb..d10d64f 100644 (file)
@@ -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) {
index 5c7d040..212e099 100644 (file)
@@ -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;
index e80446a..889f81e 100644 (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_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;
index 898a3a3..599d7f1 100644 (file)
@@ -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.
index c7bcac8..cc01f02 100644 (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_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);
index 567a8bf..153106e 100644 (file)
@@ -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;
index 5ec1dab..1da54f2 100644 (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()
  * @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);
index 650e75f..bdf7785 100644 (file)
@@ -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
index 1505155..95348da 100644 (file)
@@ -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;
index 251e95a..4f213fa 100644 (file)
@@ -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
index fc64be1..70b02c4 100644 (file)
@@ -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
index 5e57bc1..5510639 100644 (file)
@@ -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 */
index b639d39..44dc3a1 100644 (file)
@@ -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={
index f0c1cda..d5e31eb 100644 (file)
@@ -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);
 }