summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2017-10-16 18:37:43 +0300
committerAndrew Shadura <andrewsh@debian.org>2017-11-28 12:28:13 +0100
commitefbd8aeda68d7ff5f40de41300f8ca7e3f8adbd7 (patch)
tree8d5d3624efa82ad85ce0d56a35bbad9f199bd2da
parent6a9ec3b4f808282840258f8eb291ace8d7aee94a (diff)
Optional AP side workaround for key reinstallation attacks
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> Gbp-Pq: Name wpa_disable_eapol_key_retries.patch
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/defconfig4
-rw-r--r--hostapd/hostapd.conf24
-rw-r--r--src/ap/ap_config.c6
-rw-r--r--src/ap/ap_config.h1
-rw-r--r--src/ap/wpa_auth.c22
-rw-r--r--src/ap/wpa_auth.h1
-rw-r--r--src/ap/wpa_auth_glue.c2
8 files changed, 60 insertions, 2 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 2ebf649..c92db11 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2440,6 +2440,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
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_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) {
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 4659dd1..0f665d1 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -343,3 +343,7 @@ CONFIG_IPV6=y
# a client, from which a signature can be produced which can identify the model
# of client device like "Nexus 6P" or "iPhone 5s".
#CONFIG_TAXONOMY=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
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index fa9a855..e8a56f4 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1196,6 +1196,30 @@ own_ip_addr=127.0.0.1
# PTK to mitigate some attacks against TKIP deficiencies.
#wpa_ptk_rekey=600
+# 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.
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 228de2b..732862c 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -36,6 +36,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);
@@ -55,6 +59,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ 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;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8c8f7e2..76e2670 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -324,6 +324,7 @@ struct hostapd_bss_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index bf10cc1..5c75823 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -58,6 +58,7 @@ static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
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;
@@ -1627,6 +1628,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 "
@@ -2229,6 +2233,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 > (int) dot11RSNAConfigPairwiseUpdateCount) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
@@ -2554,7 +2563,9 @@ SM_STEP(WPA_PTK)
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ (int) dot11RSNAConfigPairwiseUpdateCount ||
+ (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,
"PTKINITNEGOTIATING: Retry limit %d "
@@ -2594,6 +2605,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 > (int) dot11RSNAConfigGroupUpdateCount) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
@@ -2691,7 +2707,9 @@ SM_STEP(WPA_PTK_GROUP)
!sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
else if (sm->GTimeoutCtr >
- (int) dot11RSNAConfigGroupUpdateCount)
+ (int) dot11RSNAConfigGroupUpdateCount ||
+ (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);
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 97461b0..657b53b 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -144,6 +144,7 @@ struct wpa_auth_config {
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ int wpa_disable_eapol_key_retries;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 2142414..6ea1b4c 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -41,6 +41,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
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->wpa_disable_eapol_key_retries =
+ conf->wpa_disable_eapol_key_retries;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;