[PATCH 13/21] AP: WPA: Add CIGTK handling for CIP
Benjamin Berg
benjamin at sipsolutions.net
Tue Oct 27 06:16:59 PDT 2026
From: Benjamin Berg <benjamin.berg at intel.com>
This does not yet add everything, but the key will be installed and
included in the KDE and FT subelements if enabled.
Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
Reviewed-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/ap/hostapd.h | 2 +
src/ap/wpa_auth.c | 231 +++++++++++++++++++++++++++++++++++------
src/ap/wpa_auth.h | 9 +-
src/ap/wpa_auth_ft.c | 67 ++++++++++++
src/ap/wpa_auth_glue.c | 8 ++
src/ap/wpa_auth_i.h | 6 ++
src/ap/wpa_auth_ie.c | 5 +
7 files changed, 293 insertions(+), 35 deletions(-)
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 6ce29653b2..b4859979e5 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -414,6 +414,8 @@ struct hostapd_data {
int last_bigtk_key_idx;
u8 last_bigtk[WPA_BIGTK_MAX_LEN];
size_t last_bigtk_len;
+ int last_cigtk_key_idx;
+ u8 last_cigtk[WPA_CIGTK_LEN];
bool force_backlog_bytes;
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 3d773d0cbf..9e1af3cb2a 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -70,7 +70,9 @@ static void wpa_group_put_vlan(struct wpa_authenticator *wpa_auth,
int vlan_id);
#endif /* CONFIG_IEEE80211BE */
static int ieee80211w_kde_len(struct wpa_state_machine *sm);
+static int cip_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
+static u8 * cip_kde_add(struct wpa_state_machine *sm, u8 *pos);
static int wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
@@ -911,11 +913,17 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
}
#endif /* CONFIG_P2P */
- if (conf->tx_bss_auth && conf->beacon_prot) {
- conf->tx_bss_auth->non_tx_beacon_prot = true;
- if (!conf->tx_bss_auth->conf.group_mgmt_cipher)
- conf->tx_bss_auth->conf.group_mgmt_cipher =
- conf->group_mgmt_cipher;
+ if (conf->tx_bss_auth && (conf->beacon_prot || conf->cip)) {
+ if (conf->beacon_prot) {
+ conf->tx_bss_auth->non_tx_beacon_prot = true;
+
+ if (!conf->tx_bss_auth->conf.group_mgmt_cipher)
+ conf->tx_bss_auth->conf.group_mgmt_cipher =
+ conf->group_mgmt_cipher;
+ }
+
+ if (conf->cip)
+ conf->tx_bss_auth->non_tx_cip = true;
}
return wpa_auth;
@@ -2738,6 +2746,8 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
wpa_auth->conf.tx_bss_auth->group;
tx_group->bigtk_set = false;
tx_group->bigtk_configured = false;
+ tx_group->cigtk_set = false;
+ tx_group->cigtk_configured = false;
}
/*
@@ -3608,7 +3618,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
size_t plain_len;
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
- plain_len = 1000 + ieee80211w_kde_len(sm);
+ plain_len = 1000 + ieee80211w_kde_len(sm) + cip_kde_len(sm);
if (conf->transition_disable)
plain_len += 2 + RSN_SELECTOR_LEN + 1;
plain = wpabuf_alloc(plain_len);
@@ -3670,6 +3680,11 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
wpabuf_put(plain, tmp2 - tmp);
}
+ /* CIGTK KDE */
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = cip_kde_add(sm, tmp);
+ wpabuf_put(plain, tmp2 - tmp);
+
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
#ifdef CONFIG_OCV
@@ -4296,6 +4311,19 @@ static int ieee80211w_kde_len(struct wpa_state_machine *sm)
}
+static int cip_kde_len(struct wpa_state_machine *sm)
+{
+ size_t len = 0;
+
+ if (sm->cip) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_CIGTK_KDE_PREFIX_LEN;
+ len += WPA_CIGTK_LEN;
+ }
+
+ return len;
+}
+
+
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
@@ -4367,6 +4395,49 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
}
+static u8 * cip_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_cigtk_kde cigtk;
+ struct wpa_group *gsm = sm->group;
+ u8 rsc[WPA_KEY_RSC_LEN];
+
+#ifdef CONFIG_IEEE80211BE
+ if (sm->mld_assoc_link_id >= 0)
+ return pos; /* Use per-link MLO KDEs instead */
+#endif /* CONFIG_IEEE80211BE */
+
+ if (!sm->cip)
+ return pos;
+
+ if (gsm->vlan_id) {
+ wpa_printf(MSG_DEBUG, "Fetch CIGTK from default VLAN");
+ gsm = wpa_auth->group;
+ }
+
+ if (wpa_auth->conf.tx_bss_auth) {
+ wpa_printf(MSG_DEBUG, "Fetch CIGTK from TX BSS");
+ wpa_auth = wpa_auth->conf.tx_bss_auth;
+ gsm = wpa_auth->group;
+ }
+
+ cigtk.key_info = gsm->GN_cigtk;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_cigtk, rsc) < 0)
+ os_memset(cigtk.pn, 0, sizeof(cigtk.pn));
+ else
+ os_memcpy(cigtk.pn, rsc, sizeof(cigtk.pn));
+ os_memcpy(cigtk.cigtk, gsm->CIGTK[gsm->GN_cigtk], WPA_CIGTK_LEN);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_CIGTK,
+ (const u8 *) &cigtk,
+ WPA_CIGTK_KDE_PREFIX_LEN + WPA_CIGTK_LEN,
+ NULL, 0);
+ forced_memzero(&cigtk, sizeof(cigtk));
+
+ return pos;
+}
+
+
static int ocv_oci_len(struct wpa_state_machine *sm)
{
#ifdef CONFIG_OCV
@@ -4444,14 +4515,14 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot,
- bool rekey, int vlan_id)
+ bool cip, bool rekey, int vlan_id)
{
struct wpa_group *gsm = a->group;
u8 rsc[WPA_KEY_RSC_LEN];
wpa_printf(MSG_DEBUG,
- "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u VLAN ID:%d",
- info->link_id, mgmt_frame_prot, beacon_prot, vlan_id);
+ "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u, VLAN ID:%d, CIGTK=%u",
+ info->link_id, mgmt_frame_prot, beacon_prot, vlan_id, cip);
if (vlan_id)
gsm = wpa_select_vlan_wpa_group(gsm, vlan_id);
@@ -4465,6 +4536,17 @@ void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
else
os_memcpy(info->pn, rsc, sizeof(info->pn));
+ if (cip) {
+ info->cigtkidx = gsm->GN_cigtk;
+ info->cigtk = gsm->CIGTK[gsm->GN_cigtk];
+
+ if (rekey ||
+ wpa_auth_get_seqnum(a, NULL, gsm->GN_cigtk, rsc) < 0)
+ os_memset(info->cipn, 0, sizeof(info->cipn));
+ else
+ os_memcpy(info->cipn, rsc, sizeof(info->cipn));
+ }
+
if (!mgmt_frame_prot)
return;
@@ -4547,13 +4629,19 @@ size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm, u16 req_links)
kde_len += KDE_HDR_LEN + WPA_IGTK_KDE_PREFIX_LEN + 1;
kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
- if (!wpa_auth->conf.beacon_prot)
- continue;
+ if (wpa_auth->conf.beacon_prot) {
+ /* MLO BIGTK KDE
+ * Header + Key ID + BIPN + LinkID + BIGTK */
+ kde_len += KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1;
+ kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ }
- /* MLO BIGTK KDE
- * Header + Key ID + BIPN + LinkID + BIGTK */
- kde_len += KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1;
- kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ if (wpa_auth->conf.cip) {
+ /* MLO CIGTK KDE
+ * Header + Key Info + CIPN + Prefix8 + CIGTK */
+ kde_len += KDE_HDR_LEN;
+ kde_len += sizeof(struct rsn_mlo_cigtk_kde);
+ }
}
wpa_printf(MSG_DEBUG, "MLO Group KDEs len = %zu", kde_len);
@@ -4579,6 +4667,7 @@ u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos, u8 *end,
*/
ml_key_info.mgmt_frame_prot = sm->mgmt_frame_prot;
ml_key_info.beacon_prot = sm->wpa_auth->conf.beacon_prot;
+ ml_key_info.cip = sm->cip;
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
if (!sm->mld_links[link_id].valid)
@@ -4734,6 +4823,39 @@ u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos, u8 *end,
pos += ml_key_info.links[i].igtk_len;
}
+ /* Add MLO CIGTK KDEs */
+ for (i = 0; i < ml_key_info.n_mld_links; i++) {
+ link_id = ml_key_info.links[i].link_id;
+
+ if (!sm->mld_links[link_id].valid ||
+ !ml_key_info.links[i].cigtk)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "RSN: MLO CIGTK: link=%u", link_id);
+ wpa_hexdump_key(MSG_DEBUG, "RSN: MLO CIGTK",
+ ml_key_info.links[i].cigtk, 32);
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1 + 1 +
+ sizeof(ml_key_info.links[i].cipn) + 32;
+
+ RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_CIGTK);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the Key Info */
+ *pos++ = ml_key_info.links[i].cigtkidx;
+
+ /* Add the CIPN */
+ os_memcpy(pos, ml_key_info.links[i].cipn,
+ sizeof(ml_key_info.links[i].cipn));
+ pos += sizeof(ml_key_info.links[i].cipn);
+
+ *pos++ = ml_key_info.links[i].link_id << 4;
+
+ os_memcpy(pos, ml_key_info.links[i].cigtk, 32);
+ pos += 32;
+ }
+
wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %td", pos - start);
return pos;
}
@@ -5064,7 +5186,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2], [CIGTK])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
@@ -5217,7 +5339,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm) +
+ cip_kde_len(sm);
if (sm->use_ext_key_id)
kde_len += 2 + RSN_SELECTOR_LEN + 2;
@@ -5307,6 +5430,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
pos = ieee80211w_kde_add(sm, pos);
if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0)
goto done;
+ pos = cip_kde_add(sm, pos);
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -5793,7 +5917,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
if (sm->wpa == WPA_VERSION_WPA2 && !is_mld) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm) +
+ cip_kde_len(sm);
kde_buf = os_malloc(kde_len);
if (!kde_buf)
return;
@@ -5809,6 +5934,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
os_free(kde_buf);
return;
}
+ pos = cip_kde_add(sm, pos);
kde_len = pos - kde;
#ifdef CONFIG_IEEE80211BE
} else if (sm->wpa == WPA_VERSION_WPA2 && is_mld) {
@@ -6013,27 +6139,37 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
group->IGTK[group->GN_igtk - 4], len);
}
- /* Skip BIGTK generation for groups with a non-zero VLAN ID since only
- * a single BIGTK is shared for all VLANs in a BSS. */
+ /* Skip BIGTK/CIGTK generation for groups with a non-zero VLAN ID since
+ * only a single BIGTK/CIGTK is shared for all VLANs in a BSS. */
if (group->vlan_id)
return ret;
- if (!wpa_auth->non_tx_beacon_prot &&
- !wpa_auth_pmf_enabled(conf))
- return ret;
+ if (wpa_auth->conf.tx_bss_auth) {
+ wpa_auth = wpa_auth->conf.tx_bss_auth;
+ group = wpa_auth->group;
+ wpa_printf(MSG_DEBUG, "Set up BIGTK/CIGTK for TX BSS");
+ }
+
+ if (conf->cip || wpa_auth->non_tx_cip) {
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "CIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->CIGTK[group->GN_cigtk],
+ WPA_CIGTK_LEN) < 0)
+ ret = -1;
+ group->cigtk_set = true;
+ group->cigtk_configured = false;
+ wpa_hexdump_key(MSG_DEBUG, "CIGTK",
+ group->CIGTK[group->GN_cigtk],
+ WPA_CIGTK_LEN);
+ }
/* Skip BIGTK generation if neither the TX BSS nor any of the non-TX BSS
* enable beacon protection */
if (!wpa_auth->non_tx_beacon_prot && !conf->beacon_prot)
return ret;
- if (wpa_auth->conf.tx_bss_auth) {
- group = wpa_auth->conf.tx_bss_auth->group;
- if (group->bigtk_set)
- return ret;
- wpa_printf(MSG_DEBUG, "Set up BIGTK for TX BSS");
- }
-
len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -6067,6 +6203,8 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
group->GM_igtk = 5;
group->GN_bigtk = 6;
group->GM_bigtk = 7;
+ group->GN_cigtk = 0;
+ group->GM_cigtk = 1;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
@@ -6295,6 +6433,9 @@ static int wpa_group_update_gtk(struct wpa_authenticator *wpa_auth,
tmp = group->GM_bigtk;
group->GM_bigtk = group->GN_bigtk;
group->GN_bigtk = tmp;
+ tmp = group->GM_cigtk;
+ group->GM_cigtk = group->GN_cigtk;
+ group->GN_cigtk = tmp;
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
@@ -6363,7 +6504,8 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
if (ret || group->vlan_id)
return ret;
- /* Switch to transmitting BSSID for BIGTK */
+
+ /* Switch to transmitting BSSID for BIGTK and CIGTK */
if (wpa_auth->conf.tx_bss_auth) {
wpa_auth = wpa_auth->conf.tx_bss_auth;
group = wpa_auth->group;
@@ -6379,6 +6521,18 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
group->bigtk_configured = true;
}
+ if (group->cigtk_set && !group->cigtk_configured) {
+ if (wpa_auth_set_key(wpa_auth, group->vlan_id,
+ WPA_ALG_GCMP_256,
+ broadcast_ether_addr, group->GN_cigtk,
+ group->CIGTK[group->GN_cigtk],
+ WPA_CIGTK_LEN,
+ KEY_FLAG_CIGTK | KEY_FLAG_TX) < 0)
+ return -1;
+ else
+ group->cigtk_configured = true;
+ }
+
return ret;
}
@@ -6583,6 +6737,10 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
tmp = group->GM_bigtk;
group->GM_bigtk = group->GN_bigtk;
group->GN_bigtk = tmp;
+
+ tmp = group->GM_cigtk;
+ group->GM_cigtk = group->GN_cigtk;
+ group->GN_cigtk = tmp;
}
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
@@ -7691,7 +7849,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
u8 hdr[2];
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2], [CIGTK])
*/
/* Use 0 RSC */
@@ -7742,7 +7900,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm) +
+ cip_kde_len(sm);
if (sm->use_ext_key_id)
kde_len += 2 + RSN_SELECTOR_LEN + 2;
@@ -7845,6 +8004,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
}
#endif /* CONFIG_IEEE80211R_AP */
+ pos = cip_kde_add(sm, pos);
+
wpa_send_eapol(sm->wpa_auth, sm,
(secure ? WPA_KEY_INFO_SECURE : 0) |
(wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len,
@@ -7880,7 +8041,8 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
gtk = gsm->GTK[gsm->GN - 1];
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm) +
+ cip_kde_len(sm);
kde_buf = os_malloc(kde_len);
if (!kde_buf)
return -1;
@@ -7903,6 +8065,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
os_free(kde_buf);
return -1;
}
+ pos = cip_kde_add(sm, pos);
kde_len = pos - kde;
} else {
kde = gtk;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 9e5e38459e..629f64dfc8 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -333,6 +333,7 @@ struct wpa_auth_config {
int rsn_override_mlo_compat;
bool spp_amsdu;
+ bool cip;
u64 rsnxe_capab_mask;
@@ -358,6 +359,7 @@ struct wpa_auth_ml_key_info {
unsigned int n_mld_links;
bool mgmt_frame_prot;
bool beacon_prot;
+ bool cip;
struct wpa_auth_ml_link_key_info {
u8 link_id;
@@ -375,6 +377,10 @@ struct wpa_auth_ml_key_info {
u8 bigtkidx;
const u8 *bigtk;
u8 bipn[6];
+
+ u8 cigtkidx;
+ const u8 *cigtk;
+ u8 cipn[6];
} links[MAX_NUM_MLD_LINKS];
};
@@ -492,6 +498,7 @@ int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
int wpa_auth_uses_spp_amsdu(struct wpa_state_machine *sm);
+int wpa_auth_uses_cip(struct wpa_state_machine *sm);
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
struct wpa_state_machine *
@@ -728,7 +735,7 @@ void wpa_auth_set_ml_info(struct wpa_state_machine *sm,
void wpa_auth_ml_get_key_info(struct wpa_authenticator *a,
struct wpa_auth_ml_link_key_info *info,
bool mgmt_frame_prot, bool beacon_prot,
- bool rekey, int vlan_id);
+ bool cip, bool rekey, int vlan_id);
void wpa_release_link_auth_ref(struct wpa_state_machine *sm, u8 link_id,
bool rejected);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e12f2ad8e8..d27df90501 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2404,6 +2404,50 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
}
+static u8 * wpa_ft_cigtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+ u8 *subelem, *pos;
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_group *gsm = wpa_auth->group;
+ size_t subelem_len;
+ const u8 *kek, *cigtk;
+ size_t kek_len;
+
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ kek = sm->PTK.kek2;
+ kek_len = sm->PTK.kek2_len;
+ } else {
+ kek = sm->PTK.kek;
+ kek_len = sm->PTK.kek_len;
+ }
+
+ /* Sub-elem ID[1] | Length[1] | KeyInfo | CIPN[6] | Key[32+8] */
+ subelem_len = 1 + 1 + 1 + 6 + WPA_CIGTK_LEN + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return NULL;
+
+ pos = subelem;
+ *pos++ = FTIE_SUBELEM_CIGTK;
+ *pos++ = subelem_len - 2;
+ *pos++ = u8_get_bits(gsm->GN_cigtk, RSN_MLO_CIGTK_KDE_KEY_IDX_MASK);
+
+ wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_cigtk, pos);
+ pos += 6;
+ cigtk = gsm->CIGTK[gsm->GN_cigtk];
+ if (aes_wrap(kek, kek_len, WPA_CIGTK_LEN / 8, cigtk, pos)) {
+ wpa_printf(MSG_DEBUG,
+ "FT: CIGTK subelem encryption failed: kek_len=%d",
+ (int) kek_len);
+ os_free(subelem);
+ return NULL;
+ }
+
+ *len = subelem_len;
+ return subelem;
+}
+
+
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
@@ -2670,6 +2714,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
subelem_len += bigtk_len;
os_free(bigtk);
}
+ if (sm->cip) {
+ u8 *cigtk;
+ size_t cigtk_len;
+ u8 *nbuf;
+
+ cigtk = wpa_ft_cigtk_subelem(sm, &cigtk_len);
+ if (!cigtk) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to add CIGTK subelement");
+ os_free(subelem);
+ return NULL;
+ }
+ nbuf = os_realloc(subelem, subelem_len + cigtk_len);
+ if (!nbuf) {
+ os_free(subelem);
+ os_free(cigtk);
+ return NULL;
+ }
+ subelem = nbuf;
+ os_memcpy(subelem + subelem_len, cigtk, cigtk_len);
+ subelem_len += cigtk_len;
+ os_free(cigtk);
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9da2e6d206..9208b57d86 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -661,6 +661,12 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
os_memcpy(hapd->last_bigtk, key, key_len);
hapd->last_bigtk_len = key_len;
}
+ } else if (key_flag & KEY_FLAG_CIGTK) {
+ if (idx == 0 || idx == 1) {
+ hapd->last_cigtk_key_idx = idx;
+ if (key)
+ os_memcpy(hapd->last_cigtk, key, key_len);
+ }
} else {
hapd->last_gtk_alg = alg;
hapd->last_gtk_key_idx = idx;
@@ -1755,6 +1761,7 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
&info->links[i],
info->mgmt_frame_prot,
info->beacon_prot,
+ info->cip,
rekey, vlan_id);
continue;
}
@@ -1767,6 +1774,7 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
&info->links[i],
info->mgmt_frame_prot,
info->beacon_prot,
+ info->cip,
rekey, vlan_id);
link_bss_found = true;
break;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a1b34ee0a2..7a7330b34a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -99,6 +99,7 @@ struct wpa_state_machine {
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
unsigned int spp_amsdu:1;
+ unsigned int cip:1;
unsigned int ptkstart_without_success;
@@ -228,10 +229,14 @@ struct wpa_group {
bool reject_4way_hs_for_entropy;
u8 IGTK[2][WPA_IGTK_MAX_LEN];
u8 BIGTK[2][WPA_IGTK_MAX_LEN];
+ u8 CIGTK[2][WPA_CIGTK_LEN];
int GN_igtk, GM_igtk;
int GN_bigtk, GM_bigtk;
+ int GN_cigtk, GM_cigtk;
bool bigtk_set;
bool bigtk_configured;
+ bool cigtk_set;
+ bool cigtk_configured;
/* Number of references except those in struct wpa_group->next */
unsigned int references;
unsigned int num_setup_iface;
@@ -268,6 +273,7 @@ struct wpa_authenticator {
struct wpa_ft_pmk_cache *ft_pmk_cache;
bool non_tx_beacon_prot;
+ bool non_tx_cip;
#ifdef CONFIG_P2P
struct bitfield *ip_pool;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 6b72eb3b11..0cc319ec77 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1530,6 +1530,11 @@ int wpa_auth_uses_spp_amsdu(struct wpa_state_machine *sm)
return sm ? sm->spp_amsdu : 0;
}
+int wpa_auth_uses_cip(struct wpa_state_machine *sm)
+{
+ return sm ? sm->cip : 0;
+}
+
#ifdef CONFIG_OCV
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
--
2.56.0
More information about the Hostap
mailing list