[PATCH 08/21] WPA: Add CIGTK handling and installation support
Benjamin Berg
benjamin at sipsolutions.net
Tue Oct 27 06:16:54 PDT 2026
From: Benjamin Berg <benjamin.berg at intel.com>
Handle the CIGTK when it is carried in an FT subelement or the RSN KDE.
Install the CIGTK when CIP is enabled for the wpa_sm.
Note that CIGTK uses bits 13 and 14 in keys_cleared to track whether a
key was uploaded.
Signed-off-by: Benjamin Berg <benjamin.berg at intel.com>
Reviewed-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/common/ieee802_11_defs.h | 1 +
src/common/wpa_common.c | 46 +++++++
src/common/wpa_common.h | 37 ++++++
src/rsn_supp/wpa.c | 227 ++++++++++++++++++++++++++++++++
src/rsn_supp/wpa.h | 4 +
src/rsn_supp/wpa_ft.c | 60 ++++++++-
src/rsn_supp/wpa_i.h | 3 +
src/utils/common.h | 2 +
wpa_supplicant/ctrl_iface.c | 6 +
wpa_supplicant/driver_i.h | 4 +
wpa_supplicant/wpa_supplicant.c | 9 ++
11 files changed, 398 insertions(+), 1 deletion(-)
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 20edcae0b8..291695456f 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2233,6 +2233,7 @@ enum wnm_sleep_mode_subelement_id {
WNM_SLEEP_SUBELEM_GTK = 0,
WNM_SLEEP_SUBELEM_IGTK = 1,
WNM_SLEEP_SUBELEM_BIGTK = 2,
+ WNM_SLEEP_SUBELEM_CIGTK = 7,
};
/* WNM notification type (IEEE Std 802.11-2020, Table 9-431) */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 264c2e164a..9adfb8a1f4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1329,6 +1329,11 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
parse->bigtk = pos;
parse->bigtk_len = len;
break;
+ case FTIE_SUBELEM_CIGTK:
+ wpa_printf(MSG_DEBUG, "FT: CIGTK");
+ parse->cigtk = pos;
+ parse->cigtk_len = len;
+ break;
case FTIE_SUBELEM_MLO_GTK:
if (len < 2 + 1 + 1 + 8) {
wpa_printf(MSG_DEBUG,
@@ -1374,6 +1379,21 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
parse->mlo_bigtk[link_id] = pos;
parse->mlo_bigtk_len[link_id] = len;
break;
+ case FTIE_SUBELEM_MLO_CIGTK:
+ if (len < 2 + 6 + 1) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Too short MLO CIGTK in FTE");
+ return -1;
+ }
+ link_id = pos[2 + 6] & 0x0f;
+ wpa_printf(MSG_DEBUG, "FT: MLO CIGTK (Link ID %u)",
+ link_id);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ break;
+ parse->valid_mlo_cigtks |= BIT(link_id);
+ parse->mlo_cigtk[link_id] = pos;
+ parse->mlo_cigtk_len[link_id] = len;
+ break;
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
@@ -4218,6 +4238,14 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
return 0;
}
+ if (left > 2 && selector == RSN_KEY_DATA_CIGTK) {
+ ie->cigtk = p;
+ ie->cigtk_len = left;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: CIGTK in EAPOL-Key",
+ pos, dlen);
+ return 0;
+ }
+
if (left >= 1 && selector == WFA_KEY_DATA_IP_ADDR_REQ) {
ie->ip_addr_req = p;
wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
@@ -4311,6 +4339,24 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
return 0;
}
+ if (left >= RSN_MLO_CIGTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_CIGTK) {
+ link_id = u8_get_bits(p[7],
+ RSN_MLO_CIGTK_KDE_PREFIX8_LINK_ID_MASK);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ return 2;
+
+ ie->valid_mlo_cigtks |= BIT(link_id);
+ ie->mlo_cigtk[link_id] = p;
+ ie->mlo_cigtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO CIGTK KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
+ return 0;
+ }
+
if (left >= RSN_MLO_LINK_KDE_FIXED_LENGTH &&
selector == RSN_KEY_DATA_MLO_LINK) {
link_id = (p[0] & RSN_MLO_LINK_KDE_LI_LINK_ID_MASK) >>
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 158f79afd1..dcbb13fe0e 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -158,6 +158,8 @@ WPA_CIPHER_BIP_CMAC_256)
#define RSN_KEY_DATA_MLO_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
#define RSN_KEY_DATA_MLO_LINK RSN_SELECTOR(0x00, 0x0f, 0xac, 19)
#define RSN_KEY_DATA_SAE_PW_IDS RSN_SELECTOR(0x00, 0x0f, 0xac, 25)
+#define RSN_KEY_DATA_CIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 24)
+#define RSN_KEY_DATA_MLO_CIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 26)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
@@ -184,6 +186,7 @@ WPA_CIPHER_BIP_CMAC_256)
#define WPA_IGTK_MAX_LEN 32
#define WPA_BIGTK_LEN 16
#define WPA_BIGTK_MAX_LEN 32
+#define WPA_CIGTK_LEN 32
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
@@ -309,6 +312,10 @@ struct wpa_bigtk {
size_t bigtk_len;
};
+struct wpa_cigtk {
+ u8 cigtk[WPA_CIGTK_LEN];
+};
+
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
* 0x01 0x00 (version; little endian)
@@ -390,6 +397,13 @@ struct wpa_bigtk_kde {
u8 bigtk[WPA_BIGTK_MAX_LEN];
} STRUCT_PACKED;
+#define WPA_CIGTK_KDE_PREFIX_LEN (offsetofend(struct wpa_cigtk_kde, pn))
+struct wpa_cigtk_kde {
+ u8 key_info;
+ u8 pn[RSN_PN_LEN];
+ u8 cigtk[WPA_CIGTK_LEN];
+} STRUCT_PACKED;
+
#define RSN_MLO_GTK_KDE_PREFIX_LENGTH (1 + RSN_PN_LEN)
#define RSN_MLO_GTK_KDE_PREFIX0_KEY_ID_MASK 0x03
#define RSN_MLO_GTK_KDE_PREFIX0_TX 0x04
@@ -416,6 +430,17 @@ struct rsn_mlo_bigtk_kde {
u8 bigtk[WPA_BIGTK_MAX_LEN];
} STRUCT_PACKED;
+#define RSN_MLO_CIGTK_KDE_KEY_IDX_MASK 0x01
+#define RSN_MLO_CIGTK_KDE_PREFIX_LENGTH \
+ (offsetofend(struct rsn_mlo_cigtk_kde, prefix8))
+#define RSN_MLO_CIGTK_KDE_PREFIX8_LINK_ID_MASK 0xF0
+struct rsn_mlo_cigtk_kde {
+ u8 key_info;
+ u8 pn[RSN_PN_LEN];
+ u8 prefix8;
+ u8 cigtk[WPA_CIGTK_LEN];
+} STRUCT_PACKED;
+
#define RSN_MLO_LINK_KDE_FIXED_LENGTH (1 + ETH_ALEN)
#define RSN_MLO_LINK_KDE_LINK_INFO_INDEX 0
#define RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT 0
@@ -465,6 +490,8 @@ struct rsn_ftie_sha512 {
#define FTIE_SUBELEM_MLO_GTK 8
#define FTIE_SUBELEM_MLO_IGTK 9
#define FTIE_SUBELEM_MLO_BIGTK 10
+#define FTIE_SUBELEM_CIGTK 12
+#define FTIE_SUBELEM_MLO_CIGTK 14
struct rsn_rdie {
u8 id;
@@ -624,6 +651,8 @@ struct wpa_ft_ies {
size_t igtk_len;
const u8 *bigtk;
size_t bigtk_len;
+ const u8 *cigtk;
+ size_t cigtk_len;
#ifdef CONFIG_OCV
const u8 *oci;
size_t oci_len;
@@ -643,6 +672,9 @@ struct wpa_ft_ies {
u16 valid_mlo_bigtks; /* bitmap of valid link BIGTK subelements */
const u8 *mlo_bigtk[MAX_NUM_MLD_LINKS];
size_t mlo_bigtk_len[MAX_NUM_MLD_LINKS];
+ u16 valid_mlo_cigtks; /* bitmap of valid link CIGTK subelements */
+ const u8 *mlo_cigtk[MAX_NUM_MLD_LINKS];
+ size_t mlo_cigtk_len[MAX_NUM_MLD_LINKS];
struct wpabuf *fte_buf;
};
@@ -705,6 +737,8 @@ struct wpa_eapol_ie_parse {
size_t igtk_len;
const u8 *bigtk;
size_t bigtk_len;
+ const u8 *cigtk;
+ size_t cigtk_len;
const u8 *sae_pw_ids;
size_t sae_pw_ids_len;
const u8 *mdie;
@@ -773,6 +807,9 @@ struct wpa_eapol_ie_parse {
u16 valid_mlo_bigtks; /* bitmap of valid link BIGTK KDEs */
const u8 *mlo_bigtk[MAX_NUM_MLD_LINKS];
size_t mlo_bigtk_len[MAX_NUM_MLD_LINKS];
+ u16 valid_mlo_cigtks; /* bitmap of valid link CIGTK KDEs */
+ const u8 *mlo_cigtk[MAX_NUM_MLD_LINKS];
+ size_t mlo_cigtk_len[MAX_NUM_MLD_LINKS];
u16 valid_mlo_links; /* bitmap of valid MLO link KDEs */
const u8 *mlo_link[MAX_NUM_MLD_LINKS];
size_t mlo_link_len[MAX_NUM_MLD_LINKS];
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5a05a991b9..1e1a7045c8 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1856,6 +1856,47 @@ static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
}
+static int wpa_supplicant_install_cigtk(struct wpa_sm *sm,
+ const struct wpa_cigtk_kde *cigtk,
+ int wnm_sleep)
+{
+ u8 keyidx = cigtk->key_info & 0x1;
+
+ STATIC_ASSERT(sizeof(sm->cigtk.cigtk) == WPA_CIGTK_LEN);
+
+ /* Detect possible key reinstallation */
+ if (os_memcmp(sm->cigtk.cigtk, cigtk->cigtk,
+ sizeof(cigtk->cigtk)) == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use CIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: CIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(cigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: CIGTK", cigtk->cigtk, WPA_CIGTK_LEN);
+ if (wpa_sm_set_key(sm, -1, WPA_ALG_GCMP_256,
+ broadcast_ether_addr,
+ keyidx, 0, cigtk->pn, sizeof(cigtk->pn),
+ cigtk->cigtk, WPA_CIGTK_LEN,
+ KEY_FLAG_CIGTK | KEY_FLAG_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure CIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep)
+ os_memcpy(sm->cigtk_wnm_sleep.cigtk, cigtk->cigtk,
+ WPA_CIGTK_LEN);
+ else
+ os_memcpy(sm->cigtk.cigtk, cigtk->cigtk, WPA_CIGTK_LEN);
+
+ return 0;
+}
+
+
static int wpa_supplicant_install_mlo_igtk(struct wpa_sm *sm, u8 link_id,
const struct rsn_mlo_igtk_kde *igtk,
int wnm_sleep)
@@ -1972,6 +2013,54 @@ wpa_supplicant_install_mlo_bigtk(struct wpa_sm *sm, u8 link_id,
}
+static int
+wpa_supplicant_install_mlo_cigtk(struct wpa_sm *sm, u8 link_id,
+ const struct rsn_mlo_cigtk_kde *cigtk,
+ int wnm_sleep)
+{
+ u16 keyidx = u8_get_bits(cigtk->key_info,
+ RSN_MLO_CIGTK_KDE_KEY_IDX_MASK);
+
+ STATIC_ASSERT(sizeof(sm->mlo.links[link_id].cigtk.cigtk) ==
+ WPA_CIGTK_LEN);
+
+ /* Detect possible key reinstallation */
+ if (os_memcmp(sm->mlo.links[link_id].cigtk.cigtk, cigtk->cigtk,
+ sizeof(cigtk->cigtk)) == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Not reinstalling already in-use CIGTK to the driver (link_id=%d keyidx=%d)",
+ link_id, keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: MLO Link %u CIGTK keyid %d pn " COMPACT_MACSTR,
+ link_id, keyidx, MAC2STR(cigtk->pn));
+ wpa_hexdump_link_key(MSG_DEBUG, link_id, "RSN: CIGTK", cigtk->cigtk,
+ WPA_CIGTK_LEN);
+
+ if (wpa_sm_set_key(sm, link_id,
+ WPA_ALG_GCMP_256,
+ broadcast_ether_addr, keyidx, 0, cigtk->pn,
+ sizeof(cigtk->pn), cigtk->cigtk, WPA_CIGTK_LEN,
+ KEY_FLAG_CIGTK | KEY_FLAG_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "RSN: Failed to configure MLO Link %d CIGTK to the driver",
+ link_id);
+ return -1;
+ }
+
+ if (wnm_sleep)
+ os_memcpy(sm->mlo.links[link_id].cigtk_wnm_sleep.cigtk,
+ cigtk->cigtk, sizeof(cigtk->cigtk));
+ else
+ os_memcpy(sm->mlo.links[link_id].cigtk.cigtk, cigtk->cigtk,
+ sizeof(cigtk->cigtk));
+
+ return 0;
+}
+
+
static int _mlo_ieee80211w_set_keys(struct wpa_sm *sm, u8 link_id,
struct wpa_eapol_ie_parse *ie)
{
@@ -2064,6 +2153,63 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
}
+static int _mlo_cip_set_keys(struct wpa_sm *sm, u8 link_id,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (ie->mlo_cigtk[link_id]) {
+ if (ie->mlo_cigtk_len[link_id] !=
+ RSN_MLO_CIGTK_KDE_PREFIX_LENGTH + WPA_CIGTK_LEN)
+ return -1;
+
+ if (wpa_supplicant_install_mlo_cigtk(
+ sm, link_id,
+ (const struct rsn_mlo_cigtk_kde *)
+ ie->mlo_cigtk[link_id],
+ 0) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+
+static int mlo_cip_set_keys(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *ie)
+{
+ u8 i;
+
+ if (!sm->cip)
+ return 0;
+
+ for_each_link(sm->mlo.valid_links, i) {
+ if (_mlo_cip_set_keys(sm, i, ie))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int cip_set_keys(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (!sm->cip)
+ return 0;
+
+ if (ie->cigtk) {
+ const struct wpa_cigtk_kde *cigtk;
+
+ if (ie->cigtk_len != WPA_CIGTK_KDE_PREFIX_LEN + WPA_CIGTK_LEN)
+ return -1;
+
+ cigtk = (const struct wpa_cigtk_kde *) ie->cigtk;
+ if (wpa_supplicant_install_cigtk(sm, cigtk, 0) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
static void wpa_report_ie_mismatch(struct wpa_sm *sm,
const char *reason, const u8 *src_addr,
const u8 *wpa_ie, size_t wpa_ie_len,
@@ -2755,6 +2901,26 @@ static int wpa_validate_mlo_ieee80211w_kdes(struct wpa_sm *sm,
}
+static int wpa_validate_mlo_cip_kdes(struct wpa_sm *sm,
+ u8 link_id,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (!sm->cip)
+ return 0;
+
+ if (ie->mlo_cigtk[link_id] &&
+ ie->mlo_cigtk_len[link_id] != RSN_MLO_CIGTK_KDE_PREFIX_LENGTH +
+ WPA_CIGTK_LEN) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "RSN MLO: Invalid CIGTK KDE length %lu for link ID %u",
+ (unsigned long) ie->mlo_cigtk_len[link_id], link_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static void wpa_supplicant_process_3_of_4_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
u16 ver, const u8 *key_data,
@@ -2963,6 +3129,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
wpa_validate_mlo_ieee80211w_kdes(sm, i, &ie) < 0)
goto failed;
+
+ if (sm->cip &&
+ wpa_validate_mlo_cip_kdes(sm, i, &ie) < 0)
+ goto failed;
}
#ifdef CONFIG_IEEE80211R
@@ -3138,6 +3308,13 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+ if ((mlo && mlo_cip_set_keys(sm, &ie) < 0) ||
+ (!mlo && cip_set_keys(sm, &ie) < 0)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Failed to configure CIGTK");
+ goto failed;
+ }
+
if (mlo || sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info & WPA_KEY_INFO_SECURE);
@@ -3327,6 +3504,10 @@ static void wpa_supplicant_process_mlo_1_of_2(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"MLO RSN: Failed to configure MLO IGTK");
+ if (mlo_cip_set_keys(sm, &ie) < 0)
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "MLO RSN: Failed to configure MLO CIGTK");
+
for_each_link(sm->mlo.valid_links, i) {
/*
* AP may send group keys for subset of the all links during
@@ -3587,6 +3768,10 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Failed to configure IGTK");
+ if (cip_set_keys(sm, &ie) < 0)
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Failed to configure CIGTK");
+
key_rsc = key->key_rsc;
if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc))
key_rsc = null_rsc;
@@ -5317,6 +5502,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_SECURITY_PROFILE_ACTIVE:
sm->security_profile_active = !!value;
break;
+ case WPA_PARAM_CONTROL_INTEGRITY_PROTOCOL:
+ sm->cip = !!value;
+ break;
default:
break;
}
@@ -6279,6 +6467,12 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
if (sm->beacon_prot &&
wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
return -1;
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_CIGTK) {
+ const struct wpa_cigtk_kde *cigtk;
+
+ cigtk = (const struct wpa_cigtk_kde *) (buf + 2);
+ if (sm->cip && wpa_supplicant_install_cigtk(sm, cigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
@@ -7379,6 +7573,11 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
goto fail;
}
+ if (cip_set_keys(sm, &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set CIGTK");
+ goto fail;
+ }
+
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
if (keylen <= 0 || (unsigned int) keylen != sm->ptk.tk_len) {
@@ -7706,6 +7905,12 @@ bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm)
}
+bool wpa_sm_uses_cip(struct wpa_sm *sm)
+{
+ return sm ? sm->cip : false;
+}
+
+
struct rsn_pmksa_cache * wpa_sm_get_pmksa_cache(struct wpa_sm *sm)
{
return sm ? sm->pmksa : NULL;
@@ -7787,6 +7992,24 @@ static int mlo_ieee80211w_set_keys_for_new_links(struct wpa_sm *sm,
}
+static int mlo_cip_set_keys_for_new_links(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *ie,
+ u16 added_links_bitmap)
+{
+ int i;
+
+ if (!sm->cip)
+ return 0;
+
+ for_each_link(added_links_bitmap, i) {
+ if (_mlo_cip_set_keys(sm, i, ie))
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_install_mlo_gtk_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie,
u16 added_links_bitmap)
@@ -7831,6 +8054,10 @@ int wpa_sm_install_mlo_group_keys(struct wpa_sm *sm, const u8 *key_data,
added_links_bitmap) < 0)
return -1;
+ if (mlo_cip_set_keys_for_new_links(sm, &ie,
+ added_links_bitmap) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index c61ca16a46..38e28541a0 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -148,6 +148,7 @@ enum wpa_sm_conf_params {
WPA_PARAM_ASSOC_ENC,
WPA_PARAM_PMKSA_CACHING_PRIVACY,
WPA_PARAM_SECURITY_PROFILE_ACTIVE,
+ WPA_PARAM_CONTROL_INTEGRITY_PROTOCOL,
};
enum wpa_rsn_override {
@@ -188,6 +189,8 @@ struct wpa_sm_link {
struct wpa_igtk igtk_wnm_sleep;
struct wpa_bigtk bigtk;
struct wpa_bigtk bigtk_wnm_sleep;
+ struct wpa_cigtk cigtk;
+ struct wpa_cigtk cigtk_wnm_sleep;
};
struct wpa_sm_mlo {
@@ -300,6 +303,7 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo);
void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
bool driver_bss_selection);
bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm);
+bool wpa_sm_uses_cip(struct wpa_sm *sm);
#else /* CONFIG_NO_WPA */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index fb46fa2f40..9f608e0a94 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1024,6 +1024,62 @@ static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
}
+static int wpa_ft_process_cigtk_subelem(struct wpa_sm *sm, const u8 *cigtk_elem,
+ size_t cigtk_elem_len)
+{
+ u8 cigtk[WPA_CIGTK_LEN];
+ u8 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->cip || !cigtk_elem)
+ return 0;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received CIGTK in Reassoc Resp",
+ cigtk_elem, cigtk_elem_len);
+
+ if (cigtk_elem_len != 1 + 6 + WPA_CIGTK_LEN + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid CIGTK sub-elem length %lu",
+ (unsigned long) cigtk_elem_len);
+ return -1;
+ }
+ if (aes_unwrap(kek, kek_len, WPA_CIGTK_LEN / 8, cigtk_elem + 7,
+ cigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt CIGTK");
+ return -1;
+ }
+
+ /* KeyInfo[1] | CIPN[6] | Key[32+8] */
+
+ keyidx = u8_get_bits(cigtk_elem[0], 0x1);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: CIGTK from Reassoc Resp", cigtk,
+ WPA_CIGTK_LEN);
+ if (wpa_sm_set_key(sm, -1, WPA_ALG_GCMP_256,
+ broadcast_ether_addr, keyidx, 0,
+ cigtk_elem + 1, 6, cigtk, WPA_CIGTK_LEN,
+ KEY_FLAG_CIGTK | KEY_FLAG_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set CIGTK to the driver");
+ forced_memzero(cigtk, sizeof(cigtk));
+ return -1;
+ }
+ forced_memzero(cigtk, sizeof(cigtk));
+
+ return 0;
+}
+
+
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr)
{
@@ -1256,7 +1312,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
- wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk,
+ parse.bigtk_len) < 0 ||
+ wpa_ft_process_cigtk_subelem(sm, parse.cigtk, parse.cigtk_len) < 0)
goto fail;
if (sm->set_ptk_after_assoc) {
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 72b26d1d9e..71bdb4ec59 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -42,6 +42,8 @@ struct wpa_sm {
struct wpa_igtk igtk_wnm_sleep;
struct wpa_bigtk bigtk;
struct wpa_bigtk bigtk_wnm_sleep;
+ struct wpa_cigtk cigtk;
+ struct wpa_cigtk cigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
@@ -75,6 +77,7 @@ struct wpa_sm {
int wpa_rsc_relaxation;
int owe_ptk_workaround;
int beacon_prot;
+ bool cip;
int ext_key_id; /* whether Extended Key ID is enabled */
int use_ext_key_id; /* whether Extended Key ID has been detected
* to be used */
diff --git a/src/utils/common.h b/src/utils/common.h
index eb434ebb5c..abe6b25b21 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -606,6 +606,8 @@ int * int_array_dup(const int *a);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define STATIC_ASSERT(cond) (void)sizeof(char[(cond) ? 1 : -1])
+
void str_clear_free(char *str);
void bin_clear_free(void *bin, size_t len);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 44d400020c..397a91c293 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6198,6 +6198,12 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
0, KEY_FLAG_GROUP);
wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
+ if (wpa_drv_get_cip_supported(wpa_s)) {
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 0, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_CIGTK);
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 1, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_CIGTK);
+ }
wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0,
NULL, 0, KEY_FLAG_PAIRWISE);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 559be7aad6..731e045789 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -184,9 +184,13 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, int link_id,
* Extended Key ID--a unicast key. Use bit 15 for
* the pairwise keyidx 1 which is hopefully high enough
* to not clash with future extensions.
+ *
+ * Use bit 13 and 14 for CIGTK (key_idx is 0 or 1).
*/
if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE))
wpa_s->keys_cleared &= ~BIT(15);
+ else if (key_flag & KEY_FLAG_CIGTK)
+ wpa_s->keys_cleared &= ~BIT(key_idx + 13);
else if (key_idx >= 0 && key_idx <= 5)
wpa_s->keys_cleared &= ~BIT(key_idx);
else
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 1bc91afcb9..3f7ea41f0b 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -942,6 +942,15 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
}
+ /* CIGTK Key ID is tracked in bit 13 and 14 */
+ if (~wpa_s->keys_cleared & (BIT(13) | BIT(14))) {
+ if (!(wpa_s->keys_cleared & BIT(13)))
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 0, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_CIGTK);
+ if (!(wpa_s->keys_cleared & BIT(14)))
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_CIGTK);
+ }
wpa_s->keys_cleared = (u32) -1;
}
--
2.56.0
More information about the Hostap
mailing list