Blame rebased-v2.6-0002-Prevent-reinstallation-of-an-already-in-use-group-ke.patch

fbf8c1b
From 927f891007c402fefd1ff384645b3f07597c3ede Mon Sep 17 00:00:00 2001
fbf8c1b
From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
fbf8c1b
Date: Wed, 12 Jul 2017 16:03:24 +0200
fbf8c1b
Subject: [PATCH 2/8] Prevent reinstallation of an already in-use group key
fbf8c1b
fbf8c1b
Track the current GTK and IGTK that is in use and when receiving a
fbf8c1b
(possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do
fbf8c1b
not install the given key if it is already in use. This prevents an
fbf8c1b
attacker from trying to trick the client into resetting or lowering the
fbf8c1b
sequence counter associated to the group key.
fbf8c1b
fbf8c1b
Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
fbf8c1b
---
fbf8c1b
 src/common/wpa_common.h |  11 +++++
fbf8c1b
 src/rsn_supp/wpa.c      | 116 ++++++++++++++++++++++++++++++------------------
fbf8c1b
 src/rsn_supp/wpa_i.h    |   4 ++
fbf8c1b
 3 files changed, 87 insertions(+), 44 deletions(-)
fbf8c1b
fbf8c1b
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
fbf8c1b
index af1d0f0..d200285 100644
fbf8c1b
--- a/src/common/wpa_common.h
fbf8c1b
+++ b/src/common/wpa_common.h
fbf8c1b
@@ -217,6 +217,17 @@ struct wpa_ptk {
fbf8c1b
 	size_t tk_len;
fbf8c1b
 };
fbf8c1b
 
fbf8c1b
+struct wpa_gtk {
fbf8c1b
+	u8 gtk[WPA_GTK_MAX_LEN];
fbf8c1b
+	size_t gtk_len;
fbf8c1b
+};
fbf8c1b
+
fbf8c1b
+#ifdef CONFIG_IEEE80211W
fbf8c1b
+struct wpa_igtk {
fbf8c1b
+	u8 igtk[WPA_IGTK_MAX_LEN];
fbf8c1b
+	size_t igtk_len;
fbf8c1b
+};
fbf8c1b
+#endif /* CONFIG_IEEE80211W */
fbf8c1b
 
fbf8c1b
 /* WPA IE version 1
fbf8c1b
  * 00-50-f2:1 (OUI:OUI type)
fbf8c1b
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
fbf8c1b
index 3c47879..95bd7be 100644
fbf8c1b
--- a/src/rsn_supp/wpa.c
fbf8c1b
+++ b/src/rsn_supp/wpa.c
fbf8c1b
@@ -714,6 +714,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
fbf8c1b
 	const u8 *_gtk = gd->gtk;
fbf8c1b
 	u8 gtk_buf[32];
fbf8c1b
 
fbf8c1b
+	/* Detect possible key reinstallation */
fbf8c1b
+	if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
fbf8c1b
+	    os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
fbf8c1b
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
fbf8c1b
+			"WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
fbf8c1b
+			gd->keyidx, gd->tx, gd->gtk_len);
fbf8c1b
+		return 0;
fbf8c1b
+	}
fbf8c1b
+
fbf8c1b
 	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
fbf8c1b
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
fbf8c1b
 		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
fbf8c1b
@@ -748,6 +757,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
fbf8c1b
 	}
fbf8c1b
 	os_memset(gtk_buf, 0, sizeof(gtk_buf));
fbf8c1b
 
fbf8c1b
+	sm->gtk.gtk_len = gd->gtk_len;
fbf8c1b
+	os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
fbf8c1b
+
fbf8c1b
 	return 0;
fbf8c1b
 }
fbf8c1b
 
fbf8c1b
@@ -854,6 +866,48 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
fbf8c1b
 }
fbf8c1b
 
fbf8c1b
 
fbf8c1b
+#ifdef CONFIG_IEEE80211W
fbf8c1b
+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
fbf8c1b
+				       const struct wpa_igtk_kde *igtk)
fbf8c1b
+{
fbf8c1b
+	size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
fbf8c1b
+	u16 keyidx = WPA_GET_LE16(igtk->keyid);
fbf8c1b
+
fbf8c1b
+	/* Detect possible key reinstallation */
fbf8c1b
+	if (sm->igtk.igtk_len == len &&
fbf8c1b
+	    os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
fbf8c1b
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
fbf8c1b
+			"WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
fbf8c1b
+			keyidx);
fbf8c1b
+		return  0;
fbf8c1b
+	}
fbf8c1b
+
fbf8c1b
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
fbf8c1b
+		"WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
fbf8c1b
+		keyidx, MAC2STR(igtk->pn));
fbf8c1b
+	wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
fbf8c1b
+	if (keyidx > 4095) {
fbf8c1b
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
fbf8c1b
+			"WPA: Invalid IGTK KeyID %d", keyidx);
fbf8c1b
+		return -1;
fbf8c1b
+	}
fbf8c1b
+	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
fbf8c1b
+			   broadcast_ether_addr,
fbf8c1b
+			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
fbf8c1b
+			   igtk->igtk, len) < 0) {
fbf8c1b
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
fbf8c1b
+			"WPA: Failed to configure IGTK to the driver");
fbf8c1b
+		return -1;
fbf8c1b
+	}
fbf8c1b
+
fbf8c1b
+	sm->igtk.igtk_len = len;
fbf8c1b
+	os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
fbf8c1b
+
fbf8c1b
+	return 0;
fbf8c1b
+}
fbf8c1b
+#endif /* CONFIG_IEEE80211W */
fbf8c1b
+
fbf8c1b
+
fbf8c1b
 static int ieee80211w_set_keys(struct wpa_sm *sm,
fbf8c1b
 			       struct wpa_eapol_ie_parse *ie)
fbf8c1b
 {
fbf8c1b
@@ -864,30 +918,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
fbf8c1b
 	if (ie->igtk) {
fbf8c1b
 		size_t len;
fbf8c1b
 		const struct wpa_igtk_kde *igtk;
fbf8c1b
-		u16 keyidx;
fbf8c1b
+
fbf8c1b
 		len = wpa_cipher_key_len(sm->mgmt_group_cipher);
fbf8c1b
 		if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
fbf8c1b
 			return -1;
fbf8c1b
+
fbf8c1b
 		igtk = (const struct wpa_igtk_kde *) ie->igtk;
fbf8c1b
-		keyidx = WPA_GET_LE16(igtk->keyid);
fbf8c1b
-		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
fbf8c1b
-			"pn %02x%02x%02x%02x%02x%02x",
fbf8c1b
-			keyidx, MAC2STR(igtk->pn));
fbf8c1b
-		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
fbf8c1b
-				igtk->igtk, len);
fbf8c1b
-		if (keyidx > 4095) {
fbf8c1b
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
fbf8c1b
-				"WPA: Invalid IGTK KeyID %d", keyidx);
fbf8c1b
-			return -1;
fbf8c1b
-		}
fbf8c1b
-		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
fbf8c1b
-				   broadcast_ether_addr,
fbf8c1b
-				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
fbf8c1b
-				   igtk->igtk, len) < 0) {
fbf8c1b
-			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
fbf8c1b
-				"WPA: Failed to configure IGTK to the driver");
fbf8c1b
+		if (wpa_supplicant_install_igtk(sm, igtk) < 0)
fbf8c1b
 			return -1;
fbf8c1b
-		}
fbf8c1b
 	}
fbf8c1b
 
fbf8c1b
 	return 0;
fbf8c1b
@@ -2307,7 +2345,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
fbf8c1b
  */
fbf8c1b
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
fbf8c1b
 {
fbf8c1b
-	int clear_ptk = 1;
fbf8c1b
+	int clear_keys = 1;
fbf8c1b
 
fbf8c1b
 	if (sm == NULL)
fbf8c1b
 		return;
fbf8c1b
@@ -2333,11 +2371,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
fbf8c1b
 		/* Prepare for the next transition */
fbf8c1b
 		wpa_ft_prepare_auth_request(sm, NULL);
fbf8c1b
 
fbf8c1b
-		clear_ptk = 0;
fbf8c1b
+		clear_keys = 0;
fbf8c1b
 	}
fbf8c1b
 #endif /* CONFIG_IEEE80211R */
fbf8c1b
 
fbf8c1b
-	if (clear_ptk) {
fbf8c1b
+	if (clear_keys) {
fbf8c1b
 		/*
fbf8c1b
 		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
fbf8c1b
 		 * this is not part of a Fast BSS Transition.
fbf8c1b
@@ -2347,6 +2385,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
fbf8c1b
 		os_memset(&sm->ptk, 0, sizeof(sm->ptk));
fbf8c1b
 		sm->tptk_set = 0;
fbf8c1b
 		os_memset(&sm->tptk, 0, sizeof(sm->tptk));
fbf8c1b
+		os_memset(&sm->gtk, 0, sizeof(sm->gtk));
fbf8c1b
+#ifdef CONFIG_IEEE80211W
fbf8c1b
+		os_memset(&sm->igtk, 0, sizeof(sm->igtk));
fbf8c1b
+#endif /* CONFIG_IEEE80211W */
fbf8c1b
 	}
fbf8c1b
 
fbf8c1b
 #ifdef CONFIG_TDLS
fbf8c1b
@@ -2877,6 +2919,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
fbf8c1b
 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
fbf8c1b
 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
fbf8c1b
 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
fbf8c1b
+	os_memset(&sm->gtk, 0, sizeof(sm->gtk));
fbf8c1b
+#ifdef CONFIG_IEEE80211W
fbf8c1b
+	os_memset(&sm->igtk, 0, sizeof(sm->igtk));
fbf8c1b
+#endif /* CONFIG_IEEE80211W */
fbf8c1b
 #ifdef CONFIG_IEEE80211R
fbf8c1b
 	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
fbf8c1b
 	os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
fbf8c1b
@@ -2949,29 +2995,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
fbf8c1b
 		os_memset(&gd, 0, sizeof(gd));
fbf8c1b
 #ifdef CONFIG_IEEE80211W
fbf8c1b
 	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
fbf8c1b
-		struct wpa_igtk_kde igd;
fbf8c1b
-		u16 keyidx;
fbf8c1b
-
fbf8c1b
-		os_memset(&igd, 0, sizeof(igd));
fbf8c1b
-		keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
fbf8c1b
-		os_memcpy(igd.keyid, buf + 2, 2);
fbf8c1b
-		os_memcpy(igd.pn, buf + 4, 6);
fbf8c1b
-
fbf8c1b
-		keyidx = WPA_GET_LE16(igd.keyid);
fbf8c1b
-		os_memcpy(igd.igtk, buf + 10, keylen);
fbf8c1b
-
fbf8c1b
-		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
fbf8c1b
-				igd.igtk, keylen);
fbf8c1b
-		if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
fbf8c1b
-				   broadcast_ether_addr,
fbf8c1b
-				   keyidx, 0, igd.pn, sizeof(igd.pn),
fbf8c1b
-				   igd.igtk, keylen) < 0) {
fbf8c1b
-			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
fbf8c1b
-				   "WNM mode");
fbf8c1b
-			os_memset(&igd, 0, sizeof(igd));
fbf8c1b
+		const struct wpa_igtk_kde *igtk;
fbf8c1b
+
fbf8c1b
+		igtk = (const struct wpa_igtk_kde *) (buf + 2);
fbf8c1b
+		if (wpa_supplicant_install_igtk(sm, igtk) < 0)
fbf8c1b
 			return -1;
fbf8c1b
-		}
fbf8c1b
-		os_memset(&igd, 0, sizeof(igd));
fbf8c1b
 #endif /* CONFIG_IEEE80211W */
fbf8c1b
 	} else {
fbf8c1b
 		wpa_printf(MSG_DEBUG, "Unknown element id");
fbf8c1b
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
fbf8c1b
index f653ba6..afc9e37 100644
fbf8c1b
--- a/src/rsn_supp/wpa_i.h
fbf8c1b
+++ b/src/rsn_supp/wpa_i.h
fbf8c1b
@@ -31,6 +31,10 @@ struct wpa_sm {
fbf8c1b
 	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
fbf8c1b
 	int rx_replay_counter_set;
fbf8c1b
 	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
fbf8c1b
+	struct wpa_gtk gtk;
fbf8c1b
+#ifdef CONFIG_IEEE80211W
fbf8c1b
+	struct wpa_igtk igtk;
fbf8c1b
+#endif /* CONFIG_IEEE80211W */
fbf8c1b
 
fbf8c1b
 	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
fbf8c1b
 
fbf8c1b
-- 
fbf8c1b
2.7.4
fbf8c1b