From: Ilan Peer Date: Wed, 16 Dec 2020 11:01:38 +0000 (+0200) Subject: PASN: Include RSNXE in the PASN negotiation X-Git-Tag: hostap_2_10~662 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e7b980d6535c7d944c3d137fefef3e9b901dae0;p=thirdparty%2Fhostap.git PASN: Include RSNXE in the PASN negotiation IEEE 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 --- diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 47b260e81..16f1e96c0 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 a26e30879..c320825f3 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 f5b87fbf5..daf73efb0 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2877,9 +2877,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, *data, *rsn_ie, *rsnxe_ie; + u8 *data_buf = NULL; size_t rsn_ie_len; int ret; @@ -2926,6 +2927,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); @@ -2934,8 +2940,8 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd, os_memset(ptr, 0, mic_len); - data = wpabuf_head_u8(buf) + IEEE80211_HDRLEN; - data_len = wpabuf_len(buf) - IEEE80211_HDRLEN; + frame = wpabuf_head_u8(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) @@ -2946,9 +2952,24 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd, * MDE, 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_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2); + if (!data_buf) + goto fail; + + os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2); + os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2); + data_len += rsnxe_ie[1] + 2; + data = data_buf; + } else { + data = 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, mic); + hapd->own_addr, sta->addr, data, data_len, + frame, frame_len, mic); + os_free(data_buf); 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 a56b7631b..2b8c7f661 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1327,8 +1327,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 frame RSNE. For calculating the MIC for the 3rd PASN frame, this - * should hold the hash of the body of the PASN 1st frame. + * Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN + * frame, this should hold the hash of the 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. @@ -3692,4 +3692,24 @@ int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap, return 0; } + +void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab) +{ + size_t flen; + + flen = (capab & 0xff00) ? 2 : 1; + if (!capab) + return; /* no supported extended RSN capabilities */ + if (wpabuf_tailroom(buf) < 2 + flen) + return; + capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ + + wpabuf_put_u8(buf, WLAN_EID_RSNX); + wpabuf_put_u8(buf, flen); + wpabuf_put_u8(buf, capab & 0x00ff); + capab >>= 8; + if (capab) + wpabuf_put_u8(buf, capab); +} + #endif /* CONFIG_PASN */ diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 4fe8077a6..c31e1a0fa 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,6 @@ int wpa_pasn_validate_rsne(const struct wpa_ie_data *data); int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap, struct wpa_pasn_params_data *pasn_params); +void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab); + #endif /* WPA_COMMON_H */ diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index 1f3dd08ba..736a6c7d6 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -619,6 +619,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) const u8 *pmkid; u8 wrapped_data; int ret; + u16 capab; wpa_printf(MSG_DEBUG, "PASN: Building frame 1"); @@ -684,6 +685,17 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s) if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) goto fail; + /* Add own RNSXE */ + /* TODO: How to handle protected TWT and SAE H2E? */ + capab = 0; + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) + capab |= WLAN_RSNX_CAPAB_SECURE_LTF; + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT) + capab |= WLAN_RSNX_CAPAB_SECURE_RTT; + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG) + capab |= WLAN_RSNX_CAPAB_PROT_RANGE_NEG; + wpa_pasn_add_rsnxe(buf, capab); + ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, wpabuf_head_u8(buf) + IEEE80211_HDRLEN, wpabuf_len(buf) - IEEE80211_HDRLEN, @@ -806,8 +818,8 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s) forced_memzero(&pasn->ptk, sizeof(pasn->ptk)); forced_memzero(&pasn->hash, sizeof(pasn->hash)); - wpabuf_free(pasn->beacon_rsne); - pasn->beacon_rsne = NULL; + wpabuf_free(pasn->beacon_rsne_rsnxe); + pasn->beacon_rsne_rsnxe = NULL; #ifdef CONFIG_SAE sae_clear_data(&pasn->sae); @@ -926,6 +938,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 wpas_pasn *pasn = &wpa_s->pasn; @@ -980,12 +993,18 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid, goto fail; } - pasn->beacon_rsne = wpabuf_alloc_copy(beacon_rsne, 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_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; pasn->group = group; @@ -1068,7 +1087,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); @@ -1101,8 +1120,11 @@ 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, + rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0, awork->network_id); if (ret) { wpa_printf(MSG_DEBUG, @@ -1366,8 +1388,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 2e8584565..0ce7447fe 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -542,7 +542,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;