[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