[PATCH 2/4] PASN: Include RSNXE in the PASN negotiation

Ilan Peer ilan.peer at intel.com
Wed Dec 16 06:01:38 EST 2020


Draft P802.11az_D2.6 added definitions to include RSNXE
in the PASN negotiation.

Implement the new functionality in both wpa_supplicant and
hostapd.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/beacon.c                   |  2 +-
 src/ap/beacon.h                   |  2 ++
 src/ap/ieee802_11.c               | 34 ++++++++++++++++++----
 src/common/wpa_common.c           | 48 +++++++++++++++++++++++++++++--
 src/common/wpa_common.h           |  4 +++
 wpa_supplicant/pasn_supplicant.c  | 41 +++++++++++++++++++-------
 wpa_supplicant/wpa_supplicant_i.h |  2 +-
 7 files changed, 114 insertions(+), 19 deletions(-)

diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 47b260e810..22f0751ca6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -266,7 +266,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
 }
 
 
-static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+const u8 *hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
 {
 	const u8 *ies;
 	size_t ies_len;
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a26e30879c..8f09fda1a7 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -30,4 +30,6 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
 void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
 				   struct wpabuf **probe_ie_taxonomy);
 
+const u8 *hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+
 #endif /* BEACON_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1da7eff4fb..52de046535 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2939,9 +2939,10 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 {
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
 	u8 mic[WPA_PASN_MAX_MIC_LEN];
-	u8 mic_len, data_len;
+	u8 mic_len, frame_len, data_len;
 	u8 *ptr;
-	const u8 *data, *rsn_ie;
+	const u8 *frame, *rsn_ie, *rsnxe_ie;
+	u8 *data;
 	size_t rsn_ie_len;
 	int ret;
 
@@ -2986,6 +2987,11 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 	wpabuf_free(pubkey);
 	pubkey = NULL;
 
+	/* Add RSNXE if needed */
+	rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+	if (rsnxe_ie)
+		wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+
 	/* Add the mic */
 	mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
 	wpabuf_put_u8(buf, WLAN_EID_MIC);
@@ -2994,8 +3000,8 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 
 	os_memset(ptr, 0, mic_len);
 
-	data = wpabuf_head(buf) + IEEE80211_HDRLEN;
-	data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+	frame = wpabuf_head(buf) + IEEE80211_HDRLEN;
+	frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
 
 	rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
 	if (!rsn_ie || !rsn_ie_len)
@@ -3006,11 +3012,29 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 	 * also the MD IE etc. Thus, do not use the returned length but instead
 	 * use the length specified in the IE header.
 	 */
+	data_len = rsn_ie[1] + 2;
+	if (rsnxe_ie) {
+		data = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
+		if (!data)
+			goto fail;
+
+		os_memcpy(data, (u8 *)rsn_ie, rsn_ie[1] + 2);
+		os_memcpy(data + rsn_ie[1] + 2, (u8 *)rsnxe_ie,
+			  rsnxe_ie[1] + 2);
+		data_len += rsnxe_ie[1] + 2;
+	} else {
+		data = (u8 *)rsn_ie;
+	}
+
 	ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
 		       hapd->own_addr, sta->addr,
-		       rsn_ie, rsn_ie[1] + 2,
 		       data, data_len,
+		       frame, frame_len,
 		       mic);
+
+	if (rsnxe_ie)
+		os_free(data);
+
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed mic calculation");
 		goto fail;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 6300d774b4..3acaa7e261 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1322,8 +1322,8 @@ u8 pasn_mic_len(int akmp, int cipher)
  * @addr2: for the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
  *     address
  * @data: For calculating the MIC for the 2nd PASN frame, this should hold the
- *    beacon RSN IE. For the calculating the MIC for the 3rd PASN frame, this
- *    should hold the HASH of body of the PASN 1st frame.
+ *    beacon RSN IE + RSNXE IE. For calculating the MIC for the 3rd PASN
+ *    frame, this should hold the HASH of body of the PASN 1st frame.
  * @data_len: the length of data
  * @frame: The body of the PASN frame including the MIC element with the Octets
  *     in the MIC field of the MIC element set to 0.
@@ -3667,4 +3667,48 @@ int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len,
 
 	return 0;
 }
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u8 prot_twt, u8 sae_h2e,
+			u8 sae_pk, u8 sec_ltf, u8 sec_rtt, u8 prot_range_neg)
+{
+	u8 len = 1;
+	u8 capab = 0;
+
+	if (sec_ltf || sec_rtt || prot_range_neg) {
+		len = 2;
+		capab = 1;
+	}
+
+	if (prot_twt)
+		capab |= BIT(WLAN_RSNX_CAPAB_PROTECTED_TWT);
+
+	if (sae_h2e)
+		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+	if (sae_pk)
+		capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+
+	if (!capab)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_EID_RSNX);
+	wpabuf_put_u8(buf, len);
+	wpabuf_put_u8(buf, capab);
+
+	if (len == 1)
+		return;
+
+	capab = 0;
+	if (sec_ltf)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+
+	if (sec_rtt)
+		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+
+	if (prot_range_neg)
+		capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+	wpabuf_put_u8(buf, capab);
+}
+
 #endif /* CONFIG_PASN */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index a094686d4e..89637e56d5 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -21,6 +21,7 @@
 #define WPA_GTK_MAX_LEN 32
 #define WPA_PASN_PMK_LEN 32
 #define WPA_PASN_MAX_MIC_LEN 24
+#define WPA_MAX_RSNXE_LEN 4
 
 #define OWE_DH_GROUP 19
 
@@ -664,4 +665,7 @@ int wpa_pasn_validate_rsne(const struct wpa_ie_data *data);
 int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len,
 				struct wpa_pasn_params_data *pasn_params);
 
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u8 prot_twt, u8 sae_h2e,
+			u8 sae_pk, u8 sec_ltf, u8 sec_rtt, u8 prot_range_neg);
+
 #endif /* WPA_COMMON_H */
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index bdf72d51c6..32a8a33bb6 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -708,6 +708,17 @@ static struct wpabuf *wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
 
 	wpa_pasn_add_wrapped_data(buf, wrapped_data_buf);
 
+	/*
+	 * add own RNSXE
+	 * TODO: How to handle protected TWT and SAE H2E
+	 */
+	wpa_pasn_add_rsnxe(buf,
+			   0, 0, 0,
+			   !!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF),
+			   !!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT),
+			   !!(wpa_s->drv_flags2 &
+			      WPA_DRIVER_FLAGS2_PROT_RANGE_NEG));
+
 	ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
 				   wpabuf_head(buf) + IEEE80211_HDRLEN,
 				   wpabuf_len(buf) - IEEE80211_HDRLEN,
@@ -829,8 +840,8 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
 	os_memset(&pasn->ptk, 0, sizeof(pasn->ptk));
 	os_memset(&pasn->hash, 0, sizeof(pasn->hash));
 
-	wpabuf_free(pasn->beacon_rsne);
-	pasn->beacon_rsne = NULL;
+	wpabuf_free(pasn->beacon_rsne_rsnxe);
+	pasn->beacon_rsne_rsnxe = NULL;
 
 	wpabuf_free(pasn->comeback);
 	pasn->comeback = NULL;
@@ -950,6 +961,7 @@ static int wpas_pasn_set_pmk(struct wpa_supplicant *wpa_s,
 static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   int akmp, int cipher, u16 group, int freq,
 			   const u8 *beacon_rsne, u8 beacon_rsne_len,
+			   const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
 			   int network_id, struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
@@ -1000,13 +1012,18 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		goto fail;
 	}
 
-	pasn->beacon_rsne = wpabuf_alloc(beacon_rsne_len);
-	if (!pasn->beacon_rsne) {
-		wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE");
+	pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
+					       beacon_rsnxe_len);
+	if (!pasn->beacon_rsne_rsnxe) {
+		wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE/RSNXE");
 		goto fail;
 	}
 
-	wpabuf_put_data(pasn->beacon_rsne, beacon_rsne, beacon_rsne_len);
+	wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsne, beacon_rsne_len);
+
+	if (beacon_rsnxe && beacon_rsnxe_len)
+		wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsnxe,
+				beacon_rsnxe_len);
 
 	pasn->akmp = akmp;
 	pasn->cipher = cipher;
@@ -1092,7 +1109,7 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 	struct wpa_pasn_auth_work *awork = work->ctx;
 	struct wpa_bss *bss;
-	const u8 *rsne;
+	const u8 *rsne, *rsnxe;
 	int ret;
 
 	wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
@@ -1127,9 +1144,13 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 		goto fail;
 	}
 
+	rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+
 	ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
 			      awork->group, bss->freq,
-			      rsne, *(rsne + 1) + 2, awork->network_id,
+			      rsne, *(rsne + 1) + 2,
+			      rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
+			      awork->network_id,
 			      awork->comeback);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
@@ -1425,8 +1446,8 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 	/* verify the MIC */
 	ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
 		       pasn->bssid, wpa_s->own_addr,
-		       wpabuf_head(pasn->beacon_rsne),
-		       wpabuf_len(pasn->beacon_rsne),
+		       wpabuf_head(pasn->beacon_rsne_rsnxe),
+		       wpabuf_len(pasn->beacon_rsne_rsnxe),
 		       (u8 *)&mgmt->u.auth,
 		       len - offsetof(struct ieee80211_mgmt, u.auth),
 		       out_mic);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3114b60dd2..47cf19f857 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -549,7 +549,7 @@ struct wpas_pasn {
 
 	u8 hash[SHA384_MAC_LEN];
 
-	struct wpabuf *beacon_rsne;
+	struct wpabuf *beacon_rsne_rsnxe;
 	struct wpa_ptk ptk;
 	struct crypto_ecdh *ecdh;
 
-- 
2.17.1




More information about the Hostap mailing list