[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