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

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