[PATCH 40/50] WPA_AUTH: MLO: Add MLO KDEs to message 3 of the 4-way handshake
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Feb 15 15:08:54 PST 2023
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
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
More information about the Hostap
mailing list