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 <ilan.peer@intel.com>
This commit is contained in:
parent
d8cd20e37b
commit
9e7b980d65
7 changed files with 86 additions and 18 deletions
|
@ -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;
|
const u8 *ies;
|
||||||
size_t ies_len;
|
size_t ies_len;
|
||||||
|
|
|
@ -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,
|
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
|
||||||
struct wpabuf **probe_ie_taxonomy);
|
struct wpabuf **probe_ie_taxonomy);
|
||||||
|
|
||||||
|
const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
|
||||||
|
|
||||||
#endif /* BEACON_H */
|
#endif /* BEACON_H */
|
||||||
|
|
|
@ -2877,9 +2877,10 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
|
||||||
{
|
{
|
||||||
struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
|
struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
|
||||||
u8 mic[WPA_PASN_MAX_MIC_LEN];
|
u8 mic[WPA_PASN_MAX_MIC_LEN];
|
||||||
u8 mic_len, data_len;
|
u8 mic_len, frame_len, data_len;
|
||||||
u8 *ptr;
|
u8 *ptr;
|
||||||
const u8 *data, *rsn_ie;
|
const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
|
||||||
|
u8 *data_buf = NULL;
|
||||||
size_t rsn_ie_len;
|
size_t rsn_ie_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2926,6 +2927,11 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
|
||||||
wpabuf_free(pubkey);
|
wpabuf_free(pubkey);
|
||||||
pubkey = NULL;
|
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 */
|
/* Add the mic */
|
||||||
mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
|
mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
|
||||||
wpabuf_put_u8(buf, WLAN_EID_MIC);
|
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);
|
os_memset(ptr, 0, mic_len);
|
||||||
|
|
||||||
data = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
|
frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
|
||||||
data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
|
frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
|
||||||
|
|
||||||
rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
|
rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
|
||||||
if (!rsn_ie || !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
|
* MDE, etc. Thus, do not use the returned length but instead use the
|
||||||
* length specified in the IE header.
|
* 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,
|
ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
|
||||||
hapd->own_addr, sta->addr, rsn_ie, rsn_ie[1] + 2,
|
hapd->own_addr, sta->addr, data, data_len,
|
||||||
data, data_len, mic);
|
frame, frame_len, mic);
|
||||||
|
os_free(data_buf);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
|
wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
@ -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
|
* @addr2: For the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
|
||||||
* address
|
* address
|
||||||
* @data: For calculating the MIC for the 2nd PASN frame, this should hold the
|
* @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
|
* Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN
|
||||||
* should hold the hash of the body of the PASN 1st frame.
|
* frame, this should hold the hash of the body of the PASN 1st frame.
|
||||||
* @data_len: The length of data
|
* @data_len: The length of data
|
||||||
* @frame: The body of the PASN frame including the MIC element with the octets
|
* @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.
|
* 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;
|
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 */
|
#endif /* CONFIG_PASN */
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define WPA_GTK_MAX_LEN 32
|
#define WPA_GTK_MAX_LEN 32
|
||||||
#define WPA_PASN_PMK_LEN 32
|
#define WPA_PASN_PMK_LEN 32
|
||||||
#define WPA_PASN_MAX_MIC_LEN 24
|
#define WPA_PASN_MAX_MIC_LEN 24
|
||||||
|
#define WPA_MAX_RSNXE_LEN 4
|
||||||
|
|
||||||
#define OWE_DH_GROUP 19
|
#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,
|
int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
|
||||||
struct wpa_pasn_params_data *pasn_params);
|
struct wpa_pasn_params_data *pasn_params);
|
||||||
|
|
||||||
|
void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
|
||||||
|
|
||||||
#endif /* WPA_COMMON_H */
|
#endif /* WPA_COMMON_H */
|
||||||
|
|
|
@ -619,6 +619,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
|
||||||
const u8 *pmkid;
|
const u8 *pmkid;
|
||||||
u8 wrapped_data;
|
u8 wrapped_data;
|
||||||
int ret;
|
int ret;
|
||||||
|
u16 capab;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "PASN: Building frame 1");
|
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)
|
if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
|
||||||
goto fail;
|
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,
|
ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
|
||||||
wpabuf_head_u8(buf) + IEEE80211_HDRLEN,
|
wpabuf_head_u8(buf) + IEEE80211_HDRLEN,
|
||||||
wpabuf_len(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->ptk, sizeof(pasn->ptk));
|
||||||
forced_memzero(&pasn->hash, sizeof(pasn->hash));
|
forced_memzero(&pasn->hash, sizeof(pasn->hash));
|
||||||
|
|
||||||
wpabuf_free(pasn->beacon_rsne);
|
wpabuf_free(pasn->beacon_rsne_rsnxe);
|
||||||
pasn->beacon_rsne = NULL;
|
pasn->beacon_rsne_rsnxe = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
sae_clear_data(&pasn->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,
|
static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
int akmp, int cipher, u16 group, int freq,
|
int akmp, int cipher, u16 group, int freq,
|
||||||
const u8 *beacon_rsne, u8 beacon_rsne_len,
|
const u8 *beacon_rsne, u8 beacon_rsne_len,
|
||||||
|
const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
|
||||||
int network_id)
|
int network_id)
|
||||||
{
|
{
|
||||||
struct wpas_pasn *pasn = &wpa_s->pasn;
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pasn->beacon_rsne = wpabuf_alloc_copy(beacon_rsne, beacon_rsne_len);
|
pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
|
||||||
if (!pasn->beacon_rsne) {
|
beacon_rsnxe_len);
|
||||||
wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE");
|
if (!pasn->beacon_rsne_rsnxe) {
|
||||||
|
wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE/RSNXE");
|
||||||
goto fail;
|
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->akmp = akmp;
|
||||||
pasn->cipher = cipher;
|
pasn->cipher = cipher;
|
||||||
pasn->group = group;
|
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_supplicant *wpa_s = work->wpa_s;
|
||||||
struct wpa_pasn_auth_work *awork = work->ctx;
|
struct wpa_pasn_auth_work *awork = work->ctx;
|
||||||
struct wpa_bss *bss;
|
struct wpa_bss *bss;
|
||||||
const u8 *rsne;
|
const u8 *rsne, *rsnxe;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
|
||||||
|
|
||||||
ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
|
ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
|
||||||
awork->group, bss->freq, rsne, *(rsne + 1) + 2,
|
awork->group, bss->freq, rsne, *(rsne + 1) + 2,
|
||||||
|
rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
|
||||||
awork->network_id);
|
awork->network_id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
|
@ -1366,8 +1388,8 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
|
||||||
/* Verify the MIC */
|
/* Verify the MIC */
|
||||||
ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
|
ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
|
||||||
pasn->bssid, wpa_s->own_addr,
|
pasn->bssid, wpa_s->own_addr,
|
||||||
wpabuf_head(pasn->beacon_rsne),
|
wpabuf_head(pasn->beacon_rsne_rsnxe),
|
||||||
wpabuf_len(pasn->beacon_rsne),
|
wpabuf_len(pasn->beacon_rsne_rsnxe),
|
||||||
(u8 *) &mgmt->u.auth,
|
(u8 *) &mgmt->u.auth,
|
||||||
len - offsetof(struct ieee80211_mgmt, u.auth),
|
len - offsetof(struct ieee80211_mgmt, u.auth),
|
||||||
out_mic);
|
out_mic);
|
||||||
|
|
|
@ -542,7 +542,7 @@ struct wpas_pasn {
|
||||||
|
|
||||||
u8 hash[SHA384_MAC_LEN];
|
u8 hash[SHA384_MAC_LEN];
|
||||||
|
|
||||||
struct wpabuf *beacon_rsne;
|
struct wpabuf *beacon_rsne_rsnxe;
|
||||||
struct wpa_ptk ptk;
|
struct wpa_ptk ptk;
|
||||||
struct crypto_ecdh *ecdh;
|
struct crypto_ecdh *ecdh;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue