Hi, > -----Original Message----- > From: Hostap <hostap-bounces@xxxxxxxxxxxxxxxxxxx> On Behalf Of > Veerendranath Jakkam > Sent: Thursday, August 25, 2022 08:53 > To: hostap@xxxxxxxxxxxxxxxxxxx > Cc: quic_vjakkam@xxxxxxxxxxx > 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@xxxxxxxxxxx> > --- > 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. _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap