]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Optional AP side workaround for key reinstallation attacks
authorJouni Malinen <j@w1.fi>
Mon, 16 Oct 2017 15:37:43 +0000 (18:37 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 16 Oct 2017 21:06:26 +0000 (00:06 +0300)
This adds a new hostapd configuration parameter
wpa_disable_eapol_key_retries=1 that can be used to disable
retransmission of EAPOL-Key frames that are used to install
keys (EAPOL-Key message 3/4 and group message 1/2). This is
similar to setting wpa_group_update_count=1 and
wpa_pairwise_update_count=1, but with no impact to message 1/4
retries and with extended timeout for messages 4/4 and group
message 2/2 to avoid causing issues with stations that may use
aggressive power saving have very long time in replying to the
EAPOL-Key messages.

This option can be used to work around key reinstallation attacks
on the station (supplicant) side in cases those station devices
cannot be updated for some reason. By removing the
retransmissions the attacker cannot cause key reinstallation with
a delayed frame transmission. This is related to the station side
vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
CVE-2017-13080, and CVE-2017-13081.

This workaround might cause interoperability issues and reduced
robustness of key negotiation especially in environments with
heavy traffic load due to the number of attempts to perform the
key exchange is reduced significantly. As such, this workaround
is disabled by default (unless overridden in build
configuration). To enable this, set the parameter to 1.

It is also possible to enable this in the build by default by
adding the following to the build configuration:

CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1

Signed-off-by: Jouni Malinen <j@w1.fi>
hostapd/config_file.c
hostapd/defconfig
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c

index d6b1a65796107ec912b92d0db1d8c9699094105b..e2a470c5ba4e4ec18455398c692bf32543e77b07 100644 (file)
@@ -2570,6 +2570,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
                bss->wpa_pairwise_update_count = (u32) val;
+       } else if (os_strcmp(buf, "wpa_disable_eapol_key_retries") == 0) {
+               bss->wpa_disable_eapol_key_retries = atoi(pos);
        } else if (os_strcmp(buf, "wpa_passphrase") == 0) {
                int len = os_strlen(pos);
                if (len < 8 || len > 63) {
index 9e7c480c766017bda18fd38754afb1e68e2be137..c67c6622d6efae1f9affb73ce16e08c6a536d312 100644 (file)
@@ -369,3 +369,7 @@ CONFIG_IPV6=y
 # Opportunistic Wireless Encryption (OWE)
 # Experimental implementation of draft-harkins-owe-07.txt
 #CONFIG_OWE=y
+
+# Override default value for the wpa_disable_eapol_key_retries configuration
+# parameter. See that parameter in hostapd.conf for more details.
+#CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1
index c664df6f6c3e588d08cb51eb17a3deace7d791ed..f5588551e95333f31f4e6803e7a2d9c66dbb2741 100644 (file)
@@ -1315,6 +1315,30 @@ own_ip_addr=127.0.0.1
 # Range 1..4294967295; default: 4
 #wpa_pairwise_update_count=4
 
+# Workaround for key reinstallation attacks
+#
+# This parameter can be used to disable retransmission of EAPOL-Key frames that
+# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
+# is similar to setting wpa_group_update_count=1 and
+# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
+# extended timeout on the response to avoid causing issues with stations that
+# may use aggressive power saving have very long time in replying to the
+# EAPOL-Key messages.
+#
+# This option can be used to work around key reinstallation attacks on the
+# station (supplicant) side in cases those station devices cannot be updated
+# for some reason. By removing the retransmissions the attacker cannot cause
+# key reinstallation with a delayed frame transmission. This is related to the
+# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
+# CVE-2017-13080, and CVE-2017-13081.
+#
+# This workaround might cause interoperability issues and reduced robustness of
+# key negotiation especially in environments with heavy traffic load due to the
+# number of attempts to perform the key exchange is reduced significantly. As
+# such, this workaround is disabled by default (unless overridden in build
+# configuration). To enable this, set the parameter to 1.
+#wpa_disable_eapol_key_retries=1
+
 # 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 10cacfb8ab9fdca7dabe030dbfc26699cc2a7ac7..07310f93c33b52e6fc781fb83bb793e7a21d4eab 100644 (file)
@@ -37,6 +37,10 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
 }
 
 
+#ifndef DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES
+#define DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES 0
+#endif /* DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES */
+
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 {
        dl_list_init(&bss->anqp_elem);
@@ -58,6 +62,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
        bss->wpa_gmk_rekey = 86400;
        bss->wpa_group_update_count = 4;
        bss->wpa_pairwise_update_count = 4;
+       bss->wpa_disable_eapol_key_retries =
+               DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
        bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
        bss->wpa_pairwise = WPA_CIPHER_TKIP;
        bss->wpa_group = WPA_CIPHER_TKIP;
index d4bc3a601635293edc977d0e5148f4473e510d0d..89bf2895eb70525694e55cc3a115cb68d3bd5283 100644 (file)
@@ -333,6 +333,7 @@ struct hostapd_bss_config {
        int wpa_ptk_rekey;
        u32 wpa_group_update_count;
        u32 wpa_pairwise_update_count;
+       int wpa_disable_eapol_key_retries;
        int rsn_pairwise;
        int rsn_preauth;
        char *rsn_preauth_interfaces;
index 039c55e733f134a15cae5143d5f6ca0d7f411a32..aea29b5eaac033b900de91d0b6eb30cfe0ede025 100644 (file)
@@ -65,6 +65,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
 static const u32 eapol_key_timeout_first_group = 500; /* ms */
+static const u32 eapol_key_timeout_no_retrans = 4000; /* ms */
 
 /* TODO: make these configurable */
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -1604,6 +1605,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                        eapol_key_timeout_first_group;
        else
                timeout_ms = eapol_key_timeout_subseq;
+       if (wpa_auth->conf.wpa_disable_eapol_key_retries &&
+           (!pairwise || (key_info & WPA_KEY_INFO_MIC)))
+               timeout_ms = eapol_key_timeout_no_retrans;
        if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
                sm->pending_1_of_4_timeout = 1;
        wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
@@ -2855,6 +2859,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        sm->TimeoutEvt = FALSE;
 
        sm->TimeoutCtr++;
+       if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+           sm->TimeoutCtr > 1) {
+               /* Do not allow retransmission of EAPOL-Key msg 3/4 */
+               return;
+       }
        if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
                /* No point in sending the EAPOL-Key - we will disconnect
                 * immediately following this. */
@@ -3197,7 +3206,9 @@ SM_STEP(WPA_PTK)
                         sm->EAPOLKeyPairwise && sm->MICVerified)
                        SM_ENTER(WPA_PTK, PTKINITDONE);
                else if (sm->TimeoutCtr >
-                        sm->wpa_auth->conf.wpa_pairwise_update_count) {
+                        sm->wpa_auth->conf.wpa_pairwise_update_count ||
+                        (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+                         sm->TimeoutCtr > 1)) {
                        wpa_auth->dot11RSNA4WayHandshakeFailures++;
                        wpa_auth_vlogger(
                                sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -3237,6 +3248,11 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
 
        sm->GTimeoutCtr++;
+       if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+           sm->GTimeoutCtr > 1) {
+               /* Do not allow retransmission of EAPOL-Key group msg 1/2 */
+               return;
+       }
        if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
                /* No point in sending the EAPOL-Key - we will disconnect
                 * immediately following this. */
@@ -3340,7 +3356,9 @@ SM_STEP(WPA_PTK_GROUP)
                    !sm->EAPOLKeyPairwise && sm->MICVerified)
                        SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
                else if (sm->GTimeoutCtr >
-                        sm->wpa_auth->conf.wpa_group_update_count)
+                        sm->wpa_auth->conf.wpa_group_update_count ||
+                        (sm->wpa_auth->conf.wpa_disable_eapol_key_retries &&
+                         sm->GTimeoutCtr > 1))
                        SM_ENTER(WPA_PTK_GROUP, KEYERROR);
                else if (sm->TimeoutEvt)
                        SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
index 38d9e7eab255b5483fd997ea2416b380d3f9863f..be1a1822cc970914c286bf209bb08e1d93aa2df4 100644 (file)
@@ -165,6 +165,7 @@ struct wpa_auth_config {
        int wpa_ptk_rekey;
        u32 wpa_group_update_count;
        u32 wpa_pairwise_update_count;
+       int wpa_disable_eapol_key_retries;
        int rsn_pairwise;
        int rsn_preauth;
        int eapol_version;
index d9f917e4a528eafffd478ac73a31d9e56a08a246..98133a087ba90937bc2b8385632a483f679c461f 100644 (file)
@@ -46,6 +46,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
        wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
        wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
        wconf->wpa_group_update_count = conf->wpa_group_update_count;
+       wconf->wpa_disable_eapol_key_retries =
+               conf->wpa_disable_eapol_key_retries;
        wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
        wconf->rsn_pairwise = conf->rsn_pairwise;
        wconf->rsn_preauth = conf->rsn_preauth;