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@xxxxxxxxx> --- 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap