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

[PATCH] KRACK backports for 1.0 / Debian LTS



Hi,

I finalized a backport and review of the KRACK patchset against ancient
wpa code, for the Debian LTS project, which ships a modified version of
the 1.0 release. I wasn't able to track a tag or commit in the hostapd
repository that matches the code in LTS, so unfortunately those are
synthetic patches that are not directly derived from git, even though
they have headers that may look as such.

Those patches are derived from the patchset shipped in Debian
"oldstable" (jessie, wpa 2.3) as part of the coordinated release,
towards "oldoldstable" (wheezy, LTS, wpa 1.0).

https://anonscm.debian.org/cgit/collab-maint/wpa.git/tree/debian/patches/2017-1?h=debian/jessie

permalink:
https://anonscm.debian.org/cgit/collab-maint/wpa.git/tree/debian/patches/2017-1?h=debian/2.3-1%2bdeb8u5&id=5f6f0abe2bc946b23b7c679a921501bc8a17c0d7

I submit those patches here for review before an upload in Debian LTS,
but I hope those can also be useful for other providers and distributors
that ship older versions of WPA and cannot upgrade them in any practical
way.

I hope that anyone using those patches or testing the resulting binaries
will report back here (or privately) their results. My knowledge of
WPA's is somewhat limited in time and depth so I hope some more
experienced developers can look at the patchset and confirm the approach
is correct.

As I previously mentioned, I have some concerns regarding the resulting
patchset:

https://lists.debian.org/debian-lts/2017/10/msg00081.html

After a more thorough review, I am confident that removing patches 3, 6,
7 and 8 is the correct approach, as WNM sleep support is completely
missing from 1.0. I am unsure, however, whether the nonce setup in patch
#5 is correct, considering how 1.0 was doing things. In the last chunk,
you'll notice I reset peer->tk_set to negociate a new TK. The other
approach I considered was to backport 1380fcbd9f ("TDLS: Do not modify
RNonce for an TPK M1 frame with same INonce").

Updated binary and source debian packages are available for amd64 at the
following site:

https://people.debian.org/~anarcat/debian/wheezy-lts/

I'll upload i386, armel and armhf binaries as they are built.

Note that those differ from the ones posted on monday slightly: I have
modified parts of the source code after a review, so be sure to review
this version and not the previous one if you already downloaded them.

Thanks for any feedback,

A.

-- 
Evil exists to glorify the good. Evil is negative good.
It is a relative term. Evil can be transmuted into good.
What is evil to one at one time,
becomes good at another time to somebody else.
                        - Sivananda
>From fae4ceb757da370ebd1870762fd38fb39ee3d0a2 Mon Sep 17 00:00:00 2001
From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Date: Fri, 14 Jul 2017 15:15:35 +0200
Subject: [PATCH 01/10] hostapd: Avoid key reinstallation in FT handshake

Do not reinstall TK to the driver during Reassociation Response frame
processing if the first attempt of setting the TK succeeded. This avoids
issues related to clearing the TX/RX PN that could result in reusing
same PN values for transmitted frames (e.g., due to CCM nonce reuse and
also hitting replay protection on the receiver) and accepting replayed
frames on RX side.

This issue was introduced by the commit
0e84c25434e6a1f283c7b4e62e483729085b78d2 ('FT: Fix PTK configuration in
authenticator') which allowed wpa_ft_install_ptk() to be called multiple
times with the same PTK. While the second configuration attempt is
needed with some drivers, it must be done only if the first attempt
failed.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
---
 src/ap/wpa_auth.c    |  8 ++++++++
 src/ap/wpa_auth.h    |  1 +
 src/ap/wpa_auth_ft.c | 10 ++++++++++
 src/ap/wpa_auth_i.h  |  1 +
 4 files changed, 20 insertions(+)

--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2756,6 +2756,14 @@ int wpa_auth_sta_wpa_version(struct wpa_
 }
 
 
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
+{
+	if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+		return 0;
+	return sm->tk_already_set;
+}
+
+
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
 			     struct rsn_pmksa_cache_entry *entry)
 {
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -249,6 +249,7 @@ int wpa_auth_pairwise_set(struct wpa_sta
 int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
 			     struct rsn_pmksa_cache_entry *entry);
 struct rsn_pmksa_cache_entry *
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -736,6 +736,14 @@ void wpa_ft_install_ptk(struct wpa_state
 		return;
 	}
 
+	if (sm->tk_already_set) {
+		/* Must avoid TK reconfiguration to prevent clearing of TX/RX
+		 * PN in the driver */
+		wpa_printf(MSG_DEBUG,
+			   "FT: Do not re-install same PTK to the driver");
+		return;
+	}
+
 	/* FIX: add STA entry to kernel/driver here? The set_key will fail
 	 * most likely without this.. At the moment, STA entry is added only
 	 * after association has been completed. This function will be called
@@ -748,6 +756,7 @@ void wpa_ft_install_ptk(struct wpa_state
 
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
 	sm->pairwise_set = TRUE;
+	sm->tk_already_set = TRUE;
 }
 
 
@@ -861,6 +870,7 @@ static u16 wpa_ft_process_auth_req(struc
 	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
 
 	sm->pairwise = pairwise;
+        sm->tk_already_set = FALSE;
 	wpa_ft_install_ptk(sm);
 
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -67,6 +67,7 @@ struct wpa_state_machine {
 	struct wpa_ptk PTK;
 	Boolean PTK_valid;
 	Boolean pairwise_set;
+	Boolean tk_already_set;
 	int keycount;
 	Boolean Pair;
 	struct {
>From d703108d74fb1bc98f48490c513c7061dd8fbe9e Mon Sep 17 00:00:00 2001
From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Date: Wed, 12 Jul 2017 16:03:24 +0200
Subject: [PATCH 02/10] Prevent reinstallation of an already in-use group key

Track the current GTK and IGTK that is in use and when receiving a
(possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do
not install the given key if it is already in use. This prevents an
attacker from trying to trick the client into resetting or lowering the
sequence counter associated to the group key.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
---
 src/common/wpa_common.h |  11 +++++
 src/rsn_supp/wpa.c      | 116 ++++++++++++++++++++++++++++++------------------
 src/rsn_supp/wpa_i.h    |   4 ++
 3 files changed, 87 insertions(+), 44 deletions(-)

--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -107,6 +107,7 @@
 
 #ifdef CONFIG_IEEE80211W
 #define WPA_IGTK_LEN 16
+#define WPA_IGTK_MAX_LEN 32
 #endif /* CONFIG_IEEE80211W */
 
 
@@ -185,6 +186,17 @@ struct wpa_ptk {
 	} u;
 } STRUCT_PACKED;
 
+struct wpa_gtk {
+	u8 gtk[WPA_GTK_MAX_LEN];
+	size_t gtk_len;
+};
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk {
+	u8 igtk[WPA_IGTK_MAX_LEN];
+	size_t igtk_len;
+};
+#endif /* CONFIG_IEEE80211W */
 
 /* WPA IE version 1
  * 00-50-f2:1 (OUI:OUI type)
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -639,6 +639,15 @@ static int wpa_supplicant_install_gtk(st
 	const u8 *_gtk = gd->gtk;
 	u8 gtk_buf[32];
 
+	/* Detect possible key reinstallation */
+	if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
+	    os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
+			gd->keyidx, gd->tx, gd->gtk_len);
+		return 0;
+	}
+
 	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
 		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
@@ -670,6 +679,9 @@ static int wpa_supplicant_install_gtk(st
 		return -1;
 	}
 
+	sm->gtk.gtk_len = gd->gtk_len;
+	os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
+
 	return 0;
 }
 
@@ -742,6 +754,48 @@ static int wpa_supplicant_pairwise_gtk(s
 }
 
 
+#ifdef CONFIG_IEEE80211W
+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
+				       const struct wpa_igtk_kde *igtk)
+{
+	size_t len = WPA_IGTK_LEN;
+	u16 keyidx = WPA_GET_LE16(igtk->keyid);
+
+	/* Detect possible key reinstallation */
+	if (sm->igtk.igtk_len == len &&
+	    os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
+			keyidx);
+		return  0;
+	}
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+		keyidx, MAC2STR(igtk->pn));
+	wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
+	if (keyidx > 4095) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid IGTK KeyID %d", keyidx);
+		return -1;
+	}
+	if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
+			   broadcast_ether_addr,
+			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
+			   igtk->igtk, len) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to configure IGTK to the driver");
+		return -1;
+	}
+
+	sm->igtk.igtk_len = len;
+	os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
 static int ieee80211w_set_keys(struct wpa_sm *sm,
 			       struct wpa_eapol_ie_parse *ie)
 {
@@ -751,28 +805,12 @@ static int ieee80211w_set_keys(struct wp
 
 	if (ie->igtk) {
 		const struct wpa_igtk_kde *igtk;
-		u16 keyidx;
+
 		if (ie->igtk_len != sizeof(*igtk))
 			return -1;
 		igtk = (const struct wpa_igtk_kde *) ie->igtk;
-		keyidx = WPA_GET_LE16(igtk->keyid);
-		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
-			"pn %02x%02x%02x%02x%02x%02x",
-			keyidx, MAC2STR(igtk->pn));
-		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
-				igtk->igtk, WPA_IGTK_LEN);
-		if (keyidx > 4095) {
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-				"WPA: Invalid IGTK KeyID %d", keyidx);
-			return -1;
-		}
-		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
-				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-				   igtk->igtk, WPA_IGTK_LEN) < 0) {
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-				"WPA: Failed to configure IGTK to the driver");
-			return -1;
-		}
+		if (wpa_supplicant_install_igtk(sm, igtk) < 0)
+ 			return -1;
 	}
 
 	return 0;
@@ -2098,7 +2136,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
  */
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
 {
-	int clear_ptk = 1;
+	int clear_keys = 1;
 
 	if (sm == NULL)
 		return;
@@ -2124,11 +2162,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *
 		/* Prepare for the next transition */
 		wpa_ft_prepare_auth_request(sm, NULL);
 
-		clear_ptk = 0;
+		clear_keys = 0;
 	}
 #endif /* CONFIG_IEEE80211R */
 
-	if (clear_ptk) {
+	if (clear_keys) {
 		/*
 		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
 		 * this is not part of a Fast BSS Transition.
@@ -2136,6 +2174,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *
 		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
 		sm->ptk_set = 0;
 		sm->tptk_set = 0;
+		os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+#ifdef CONFIG_IEEE80211W
+		os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+#endif /* CONFIG_IEEE80211W */
 	}
 
 #ifdef CONFIG_TDLS
@@ -2640,6 +2682,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+	os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+#ifdef CONFIG_IEEE80211W
+	os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+#endif /* CONFIG_IEEE80211W */
 }
 
 
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -35,6 +35,10 @@ struct wpa_sm {
 	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int rx_replay_counter_set;
 	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+	struct wpa_gtk gtk;
+#ifdef CONFIG_IEEE80211W
+	struct wpa_igtk igtk;
+#endif /* CONFIG_IEEE80211W */
 
 	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
 
>From dd1900d11c28a968cfc0d1f92153b2789bcbd686 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@w1.fi>
Date: Sun, 1 Oct 2017 12:32:57 +0300
Subject: [PATCH 04/10] Fix PTK rekeying to generate a new ANonce

The Authenticator state machine path for PTK rekeying ended up bypassing
the AUTHENTICATION2 state where a new ANonce is generated when going
directly to the PTKSTART state since there is no need to try to
determine the PMK again in such a case. This is far from ideal since the
new PTK would depend on a new nonce only from the supplicant.

Fix this by generating a new ANonce when moving to the PTKSTART state
for the purpose of starting new 4-way handshake to rekey PTK.

Signed-off-by: Jouni Malinen <j@w1.fi>
---
 src/ap/wpa_auth.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index c2ba9a0..26b224a 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1710,6 +1710,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
 }
 
 
+static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
+{
+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_ERROR,
+			   "WPA: Failed to get random data for ANonce");
+		sm->Disconnect = TRUE;
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
+		    WPA_NONCE_LEN);
+	sm->TimeoutCtr = 0;
+	return 0;
+}
+
+
 SM_STATE(WPA_PTK, INITPMK)
 {
 	u8 msk[2 * PMK_LEN];
@@ -2221,9 +2236,12 @@ SM_STEP(WPA_PTK)
 		SM_ENTER(WPA_PTK, AUTHENTICATION);
 	else if (sm->ReAuthenticationRequest)
 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
-	else if (sm->PTKRequest)
-		SM_ENTER(WPA_PTK, PTKSTART);
-	else switch (sm->wpa_ptk_state) {
+	else if (sm->PTKRequest) {
+		if (wpa_auth_sm_ptk_update(sm) < 0)
+			SM_ENTER(WPA_PTK, DISCONNECTED);
+		else
+			SM_ENTER(WPA_PTK, PTKSTART);
+	} else switch (sm->wpa_ptk_state) {
 	case WPA_PTK_INITIALIZE:
 		break;
 	case WPA_PTK_DISCONNECT:
-- 
2.7.4

>From ce152bef7ea0a6a5ccbff073564bc0499d5b5dfb Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@w1.fi>
Date: Fri, 22 Sep 2017 11:03:15 +0300
Subject: [PATCH 05/10] TDLS: Reject TPK-TK reconfiguration

Do not try to reconfigure the same TPK-TK to the driver after it has
been successfully configured. This is an explicit check to avoid issues
related to resetting the TX/RX packet number. There was already a check
for this for TPK M2 (retries of that message are ignored completely), so
that behavior does not get modified.

For TPK M3, the TPK-TK could have been reconfigured, but that was
followed by immediate teardown of the link due to an issue in updating
the STA entry. Furthermore, for TDLS with any real security (i.e.,
ignoring open/WEP), the TPK message exchange is protected on the AP path
and simple replay attacks are not feasible.

As an additional corner case, make sure the local nonce gets updated if
the peer uses a very unlikely "random nonce" of all zeros.

Signed-off-by: Jouni Malinen <j@w1.fi>
---
 src/rsn_supp/tdls.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -109,6 +109,7 @@ struct wpa_tdls_peer {
 		u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
 	} tpk;
 	int tpk_set;
+	int tk_set; /* TPK-TK configured to the driver */
 	int tpk_success;
 
 	struct tpk_timer {
@@ -166,6 +167,20 @@ static int wpa_tdls_set_key(struct wpa_s
 	u8 rsc[6];
 	enum wpa_alg alg;
 
+	if (peer->tk_set) {
+		/*
+		 * This same TPK-TK has already been configured to the driver
+		 * and this new configuration attempt (likely due to an
+		 * unexpected retransmitted frame) would result in clearing
+		 * the TX/RX sequence number which can break security, so must
+		 * not allow that to happen.
+		 */
+		wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR
+			   " has already been configured to the driver - do not reconfigure",
+			   MAC2STR(peer->addr));
+		return -1;
+	}
+
 	os_memset(rsc, 0, 6);
 
 	switch (peer->cipher) {
@@ -183,12 +198,15 @@ static int wpa_tdls_set_key(struct wpa_s
 		return -1;
 	}
 
+	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
+		   MAC2STR(peer->addr));
 	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
 			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
 			   "driver");
 		return -1;
 	}
+	peer->tk_set = 1;
 	return 0;
 }
 
@@ -619,7 +637,7 @@ static void wpa_tdls_peer_free(struct wp
 	peer->sm_tmr.buf = NULL;
 	peer->rsnie_i_len = peer->rsnie_p_len = 0;
 	peer->cipher = 0;
-	peer->tpk_set = peer->tpk_success = 0;
+	peer->tk_set = peer->tpk_set = peer->tpk_success = 0;
 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
 	os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
@@ -1008,6 +1026,7 @@ skip_rsnie:
 		wpa_tdls_peer_free(sm, peer);
 		return -1;
 	}
+	peer->tk_set = 0; /* A new nonce results in a new TK */
 	wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake",
 		    peer->inonce, WPA_NONCE_LEN);
 	os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
@@ -1334,6 +1353,19 @@ static int copy_supp_rates(const struct
 }
 
 
+static int tdls_nonce_set(const u8 *nonce)
+{
+	int i;
+
+	for (i = 0; i < WPA_NONCE_LEN; i++) {
+		if (nonce[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1589,6 +1621,7 @@ skip_rsn:
 		wpa_tdls_peer_free(sm, peer);
 		goto error;
 	}
+	peer->tk_set = 0; /* A new nonce results in a new TK */
 
 #if 0
 	/* get version info from RSNIE received from Peer */
>From dda06c8255d189bc951d81c67d29c6a378a705ba Mon Sep 17 00:00:00 2001
From: Jouni Malinen <j@w1.fi>
Date: Fri, 22 Sep 2017 12:06:37 +0300
Subject: [PATCH 09/10] FT: Do not allow multiple Reassociation Response frames

The driver is expected to not report a second association event without
the station having explicitly request a new association. As such, this
case should not be reachable. However, since reconfiguring the same
pairwise or group keys to the driver could result in nonce reuse issues,
be extra careful here and do an additional state check to avoid this
even if the local driver ends up somehow accepting an unexpected
Reassociation Response frame.

Signed-off-by: Jouni Malinen <j@w1.fi>
---
 src/rsn_supp/wpa.c    | 3 +++
 src/rsn_supp/wpa_ft.c | 8 ++++++++
 src/rsn_supp/wpa_i.h  | 1 +
 3 files changed, 12 insertions(+)

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 1c80bf7..6df5a5f 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2236,6 +2236,9 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 #ifdef CONFIG_TDLS
 	wpa_tdls_disassoc(sm);
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_IEEE80211R
+	sm->ft_reassoc_completed = 0;
+#endif /* CONFIG_IEEE80211R */
 }
 
 
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 3b3c9d0..6d6dfab 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -156,6 +156,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
 	u16 capab;
 
 	sm->ft_completed = 0;
+	sm->ft_reassoc_completed = 0;
 
 	buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
 		2 + sm->r0kh_id_len + ric_ies_len + 100;
@@ -687,6 +688,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 		return -1;
 	}
 
+	if (sm->ft_reassoc_completed) {
+		wpa_printf(MSG_DEBUG, "FT: Reassociation has already been completed for this FT protocol instance - ignore unexpected retransmission");
+		return 0;
+	}
+
 	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
 		return -1;
@@ -787,6 +793,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 		return -1;
 	}
 
+	sm->ft_reassoc_completed = 1;
+
 	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
 		return -1;
 
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index b4885de..269e4df 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -122,6 +122,7 @@ struct wpa_sm {
 	size_t r0kh_id_len;
 	u8 r1kh_id[FT_R1KH_ID_LEN];
 	int ft_completed;
+	int ft_reassoc_completed;
 	int over_the_ds_in_progress;
 	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
 	int set_ptk_after_assoc;
-- 
2.7.4


Reply to: