Signed-off-by: Ilan Peer <ilan.peer@xxxxxxxxx> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx> --- src/ap/wpa_auth.c | 342 ++++++++++++++++++++++++++++++++++++++++- src/ap/wpa_auth.h | 4 + src/ap/wpa_auth_glue.c | 46 ++++++ 3 files changed, 389 insertions(+), 3 deletions(-) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 6a12b2d3e5..1ffa94effc 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -3561,6 +3561,11 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) if (!sm->mgmt_frame_prot) return pos; +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) + return pos; +#endif /* CONFIG_IEEE80211BE */ + igtk.keyid[0] = gsm->GN_igtk; igtk.keyid[1] = 0; if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || @@ -3703,8 +3708,329 @@ static void wpa_auth_get_ml_rsn_info(struct wpa_authenticator *wpa_auth, wpa_auth->cb->get_ml_rsn_info(wpa_auth->cb_ctx, info); } + + +void wpa_auth_ml_get_info(struct wpa_authenticator *a, + struct wpa_auth_ml_link_key_info *info, + bool mgmt_frame_prot, bool beacon_prot) +{ + struct wpa_group *gsm = a->group; + u8 rsc[WPA_KEY_RSC_LEN]; + + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: get info: link_id=%u, mgmt=%u, beacon=%u", + info->link_id, mgmt_frame_prot, beacon_prot); + + info->gtkidx = gsm->GN & 0x03; + info->gtk = gsm->GTK[gsm->GN - 1]; + info->gtk_len = gsm->GTK_len; + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0) + os_memset(info->pn, 0, sizeof(info->pn)); + else + os_memcpy(info->pn, rsc, sizeof(info->pn)); + + if (!mgmt_frame_prot) + return; + + info->igtkidx = gsm->GN_igtk; + info->igtk = gsm->IGTK[gsm->GN_igtk - 4]; + info->igtk_len = wpa_cipher_key_len(a->conf.group_mgmt_cipher); + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN_igtk, rsc) < 0) + os_memset(info->ipn, 0, sizeof(info->ipn)); + else + os_memcpy(info->ipn, rsc, sizeof(info->ipn)); + + if (!beacon_prot) + return; + + info->bigtkidx = gsm->GN_bigtk; + info->bigtk = gsm->BIGTK[gsm->GN_bigtk - 6]; + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN_bigtk, rsc) < 0) + os_memset(info->bipn, 0, sizeof(info->bipn)); + else + os_memcpy(info->bipn, rsc, sizeof(info->bipn)); +} + + +static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth, + struct wpa_auth_ml_key_info *info) +{ + if (!wpa_auth->cb->get_ml_key_info) + return; + + wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info); +} + + +static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm) +{ + struct wpa_group *gsm = sm->group; + size_t gtk_len = gsm->GTK_len; + size_t igtk_len = + wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + size_t kde_len; + u8 n_links; + + if (sm->mld_assoc_link_id < 0) + return 0; + + n_links = sm->n_mld_affiliated_links + 1; + + /* MLO GTK KDE for each link */ + kde_len = n_links * (2 + RSN_SELECTOR_LEN + 7 + gtk_len); + + if (!sm->mgmt_frame_prot) + return kde_len; + + kde_len += n_links * (2 + RSN_SELECTOR_LEN + 3 + 6 + + igtk_len); + + if (!sm->wpa_auth->conf.beacon_prot) + return kde_len; + + kde_len += n_links* (2 + RSN_SELECTOR_LEN + 3 + 6 + igtk_len); + + return kde_len; +} + + +static u8 *wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_auth_ml_key_info ml_key_info; + u8 i, link_id; + + /* first fetch the key information from all the authenticators */ + os_memset(&ml_key_info, 0, sizeof(ml_key_info)); + ml_key_info.n_mld_links = sm->n_mld_affiliated_links + 1; + + /* + * Assume that management frame protection and beacon protection are the + * same on all links + */ + ml_key_info.mgmt_frame_prot = sm->mgmt_frame_prot; + ml_key_info.beacon_prot = sm->wpa_auth->conf.beacon_prot; + + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + ml_key_info.links[i++].link_id = link_id; + } + + wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info); + + /* Add MLO GTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO GTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO GTK:", + ml_key_info.links[i].gtk, + ml_key_info.links[i].gtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 1 + 6 + + ml_key_info.links[i].gtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_GTK); + pos += RSN_SELECTOR_LEN; + + *pos++ = (ml_key_info.links[i].gtkidx & 0x3) | (link_id << 4); + + os_memcpy(pos, ml_key_info.links[i].pn, 6); + pos += 6; + + os_memcpy(pos, ml_key_info.links[i].gtk, + ml_key_info.links[i].gtk_len); + pos += ml_key_info.links[i].gtk_len; + + i++; + } + + if (!sm->mgmt_frame_prot) + return pos; + + /* Add MLO IGTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO IGTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO IGTK:", + ml_key_info.links[i].igtk, + ml_key_info.links[i].igtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 2 + 1 + + sizeof(ml_key_info.links[i].ipn) + + ml_key_info.links[i].igtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_IGTK); + pos += RSN_SELECTOR_LEN; + + /* Add the key ID */ + *pos++ = ml_key_info.links[i].igtkidx; + *pos++ = 0; + + /* Add the IPN */ + os_memcpy(pos, ml_key_info.links[i].ipn, + sizeof(ml_key_info.links[i].ipn)); + pos += sizeof(ml_key_info.links[i].ipn); + + *pos++ = ml_key_info.links[i].link_id << 4; + + os_memcpy(pos, ml_key_info.links[i].igtk, + ml_key_info.links[i].igtk_len); + pos += ml_key_info.links[i].igtk_len; + + i++; + } + + if (!sm->wpa_auth->conf.beacon_prot) + return pos; + + /* Add MLO BIGTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO BIGTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO BIGTK:", + ml_key_info.links[i].bigtk, + ml_key_info.links[i].igtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 2 + 1 + + sizeof(ml_key_info.links[i].bipn) + + ml_key_info.links[i].igtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_BIGTK); + pos += RSN_SELECTOR_LEN; + + /* Add the key ID */ + *pos++ = ml_key_info.links[i].bigtkidx; + *pos++ = 0; + + /* Add the IPN */ + os_memcpy(pos, ml_key_info.links[i].bipn, + sizeof(ml_key_info.links[i].bipn)); + pos += sizeof(ml_key_info.links[i].bipn); + + *pos++ = ml_key_info.links[i].link_id << 4; + + os_memcpy(pos, ml_key_info.links[i].bigtk, + ml_key_info.links[i].igtk_len); + pos += ml_key_info.links[i].igtk_len; + + i++; + } + + return pos; +} + +#endif /* CONFIG_IEEE80211BE */ + +static size_t wpa_auth_ml_kdes_len(struct wpa_state_machine *sm) +{ + size_t kde_len = 0; + +#ifdef CONFIG_IEEE80211BE + u8 link_id; + + if (sm->mld_assoc_link_id < 0) + return 0; + + /* For the MAC address KDE */ + kde_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN; + + /* MLO link KDE for each link */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + kde_len += 2 + RSN_SELECTOR_LEN + 7 + + sm->mld_links[link_id].rsne_len + + sm->mld_links[link_id].rsnxe_len; + } + + kde_len += wpa_auth_ml_group_kdes_len(sm); +#endif /* CONFIG_IEEE80211BE */ + + return kde_len; +} + + +static u8 *wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos, + u8 *gtk, size_t gtk_len, int gtkidx) +{ +#ifdef CONFIG_IEEE80211BE + u8 link_id; + + if (sm->mld_assoc_link_id < 0) + return pos; + + wpa_printf(MSG_DEBUG, + "RSN: MLD: Adding MAC Address KDE"); + + pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, + sm->own_mld_addr, ETH_ALEN, NULL, 0); + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + wpa_printf(MSG_DEBUG, + "RSN: MLO Link: link=%u, len=%u", link_id, + RSN_SELECTOR_LEN + 7 + + sm->mld_links[link_id].rsne_len + + sm->mld_links[link_id].rsnxe_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 7 + + sm->mld_links[link_id].rsne_len + + sm->mld_links[link_id].rsnxe_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_LINK); + pos += RSN_SELECTOR_LEN; + + /* add the link information */ + *pos = link_id; + + if (sm->mld_links[link_id].rsne_len) + *pos |= RSN_KEY_DATA_MLO_LINK_INFO_RSNE_PRESENT; + + if (sm->mld_links[link_id].rsnxe_len) + *pos |= RSN_KEY_DATA_MLO_LINK_INFO_RSNXE_PRESENT; + + pos++; + os_memcpy(pos, sm->mld_links[link_id].own_addr, ETH_ALEN); + pos += ETH_ALEN; + + if (sm->mld_links[link_id].rsne_len) { + os_memcpy(pos, sm->mld_links[link_id].rsne, + sm->mld_links[link_id].rsne_len); + pos += sm->mld_links[link_id].rsne_len; + } + + if (sm->mld_links[link_id].rsnxe_len) { + os_memcpy(pos, sm->mld_links[link_id].rsnxe, + sm->mld_links[link_id].rsnxe_len); + pos += sm->mld_links[link_id].rsnxe_len; + } + } + + pos = wpa_auth_ml_group_kdes(sm, pos); + #endif /* CONFIG_IEEE80211BE */ + return pos; +} + + SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32]; @@ -3715,6 +4041,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; u8 hdr[2]; struct wpa_auth_config *conf = &sm->wpa_auth->conf; + u8 is_mld = 0; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = false; @@ -3821,6 +4148,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) gtk = NULL; gtk_len = 0; _rsc = NULL; + gtkidx = 0; if (sm->rx_eapol_key_secure) { /* * It looks like Windows 7 supplicant tries to use @@ -3863,13 +4191,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) kde_len += 2 + RSN_SELECTOR_LEN + 2; #endif /* CONFIG_DPP2 */ + kde_len += wpa_auth_ml_kdes_len(sm); + is_mld = (sm->mld_assoc_link_id >= 0); + kde = os_malloc(kde_len); if (!kde) goto done; pos = kde; - os_memcpy(pos, wpa_ie, wpa_ie_len); - pos += wpa_ie_len; + if (!is_mld) { + os_memcpy(pos, wpa_ie, wpa_ie_len); + pos += wpa_ie_len; + } + #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; @@ -3893,7 +4227,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); } - if (gtk) { + if (gtk && !is_mld) { hdr[0] = gtkidx & 0x03; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); @@ -3973,6 +4307,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } #endif /* CONFIG_DPP2 */ + pos = wpa_auth_ml_kdes(sm, pos, gtk, gtk_len, gtkidx); + wpa_send_eapol(sm->wpa_auth, sm, (secure ? WPA_KEY_INFO_SECURE : 0) | (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index fbd9d84f8b..297ff9a424 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -392,6 +392,7 @@ struct wpa_auth_callbacks { #endif /* CONFIG_PASN */ #ifdef CONFIG_IEEE80211BE int (*get_ml_rsn_info)(void *ctx, struct wpa_auth_ml_rsn_info *info); + int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info); #endif /* CONFIG_IEEE80211BE */ }; @@ -637,4 +638,7 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm, struct mld_info *info); void wpa_auth_ml_get_rsn_info(struct wpa_authenticator *a, struct wpa_auth_ml_link_rsn_info *info); +void wpa_auth_ml_get_info(struct wpa_authenticator *a, + struct wpa_auth_ml_link_key_info *info, + bool mgmt_frame_prot, bool beacon_prot); #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index e15013c11b..d9bcea316d 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1538,8 +1538,53 @@ static int hostapd_wpa_auth_get_ml_rsn_info(void *ctx, return 0; } + + +static int hostapd_wpa_auth_get_ml_key_info(void *ctx, + struct wpa_auth_ml_key_info *info) +{ + struct hostapd_data *hapd = ctx; + u8 i, j; + + wpa_printf(MSG_DEBUG, "WPA_AUTH: MLD: get key info CB: n_mld_links=%u", + info->n_mld_links); + + if (!hapd->conf->mld_ap || !hapd->iface || !hapd->iface->interfaces) + return -1; + + for (i = 0; i < info->n_mld_links; i++) { + u8 link_id = info->links[i].link_id; + + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: get link info CB: link_id=%u", + link_id); + + for (j = 0; j < hapd->iface->interfaces->count; j++) { + struct hostapd_iface *iface = + hapd->iface->interfaces->iface[j]; + + if (!iface->bss[0]->conf->mld_ap || + hapd->conf->mld_id != iface->bss[0]->conf->mld_id || + link_id != iface->bss[0]->conf->mld_link_id) + continue; + + wpa_auth_ml_get_info(iface->bss[0]->wpa_auth, + &info->links[i], + info->mgmt_frame_prot, + info->beacon_prot); + break; + } + + if (j == hapd->iface->interfaces->count) + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: link=%u not found", link_id); + } + + return 0; +} #endif /* CONFIG_IEEE80211BE */ + int hostapd_setup_wpa(struct hostapd_data *hapd) { struct wpa_auth_config _conf; @@ -1591,6 +1636,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) #endif /* CONFIG_PASN */ #ifdef CONFIG_IEEE80211BE .get_ml_rsn_info = hostapd_wpa_auth_get_ml_rsn_info, + .get_ml_key_info = hostapd_wpa_auth_get_ml_key_info, #endif /* CONFIG_IEEE80211BE */ }; const u8 *wpa_ie; -- 2.38.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap