Blame SOURCES/rh1495527-0001-hostapd-Avoid-key-reinstallation-in-FT-handshake.patch

92bdd1
From cf4cab804c7afd5c45505528a8d16e46163243a2 Mon Sep 17 00:00:00 2001
92bdd1
From: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
92bdd1
Date: Fri, 14 Jul 2017 15:15:35 +0200
92bdd1
Subject: [PATCH 1/8] hostapd: Avoid key reinstallation in FT handshake
92bdd1
92bdd1
Do not reinstall TK to the driver during Reassociation Response frame
92bdd1
processing if the first attempt of setting the TK succeeded. This avoids
92bdd1
issues related to clearing the TX/RX PN that could result in reusing
92bdd1
same PN values for transmitted frames (e.g., due to CCM nonce reuse and
92bdd1
also hitting replay protection on the receiver) and accepting replayed
92bdd1
frames on RX side.
92bdd1
92bdd1
This issue was introduced by the commit
92bdd1
0e84c25434e6a1f283c7b4e62e483729085b78d2 ('FT: Fix PTK configuration in
92bdd1
authenticator') which allowed wpa_ft_install_ptk() to be called multiple
92bdd1
times with the same PTK. While the second configuration attempt is
92bdd1
needed with some drivers, it must be done only if the first attempt
92bdd1
failed.
92bdd1
92bdd1
Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
92bdd1
---
92bdd1
 src/ap/ieee802_11.c  | 16 +++++++++++++---
92bdd1
 src/ap/wpa_auth.c    | 11 +++++++++++
92bdd1
 src/ap/wpa_auth.h    |  3 ++-
92bdd1
 src/ap/wpa_auth_ft.c | 10 ++++++++++
92bdd1
 src/ap/wpa_auth_i.h  |  1 +
92bdd1
 5 files changed, 37 insertions(+), 4 deletions(-)
92bdd1
92bdd1
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
92bdd1
index 4e04169..333035f 100644
92bdd1
--- a/src/ap/ieee802_11.c
92bdd1
+++ b/src/ap/ieee802_11.c
92bdd1
@@ -1841,6 +1841,7 @@ static int add_associated_sta(struct hostapd_data *hapd,
92bdd1
 {
92bdd1
 	struct ieee80211_ht_capabilities ht_cap;
92bdd1
 	struct ieee80211_vht_capabilities vht_cap;
92bdd1
+	int set = 1;
92bdd1
 
92bdd1
 	/*
92bdd1
 	 * Remove the STA entry to ensure the STA PS state gets cleared and
92bdd1
@@ -1848,9 +1849,18 @@ static int add_associated_sta(struct hostapd_data *hapd,
92bdd1
 	 * FT-over-the-DS, where a station re-associates back to the same AP but
92bdd1
 	 * skips the authentication flow, or if working with a driver that
92bdd1
 	 * does not support full AP client state.
92bdd1
+	 *
92bdd1
+	 * Skip this if the STA has already completed FT reassociation and the
92bdd1
+	 * TK has been configured since the TX/RX PN must not be reset to 0 for
92bdd1
+	 * the same key.
92bdd1
 	 */
92bdd1
-	if (!sta->added_unassoc)
92bdd1
+	if (!sta->added_unassoc &&
92bdd1
+	    (!(sta->flags & WLAN_STA_AUTHORIZED) ||
92bdd1
+	     !wpa_auth_sta_ft_tk_already_set(sta->wpa_sm))) {
92bdd1
 		hostapd_drv_sta_remove(hapd, sta->addr);
92bdd1
+		wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
92bdd1
+		set = 0;
92bdd1
+	}
92bdd1
 
92bdd1
 #ifdef CONFIG_IEEE80211N
92bdd1
 	if (sta->flags & WLAN_STA_HT)
92bdd1
@@ -1873,11 +1883,11 @@ static int add_associated_sta(struct hostapd_data *hapd,
92bdd1
 			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
92bdd1
 			    sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
92bdd1
 			    sta->vht_opmode, sta->p2p_ie ? 1 : 0,
92bdd1
-			    sta->added_unassoc)) {
92bdd1
+			    set)) {
92bdd1
 		hostapd_logger(hapd, sta->addr,
92bdd1
 			       HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
92bdd1
 			       "Could not %s STA to kernel driver",
92bdd1
-			       sta->added_unassoc ? "set" : "add");
92bdd1
+			       set ? "set" : "add");
92bdd1
 
92bdd1
 		if (sta->added_unassoc) {
92bdd1
 			hostapd_drv_sta_remove(hapd, sta->addr);
92bdd1
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
92bdd1
index 3587086..707971d 100644
92bdd1
--- a/src/ap/wpa_auth.c
92bdd1
+++ b/src/ap/wpa_auth.c
92bdd1
@@ -1745,6 +1745,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
92bdd1
 #else /* CONFIG_IEEE80211R */
92bdd1
 		break;
92bdd1
 #endif /* CONFIG_IEEE80211R */
92bdd1
+	case WPA_DRV_STA_REMOVED:
92bdd1
+		sm->tk_already_set = FALSE;
92bdd1
+		return 0;
92bdd1
 	}
92bdd1
 
92bdd1
 #ifdef CONFIG_IEEE80211R
92bdd1
@@ -3250,6 +3253,14 @@ int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
92bdd1
 }
92bdd1
 
92bdd1
 
92bdd1
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm)
92bdd1
+{
92bdd1
+	if (!sm || !wpa_key_mgmt_ft(sm->wpa_key_mgmt))
92bdd1
+		return 0;
92bdd1
+	return sm->tk_already_set;
92bdd1
+}
92bdd1
+
92bdd1
+
92bdd1
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
92bdd1
 			     struct rsn_pmksa_cache_entry *entry)
92bdd1
 {
92bdd1
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
92bdd1
index 0de8d97..97461b0 100644
92bdd1
--- a/src/ap/wpa_auth.h
92bdd1
+++ b/src/ap/wpa_auth.h
92bdd1
@@ -267,7 +267,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
92bdd1
 		 u8 *data, size_t data_len);
92bdd1
 enum wpa_event {
92bdd1
 	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
92bdd1
-	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
92bdd1
+	WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
92bdd1
 };
92bdd1
 void wpa_remove_ptk(struct wpa_state_machine *sm);
92bdd1
 int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
92bdd1
@@ -280,6 +280,7 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
92bdd1
 int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
92bdd1
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
92bdd1
 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
92bdd1
+int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
92bdd1
 int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
92bdd1
 			     struct rsn_pmksa_cache_entry *entry);
92bdd1
 struct rsn_pmksa_cache_entry *
92bdd1
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
92bdd1
index 42242a5..e63b99a 100644
92bdd1
--- a/src/ap/wpa_auth_ft.c
92bdd1
+++ b/src/ap/wpa_auth_ft.c
92bdd1
@@ -780,6 +780,14 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
92bdd1
 		return;
92bdd1
 	}
92bdd1
 
92bdd1
+	if (sm->tk_already_set) {
92bdd1
+		/* Must avoid TK reconfiguration to prevent clearing of TX/RX
92bdd1
+		 * PN in the driver */
92bdd1
+		wpa_printf(MSG_DEBUG,
92bdd1
+			   "FT: Do not re-install same PTK to the driver");
92bdd1
+		return;
92bdd1
+	}
92bdd1
+
92bdd1
 	/* FIX: add STA entry to kernel/driver here? The set_key will fail
92bdd1
 	 * most likely without this.. At the moment, STA entry is added only
92bdd1
 	 * after association has been completed. This function will be called
92bdd1
@@ -792,6 +800,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
92bdd1
 
92bdd1
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
92bdd1
 	sm->pairwise_set = TRUE;
92bdd1
+	sm->tk_already_set = TRUE;
92bdd1
 }
92bdd1
 
92bdd1
 
92bdd1
@@ -898,6 +907,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
92bdd1
 
92bdd1
 	sm->pairwise = pairwise;
92bdd1
 	sm->PTK_valid = TRUE;
92bdd1
+	sm->tk_already_set = FALSE;
92bdd1
 	wpa_ft_install_ptk(sm);
92bdd1
 
92bdd1
 	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
92bdd1
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
92bdd1
index 72b7eb3..7fd8f05 100644
92bdd1
--- a/src/ap/wpa_auth_i.h
92bdd1
+++ b/src/ap/wpa_auth_i.h
92bdd1
@@ -65,6 +65,7 @@ struct wpa_state_machine {
92bdd1
 	struct wpa_ptk PTK;
92bdd1
 	Boolean PTK_valid;
92bdd1
 	Boolean pairwise_set;
92bdd1
+	Boolean tk_already_set;
92bdd1
 	int keycount;
92bdd1
 	Boolean Pair;
92bdd1
 	struct wpa_key_replay_counter {
92bdd1
-- 
92bdd1
2.7.4
92bdd1