[PATCH 1/3] AP: Address PTK rekey issues

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many broken
implementations and should be avoided when using or interacting with
one.

The effects can be triggered by either end of the connection and range
from hardly noticeable disconnects over long connection freezes up to
leaking clear text MPDUs.

To allow affected users to mitigate the issues the new option
"wpa_deny_ptk0_rekey" has been added to replace all PTK0 rekeys with
disconnects.

Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
---
 hostapd/config_file.c  |  9 +++++++++
 hostapd/hostapd.conf   | 34 ++++++++++++++++++++++++++++++++++
 src/ap/ap_config.c     |  1 +
 src/ap/ap_config.h     |  1 +
 src/ap/wpa_auth.c      | 23 +++++++++++++++++++++--
 src/ap/wpa_auth.h      |  1 +
 src/ap/wpa_auth_glue.c | 14 ++++++++++++++
 src/common/defs.h      |  6 ++++++
 8 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 89e02a59a..e19653218 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2884,6 +2884,15 @@ 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_deny_ptk0_rekey") == 0) {
+		bss->wpa_deny_ptk0_rekey = atoi(pos);
+		if (bss->wpa_deny_ptk0_rekey < 0 ||
+		    bss->wpa_deny_ptk0_rekey > 2) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2",
+				   line, bss->wpa_deny_ptk0_rekey);
+			return 1;
+		}
 	} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
 		char *endp;
 		unsigned long val = strtoul(pos, &endp, 0);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 10a6291ff..bdfb62051 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -903,6 +903,8 @@ eapol_key_index_workaround=0
 
 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
 # reauthentication).
+# Reauthentications may enforce a disconnect, check the related setting
+# "wpa_deny_ptk0_rekey" for details.
 #eap_reauth_period=3600
 
 # Use PAE group address (01:80:c2:00:00:03) instead of individual target
@@ -1607,8 +1609,40 @@ own_ip_addr=127.0.0.1
 
 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
 # PTK to mitigate some attacks against TKIP deficiencies.
+# Warning: PTK rekeying is buggy with many drivers/devices and the only secure
+# method to rekey the PTK without Extended Key ID support requires a disconnect.
+# Check the related setting "wpa_deny_ptk0_rekey" for details.
 #wpa_ptk_rekey=600
 
+# Workaround for PTK rekey issues
+#
+# Rekeying the PTK without using "Extended Key ID for Individually Addressed
+# Frames" can - depending on the used cards/drivers - impact the security and
+# stability of connections. Both ends can accidentally trick one end to drop
+# all packets send by it till the connection is torn down or rekeyed again.
+# Additionally some drivers may skip/break the encryption for the time window
+# the key is updated (normally a few ms).
+#
+# To avoid the issues hostapd can now replace all PTK rekeys using only keyid 0
+# (PTK0 rekeys) with disconnects and forcing the remote stations to reconnect
+# instead.
+#
+# Eap reauthentication depends on replacing the PTK and is therefore just
+# another way to rekey the PTK and affected by the setting, too.
+#
+# "Extended Key ID for Individually Addressed Frames" is avoiding the issues
+# and the setting will be ignored when using it.
+#
+# If you your cards/drivers - either local or remote - need the workaround for
+# PTK0 rekeys you must set "wpa_deny_ptk0_rekey = 0" or - if you want to allow
+# it when the local system is known to be ok - "wpa_deny_ptk0_rekey = 1".
+#
+# Available options:
+# 0 = always rekey when configured/instructed (default)
+# 1 = only rekey when the local driver is able to do it bug free
+# 2 = never allow PTK0 rekeys
+# wpa_deny_ptk0_rekey = 2
+
 # The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
 # Handshake are retried per 4-Way Handshake attempt.
 # (dot11RSNAConfigPairwiseUpdateCount)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cc041441c..0142c87b0 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -64,6 +64,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
 	bss->wpa_group_rekey = 600;
 	bss->wpa_gmk_rekey = 86400;
+	bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
 	bss->wpa_group_update_count = 4;
 	bss->wpa_pairwise_update_count = 4;
 	bss->wpa_disable_eapol_key_retries =
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 1efdc2b43..db8745be7 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -368,6 +368,7 @@ struct hostapd_bss_config {
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	int wpa_deny_ptk0_rekey;
 	u32 wpa_group_update_count;
 	u32 wpa_pairwise_update_count;
 	int wpa_disable_eapol_key_retries;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 423528d12..f3d7b4a87 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -780,8 +780,17 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 	if (sm == NULL)
 		return;
 
-	sm->PTKRequest = TRUE;
-	sm->PTK_valid = 0;
+	if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+		wpa_printf(MSG_WARNING,
+			   "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+			   MAC2STR(sm->addr));
+		sm->Disconnect = TRUE;
+		/* Try to encourage the STA to reconnect */
+		sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+	} else {
+		sm->PTKRequest = TRUE;
+		sm->PTK_valid = 0;
+	}
 }
 
 
@@ -1800,6 +1809,16 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
 			sm->Init = FALSE;
 			sm->AuthenticationRequest = TRUE;
 			break;
+		} else {
+			if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+				wpa_printf(MSG_WARNING,
+					   "WPA: PTK0 rekey not allowed, disconnect "
+					   MACSTR, MAC2STR(sm->addr));
+				sm->Disconnect = TRUE;
+				/* Try to encourage the STA reconnect */
+				sm->disconnect_reason = WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+				break;
+			}
 		}
 		if (sm->GUpdateStationKeys) {
 			/*
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 0b4b7297c..5705694ae 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -176,6 +176,7 @@ struct wpa_auth_config {
 	int wpa_strict_rekey;
 	int wpa_gmk_rekey;
 	int wpa_ptk_rekey;
+	int wpa_deny_ptk0_rekey;
 	u32 wpa_group_update_count;
 	u32 wpa_pairwise_update_count;
 	int wpa_disable_eapol_key_retries;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index e64304636..156e71ae6 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1370,6 +1370,20 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 		_conf.tx_status = 1;
 	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
 		_conf.ap_mlme = 1;
+
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) &&
+	    (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER ||
+	     (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK &&
+	      !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			"Disable PTK0 rekey support - replaced with disconnect");
+		_conf.wpa_deny_ptk0_rekey = 1;
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_WARNING,
+			"Support PTK0 rekey - may randomly break connections");
+		_conf.wpa_deny_ptk0_rekey = 0;
+	}
+
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
 	if (hapd->wpa_auth == NULL) {
 		wpa_printf(MSG_ERROR, "WPA initialization failed.");
diff --git a/src/common/defs.h b/src/common/defs.h
index 5e22278e6..1e21ec2de 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -445,4 +445,10 @@ enum key_flag {
 					  KEY_FLAG_MODIFY,
 };
 
+enum ptk0_rekey_handling {
+	PTK0_REKEY_ALLOW_ALWAYS,
+	PTK0_REKEY_ALLOW_LOCAL_OK,
+	PTK0_REKEY_ALLOW_NEVER
+};
+
 #endif /* DEFS_H */
-- 
2.24.1


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux