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) {
# 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
# 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.
}
+#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);
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;
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;
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;
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 "
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. */
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,
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. */
!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);
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;
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;