[PATCH 08/12] MLD STA: Add support for processing EAPOL 3/4 frame
Peer, Ilan
ilan.peer at intel.com
Tue Sep 13 01:12:14 PDT 2022
Hi,
> -----Original Message-----
> From: Hostap <hostap-bounces at lists.infradead.org> On Behalf Of
> Veerendranath Jakkam
> Sent: Thursday, August 25, 2022 08:53
> To: hostap at lists.infradead.org
> Cc: quic_vjakkam at quicinc.com
> Subject: [PATCH 08/12] MLD STA: Add support for processing EAPOL 3/4
> frame
>
> Process EAPOL 3/4 frame and plumb PTK and per-link GTK/IGTK/BIGTK keys
> to driver.
>
> Signed-off-by: Veerendranath Jakkam <quic_vjakkam at quicinc.com>
> ---
> src/rsn_supp/wpa.c | 494
> ++++++++++++++++++++++++++++++++++++++++++-
> src/rsn_supp/wpa_i.h | 6 +
> 2 files changed, 498 insertions(+), 2 deletions(-)
>
> diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index
> 8ac22eac9..96adc4817 100644
> --- a/src/rsn_supp/wpa.c
> +++ b/src/rsn_supp/wpa.c
> @@ -1203,6 +1203,76 @@ static int wpa_supplicant_install_gtk(struct
> wpa_sm *sm, }
>
>
> +static int wpa_supplicant_install_mlo_gtk(struct wpa_sm *sm, u8 link_id,
> + const struct wpa_gtk_data *gd,
> + const u8 *key_rsc, int wnm_sleep) {
> + const u8 *_gtk = gd->gtk;
> + u8 gtk_buf[32];
> +
> + /* Detect possible key reinstallation */
> + if ((sm->links[link_id].gtk.gtk_len == (size_t) gd->gtk_len &&
> + os_memcmp(sm->links[link_id].gtk.gtk, gd->gtk,
> + sm->links[link_id].gtk.gtk_len) == 0) ||
> + (sm->links[link_id].gtk_wnm_sleep.gtk_len == (size_t) gd-
> >gtk_len &&
> + os_memcmp(sm->links[link_id].gtk_wnm_sleep.gtk, gd->gtk,
> + sm->links[link_id].gtk_wnm_sleep.gtk_len) == 0)) {
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA MLO: Not reinstalling already in-use GTK to the
> driver (keyidx=%d tx=%d len=%d)",
> + gd->keyidx, gd->tx, gd->gtk_len);
Also print the link ID?
> + return 0;
> + }
> +
> + wpa_hexdump_key(MSG_DEBUG, "WPA MLO: Group Key", gd->gtk,
> gd->gtk_len);
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA MLO: Installing GTK to the driver (keyidx=%d tx=%d
> len=%d)",
> + gd->keyidx, gd->tx, gd->gtk_len);
> + wpa_hexdump(MSG_DEBUG, "WPA MLO: RSC", key_rsc, gd-
> >key_rsc_len);
Same in the above prints. I think it would be useful to print the link ID.
> + if (sm->group_cipher == WPA_CIPHER_TKIP) {
> + /* Swap Tx/Rx keys for Michael MIC */
> + os_memcpy(gtk_buf, gd->gtk, 16);
> + os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
> + os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
> + _gtk = gtk_buf;
> + }
As noted earlier not sure we need to allow TKIP.
> + if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
> + if (wpa_sm_mlo_set_key(sm, link_id, gd->alg, NULL, gd-
> >keyidx,
> + 1, key_rsc, gd->key_rsc_len, _gtk,
> + gd->gtk_len,
> + KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0)
> {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA MLO: Failed to set GTK to the driver "
> + "(Group only)");
> + forced_memzero(gtk_buf, sizeof(gtk_buf));
> + return -1;
> + }
This also seems something that we do not to deal with in a MLO connection. But really not sure.
> + } else if (wpa_sm_mlo_set_key(sm, link_id, gd->alg,
> + broadcast_ether_addr, gd->keyidx,
> + gd->tx, key_rsc, gd->key_rsc_len, _gtk,
> + gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA MLO: Failed to set GTK to "
> + "the driver (alg=%d keylen=%d keyidx=%d)",
> + gd->alg, gd->gtk_len, gd->keyidx);
> + forced_memzero(gtk_buf, sizeof(gtk_buf));
> + return -1;
> + }
> + forced_memzero(gtk_buf, sizeof(gtk_buf));
> +
> + if (wnm_sleep) {
> + sm->links[link_id].gtk_wnm_sleep.gtk_len = gd->gtk_len;
> + os_memcpy(sm->links[link_id].gtk_wnm_sleep.gtk, gd->gtk,
> + sm->links[link_id].gtk_wnm_sleep.gtk_len);
> + } else {
> + sm->links[link_id].gtk.gtk_len = gd->gtk_len;
> + os_memcpy(sm->links[link_id].gtk.gtk, gd->gtk,
> + sm->links[link_id].gtk.gtk_len);
> + }
> +
> + return 0;
> +}
> +
> +
> static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm
> *sm,
> int tx)
> {
> @@ -1251,6 +1321,82 @@ static int wpa_supplicant_rsc_relaxation(const
> struct wpa_sm *sm, }
>
>
> +static int _wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm, u8
Why use pairwise in the function name?
> link_id,
> + const u8 *gtk, size_t gtk_len,
> + int key_info)
> +{
> + struct wpa_gtk_data gd;
> + const u8 *key_rsc;
> +
> + /*
> + * MLO GTK KDE format:
> + * KeyID[bits 0-1], Tx [bit 2], Reserved [bit 3], link id [4-7]
> + * PN
> + * GTK
> + */
> +
> + os_memset(&gd, 0, sizeof(gd));
> + wpa_hexdump_key(MSG_DEBUG, "MLO RSN: received GTK in
> pairwise handshake",
> + gtk, gtk_len);
> +
> + if (gtk_len < 7 || gtk_len - 7 > sizeof(gd.gtk))
> + return -1;
> +
Can use WPA_MLO_GTK_KDE_PREFIX_LENGTH instead of 7.
> + gd.keyidx = gtk[0] & 0x3;
> + gtk += 1;
> + gtk_len -= 1;
> +
> + key_rsc = gtk;
> +
> + gtk += 6;
> + gtk_len -= 6;
> +
> + os_memcpy(gd.gtk, gtk, gtk_len);
> + gd.gtk_len = gtk_len;
> +
> + if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
> + (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
> + gtk_len, gtk_len,
> + &gd.key_rsc_len, &gd.alg) ||
> + wpa_supplicant_install_mlo_gtk(sm, link_id, &gd, key_rsc, 0))) {
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "MLO RSN: Failed to install GTK");
> + forced_memzero(&gd, sizeof(gd));
> + return -1;
> + }
> + forced_memzero(&gd, sizeof(gd));
The code can be refactored so "forced_memzero(&gd, sizeof(gd));" would be called once.
> +
> + return 0;
> +}
> +
> +
> +static int wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm,
> + const struct wpa_eapol_key *key,
> + struct wpa_eapol_ie_parse *ie,
> + int key_info)
> +{
> + u8 i;
> +
> + for (i = 0; i < MAX_NUM_MLO_LINKS; i++) {
> + if (!(sm->valid_links & BIT(i)))
> + continue;
As noted earlier, I think that this should also handle the case of rejected links, for which the MLD AP
Is not expected to provide GTK/IGTK/BIGTK.
> +
> + if (!ie->mlo_gtk[i]) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
> + "MLO RSN: GTK not found for link ID %u", i);
> + return -1;
> + }
> +
> + if (_wpa_supplicant_pairwise_mlo_gtk(sm, i, ie->mlo_gtk[i],
> + ie->mlo_gtk_len[i],
> + key_info))
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +
> static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
> const struct wpa_eapol_key *key,
> const u8 *gtk, size_t gtk_len, @@ -1421,6
> +1567,170 @@ static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
> return 0;
> }
>
> +static int wpa_supplicant_install_mlo_igtk(struct wpa_sm *sm, u8 link_id,
> + const struct wpa_mlo_igtk_kde
> *igtk,
> + int wnm_sleep)
> +{
> + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
> + u16 keyidx = WPA_GET_LE16(igtk->hdr.keyid);
> +
> + /* Detect possible key reinstallation */
> + if ((sm->links[link_id].igtk.igtk_len == len &&
> + os_memcmp(sm->links[link_id].igtk.igtk, igtk->igtk,
> + sm->links[link_id].igtk.igtk_len) == 0) ||
> + (sm->links[link_id].igtk_wnm_sleep.igtk_len == len &&
> + os_memcmp(sm->links[link_id].igtk_wnm_sleep.igtk, igtk->igtk,
> + sm->links[link_id].igtk_wnm_sleep.igtk_len) == 0)) {
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA: Not reinstalling already in-use IGTK to the
> driver (keyidx=%d)",
> + keyidx);
Same here: print link ID.
> + return 0;
> + }
> +
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA: IGTK keyid %d pn " COMPACT_MACSTR,
> + keyidx, MAC2STR(igtk->hdr.pn));
> + wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
> + if (keyidx > 4095) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA: Invalid IGTK KeyID %d", keyidx);
> + return -1;
> + }
> + if (wpa_sm_mlo_set_key(sm, link_id,
> + wpa_cipher_to_alg(sm->mgmt_group_cipher),
> + broadcast_ether_addr, keyidx, 0, igtk->hdr.pn,
> + sizeof(igtk->hdr.pn), igtk->igtk, len,
> + KEY_FLAG_GROUP_RX) < 0) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA: Failed to configure IGTK to the driver");
> + return -1;
> + }
> +
> + if (wnm_sleep) {
> + sm->links[link_id].igtk_wnm_sleep.igtk_len = len;
> + os_memcpy(sm->links[link_id].igtk_wnm_sleep.igtk,
> + igtk->igtk,
> + sm->links[link_id].igtk_wnm_sleep.igtk_len);
> + } else {
> + sm->links[link_id].igtk.igtk_len = len;
> + os_memcpy(sm->links[link_id].igtk.igtk, igtk->igtk,
> + sm->links[link_id].igtk.igtk_len);
> + }
> +
> + return 0;
> +}
> +
> +
> +static int
> +wpa_supplicant_install_mlo_bigtk(struct wpa_sm *sm, u8 link_id,
> + const struct wpa_mlo_bigtk_kde *bigtk,
> + int wnm_sleep)
> +{
> + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
> + u16 keyidx = WPA_GET_LE16(bigtk->hdr.keyid);
> +
> + /* Detect possible key reinstallation */
> + if ((sm->links[link_id].bigtk.bigtk_len == len &&
> + os_memcmp(sm->links[link_id].bigtk.bigtk, bigtk->bigtk,
> + sm->links[link_id].bigtk.bigtk_len) == 0) ||
> + (sm->links[link_id].bigtk_wnm_sleep.bigtk_len == len &&
> + os_memcmp(sm->links[link_id].bigtk_wnm_sleep.bigtk, bigtk-
> >bigtk,
> + sm->links[link_id].bigtk_wnm_sleep.bigtk_len) == 0)) {
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA: Not reinstalling already in-use BIGTK to the
> driver (keyidx=%d)",
> + keyidx);
> + return 0;
> + }
> +
> + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
> + "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
> + keyidx, MAC2STR(bigtk->hdr.pn));
> + wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
> + if (keyidx < 6 || keyidx > 7) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA: Invalid BIGTK KeyID %d", keyidx);
> + return -1;
> + }
> + if (wpa_sm_mlo_set_key(sm, link_id,
> + wpa_cipher_to_alg(sm->mgmt_group_cipher),
> + broadcast_ether_addr, keyidx, 0, bigtk->hdr.pn,
> + sizeof(bigtk->hdr.pn), bigtk->bigtk, len,
> + KEY_FLAG_GROUP_RX) < 0) {
> + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
> + "WPA: Failed to configure BIGTK to the driver");
> + return -1;
> + }
> +
> + if (wnm_sleep) {
> + sm->links[link_id].bigtk_wnm_sleep.bigtk_len = len;
> + os_memcpy(sm->links[link_id].bigtk_wnm_sleep.bigtk,
> + bigtk->bigtk,
> + sm->links[link_id].bigtk_wnm_sleep.bigtk_len);
> + } else {
> + sm->links[link_id].bigtk.bigtk_len = len;
> + os_memcpy(sm->links[link_id].bigtk.bigtk, bigtk->bigtk,
> + sm->links[link_id].bigtk.bigtk_len);
> + }
> +
> + return 0;
> +}
> +
> +
> +static int _mlo_ieee80211w_set_keys(struct wpa_sm *sm, u8 link_id,
> + struct wpa_eapol_ie_parse *ie)
> +{
> + size_t len;
> +
> + if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
> + sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED)
> + return 0;
> +
I do not think that WPA_CIPHER_GTK_NOT_USED is valid for MLO.
> + if (ie->mlo_igtk[link_id]) {
> + const struct wpa_mlo_igtk_kde *igtk;
> +
> + len = wpa_cipher_key_len(sm->mgmt_group_cipher);
> + if (ie->mlo_igtk_len[link_id] !=
> + sizeof(struct wpa_mlo_igtk_hdr) + len)
> + return -1;
> +
> + igtk = (const struct wpa_mlo_igtk_kde *) ie-
> >mlo_igtk[link_id];
> + if (wpa_supplicant_install_mlo_igtk(sm, link_id, igtk, 0) < 0)
> + return -1;
> + }
> +
> + if (ie->mlo_bigtk[link_id] && sm->beacon_prot) {
> + const struct wpa_mlo_bigtk_kde *bigtk;
> +
> + len = wpa_cipher_key_len(sm->mgmt_group_cipher);
> + if (ie->mlo_bigtk_len[link_id] !=
> + sizeof(struct wpa_mlo_bigtk_hdr) + len)
> + return -1;
> +
> + bigtk = (const struct wpa_mlo_bigtk_kde *) ie-
> >mlo_bigtk[link_id];
> + if (wpa_supplicant_install_mlo_bigtk(sm, link_id, bigtk, 0) <
> 0)
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +
> +static int mlo_ieee80211w_set_keys(struct wpa_sm *sm,
> + struct wpa_eapol_ie_parse *ie)
> +{
> + u8 i;
> +
> + for (i = 0; i < MAX_NUM_MLO_LINKS; i++) {
> + if (!(sm->valid_links & BIT(i)))
> + continue;
> +
Also here, consider links that were rejected during negotiation.
Regards,
Ilan.
More information about the Hostap
mailing list