aboutsummaryrefslogtreecommitdiff
path: root/src/common/wpa_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/wpa_common.c')
-rw-r--r--src/common/wpa_common.c791
1 files changed, 583 insertions, 208 deletions
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index b78db05a..15ebcabb 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -36,6 +36,9 @@ static unsigned int wpa_kck_len(int akmp, size_t pmk_len)
return pmk_len / 2;
case WPA_KEY_MGMT_OWE:
return pmk_len / 2;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len / 2;
default:
return 16;
}
@@ -72,6 +75,9 @@ static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
return pmk_len <= 32 ? 16 : 32;
case WPA_KEY_MGMT_OWE:
return pmk_len <= 32 ? 16 : 32;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len <= 32 ? 16 : 32;
default:
return 16;
}
@@ -108,6 +114,9 @@ unsigned int wpa_mic_len(int akmp, size_t pmk_len)
return pmk_len / 2;
case WPA_KEY_MGMT_OWE:
return pmk_len / 2;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len / 2;
default:
return 16;
}
@@ -143,7 +152,8 @@ int wpa_use_cmac(int akmp)
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_ft(akmp) ||
wpa_key_mgmt_sha256(akmp) ||
- wpa_key_mgmt_sae(akmp) ||
+ (wpa_key_mgmt_sae(akmp) &&
+ !wpa_key_mgmt_sae_ext_key(akmp)) ||
wpa_key_mgmt_suite_b(akmp);
}
@@ -223,6 +233,32 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
return omac1_aes_128(key, buf, len, mic);
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - SAE-EXT-KEY)",
+ (unsigned int) key_len * 8 * 2);
+ if (key_len == 128 / 8) {
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+#ifdef CONFIG_SHA384
+ } else if (key_len == 192 / 8) {
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ } else if (key_len == 256 / 8) {
+ if (hmac_sha512(key, key_len, buf, len, hash))
+ return -1;
+#endif /* CONFIG_SHA512 */
+ } else {
+ wpa_printf(MSG_INFO,
+ "SAE: Unsupported KCK length: %u",
+ (unsigned int) key_len);
+ return -1;
+ }
+ os_memcpy(mic, hash, key_len);
+ break;
#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
case WPA_KEY_MGMT_OSEN:
@@ -473,6 +509,36 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
(unsigned int) pmk_len);
return -1;
#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ } else if (wpa_key_mgmt_sae_ext_key(akmp)) {
+ if (pmk_len == 32) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#ifdef CONFIG_SHA384
+ } else if (pmk_len == 48) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ } else if (pmk_len == 64) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#endif /* CONFIG_SHA512 */
+ } else {
+ wpa_printf(MSG_INFO, "SAE: Unknown PMK length %u",
+ (unsigned int) pmk_len);
+ return -1;
+ }
+#endif /* CONFIG_SAE */
} else {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
@@ -816,7 +882,7 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *ap_addr, u8 transaction_seqnum,
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
@@ -828,8 +894,9 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *addr[10];
size_t len[10];
size_t i, num_elem = 0;
- u8 zero_mic[24];
+ u8 zero_mic[32];
size_t mic_len, fte_fixed_len;
+ int res;
if (kck_len == 16) {
mic_len = 16;
@@ -837,6 +904,10 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
} else if (kck_len == 24) {
mic_len = 24;
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ } else if (kck_len == 32) {
+ mic_len = 32;
+#endif /* CONFIG_SHA512 */
} else {
wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
(unsigned int) kck_len);
@@ -901,6 +972,17 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (kck_len == 32) {
+ u8 hash[SHA512_MAC_LEN];
+
+ if (hmac_sha512_vector(kck, kck_len, num_elem, addr, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 32);
+ res = 0;
+ }
+#endif /* CONFIG_SHA384 */
#ifdef CONFIG_SHA384
if (kck_len == 24) {
u8 hash[SHA384_MAC_LEN];
@@ -908,26 +990,34 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
return -1;
os_memcpy(mic, hash, 24);
+ res = 0;
}
#endif /* CONFIG_SHA384 */
- if (kck_len == 16 &&
- omac1_aes_128_vector(kck, num_elem, addr, len, mic))
- return -1;
+ if (kck_len == 16 && key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ u8 hash[SHA256_MAC_LEN];
- return 0;
+ if (hmac_sha256_vector(kck, kck_len, num_elem, addr, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 16);
+ res = 0;
+ }
+ if (kck_len == 16 && key_mgmt != WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+ omac1_aes_128_vector(kck, num_elem, addr, len, mic) == 0)
+ res = 0;
+
+ return res;
}
static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
- struct wpa_ft_ies *parse, int use_sha384)
+ struct wpa_ft_ies *parse, const u8 *opt)
{
const u8 *end, *pos;
parse->ftie = ie;
parse->ftie_len = ie_len;
- pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
- sizeof(struct rsn_ftie));
+ pos = opt;
end = ie + ie_len;
wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
@@ -938,7 +1028,7 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
len = *pos++;
if (len > end - pos) {
wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
- break;
+ return -1;
}
switch (id) {
@@ -950,8 +1040,11 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
return -1;
}
parse->r1kh_id = pos;
+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
+ parse->r1kh_id, FT_R1KH_ID_LEN);
break;
case FTIE_SUBELEM_GTK:
+ wpa_printf(MSG_DEBUG, "FT: GTK");
parse->gtk = pos;
parse->gtk_len = len;
break;
@@ -964,8 +1057,11 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
}
parse->r0kh_id = pos;
parse->r0kh_id_len = len;
+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
+ parse->r0kh_id, parse->r0kh_id_len);
break;
case FTIE_SUBELEM_IGTK:
+ wpa_printf(MSG_DEBUG, "FT: IGTK");
parse->igtk = pos;
parse->igtk_len = len;
break;
@@ -973,9 +1069,12 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
case FTIE_SUBELEM_OCI:
parse->oci = pos;
parse->oci_len = len;
+ wpa_hexdump(MSG_DEBUG, "FT: OCI",
+ parse->oci, parse->oci_len);
break;
#endif /* CONFIG_OCV */
case FTIE_SUBELEM_BIGTK:
+ wpa_printf(MSG_DEBUG, "FT: BIGTK");
parse->bigtk = pos;
parse->bigtk_len = len;
break;
@@ -991,20 +1090,73 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
}
-int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
- struct wpa_ft_ies *parse, int use_sha384)
+static int wpa_ft_parse_fte(int key_mgmt, const u8 *ie, size_t len,
+ struct wpa_ft_ies *parse)
+{
+ size_t mic_len;
+ u8 mic_len_info;
+ const u8 *pos = ie;
+ const u8 *end = pos + len;
+
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", pos, 2);
+ parse->fte_rsnxe_used = pos[0] & FTE_MIC_CTRL_RSNXE_USED;
+ mic_len_info = (pos[0] & FTE_MIC_CTRL_MIC_LEN_MASK) >>
+ FTE_MIC_CTRL_MIC_LEN_SHIFT;
+ parse->fte_elem_count = pos[1];
+ pos += 2;
+
+ if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ switch (mic_len_info) {
+ case FTE_MIC_LEN_16:
+ mic_len = 16;
+ break;
+ case FTE_MIC_LEN_24:
+ mic_len = 24;
+ break;
+ case FTE_MIC_LEN_32:
+ mic_len = 32;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "FT: Unknown MIC Length subfield value %u",
+ mic_len_info);
+ return -1;
+ }
+ } else {
+ mic_len = wpa_key_mgmt_sha384(key_mgmt) ? 24 : 16;
+ }
+ if (mic_len > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "FT: No room for %zu octet MIC in FTE",
+ mic_len);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len);
+ parse->fte_mic = pos;
+ parse->fte_mic_len = mic_len;
+ pos += mic_len;
+
+ if (2 * WPA_NONCE_LEN > end - pos)
+ return -1;
+ parse->fte_anonce = pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
+ parse->fte_anonce, WPA_NONCE_LEN);
+ pos += WPA_NONCE_LEN;
+ parse->fte_snonce = pos;
+ wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
+ parse->fte_snonce, WPA_NONCE_LEN);
+ pos += WPA_NONCE_LEN;
+
+ return wpa_ft_parse_ftie(ie, len, parse, pos);
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
+ int key_mgmt)
{
const u8 *end, *pos;
struct wpa_ie_data data;
int ret;
- const struct rsn_ftie *ftie;
int prot_ie_count = 0;
- int update_use_sha384 = 0;
-
- if (use_sha384 < 0) {
- use_sha384 = 0;
- update_use_sha384 = 1;
- }
os_memset(parse, 0, sizeof(*parse));
if (ies == NULL)
@@ -1038,11 +1190,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
parse->rsn_pmkid = data.pmkid;
parse->key_mgmt = data.key_mgmt;
parse->pairwise_cipher = data.pairwise_cipher;
- if (update_use_sha384) {
- use_sha384 =
- wpa_key_mgmt_sha384(parse->key_mgmt);
- update_use_sha384 = 0;
- }
+ if (!key_mgmt)
+ key_mgmt = parse->key_mgmt;
break;
case WLAN_EID_RSNX:
wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
@@ -1060,47 +1209,19 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
break;
case WLAN_EID_FAST_BSS_TRANSITION:
wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
- if (use_sha384) {
- const struct rsn_ftie_sha384 *ftie_sha384;
-
- if (len < sizeof(*ftie_sha384))
- return -1;
- ftie_sha384 =
- (const struct rsn_ftie_sha384 *) pos;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
- ftie_sha384->mic_control, 2);
- wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
- ftie_sha384->mic,
- sizeof(ftie_sha384->mic));
- parse->fte_anonce = ftie_sha384->anonce;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
- ftie_sha384->anonce,
- WPA_NONCE_LEN);
- parse->fte_snonce = ftie_sha384->snonce;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
- ftie_sha384->snonce,
- WPA_NONCE_LEN);
- prot_ie_count = ftie_sha384->mic_control[1];
- if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
- return -1;
- break;
- }
-
- if (len < sizeof(*ftie))
+ /* The first two octets (MIC Control field) is in the
+ * same offset for all cases, but the second field (MIC)
+ * has variable length with three different values.
+ * In particular the FT-SAE-EXT-KEY is inconvinient to
+ * parse, so try to handle this in pieces instead of
+ * using the struct rsn_ftie* definitions. */
+
+ if (len < 2)
return -1;
- ftie = (const struct rsn_ftie *) pos;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
- ftie->mic_control, 2);
- wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
- ftie->mic, sizeof(ftie->mic));
- parse->fte_anonce = ftie->anonce;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
- ftie->anonce, WPA_NONCE_LEN);
- parse->fte_snonce = ftie->snonce;
- wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
- ftie->snonce, WPA_NONCE_LEN);
- prot_ie_count = ftie->mic_control[1];
- if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
+ prot_ie_count = pos[1]; /* Element Count field in
+ * MIC Control */
+
+ if (wpa_ft_parse_fte(key_mgmt, pos, len, parse) < 0)
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
@@ -1183,7 +1304,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
* PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers
* 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used.
*/
-static bool pasn_use_sha384(int akmp, int cipher)
+bool pasn_use_sha384(int akmp, int cipher)
{
return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 ||
cipher == WPA_CIPHER_GCMP_256)) ||
@@ -1318,6 +1439,62 @@ u8 pasn_mic_len(int akmp, int cipher)
/**
+ * wpa_ltf_keyseed - Compute LTF keyseed from KDK
+ * @ptk: Buffer that holds pairwise transient key
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher)
+{
+ u8 *buf;
+ size_t buf_len;
+ u8 hash[SHA384_MAC_LEN];
+ const u8 *kdk = ptk->kdk;
+ size_t kdk_len = ptk->kdk_len;
+ const char *label = "Secure LTF key seed";
+
+ if (!kdk || !kdk_len) {
+ wpa_printf(MSG_ERROR, "WPA: No KDK for LTF keyseed generation");
+ return -1;
+ }
+
+ buf = (u8 *)label;
+ buf_len = os_strlen(label);
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Secure LTF keyseed using HMAC-SHA384");
+
+ if (hmac_sha384(kdk, kdk_len, buf, buf_len, hash)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: HMAC-SHA384 compute failed");
+ return -1;
+ }
+ os_memcpy(ptk->ltf_keyseed, hash, SHA384_MAC_LEN);
+ ptk->ltf_keyseed_len = SHA384_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
+ ptk->ltf_keyseed, ptk->ltf_keyseed_len);
+
+ } else {
+ wpa_printf(MSG_DEBUG, "WPA: LTF keyseed using HMAC-SHA256");
+
+ if (hmac_sha256(kdk, kdk_len, buf, buf_len, hash)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: HMAC-SHA256 compute failed");
+ return -1;
+ }
+ os_memcpy(ptk->ltf_keyseed, hash, SHA256_MAC_LEN);
+ ptk->ltf_keyseed_len = SHA256_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
+ ptk->ltf_keyseed, ptk->ltf_keyseed_len);
+ }
+
+ return 0;
+}
+
+
+/**
* pasn_mic - Calculate PASN MIC
* @kck: The key confirmation key for the PASN PTKSA
* @akmp: Negotiated AKM
@@ -1479,8 +1656,12 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
+ return WPA_KEY_MGMT_SAE_EXT_KEY;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
return WPA_KEY_MGMT_FT_SAE;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
+ return WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
@@ -1599,6 +1780,13 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
"%s: invalid group cipher 0x%x (%08x)",
__func__, data->group_cipher,
WPA_GET_BE32(pos));
+#ifdef CONFIG_NO_TKIP
+ if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) {
+ wpa_printf(MSG_DEBUG,
+ "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build",
+ __func__);
+ }
+#endif /* CONFIG_NO_TKIP */
return -1;
}
pos += RSN_SELECTOR_LEN;
@@ -1855,30 +2043,40 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
- int use_sha384)
+ int key_mgmt)
{
u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
- u8 *pos, r0_key_data[64], hash[48];
+ u8 *pos, r0_key_data[64 + 16], hash[64];
const u8 *addr[2];
size_t len[2];
- size_t q = use_sha384 ? 48 : 32;
- size_t r0_key_data_len = q + 16;
+ size_t q, r0_key_data_len;
+ int res;
+
+ if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+ (xxkey_len == SHA256_MAC_LEN || xxkey_len == SHA384_MAC_LEN ||
+ xxkey_len == SHA512_MAC_LEN))
+ q = xxkey_len;
+ else if (wpa_key_mgmt_sha384(key_mgmt))
+ q = SHA384_MAC_LEN;
+ else
+ q = SHA256_MAC_LEN;
+ r0_key_data_len = q + 16;
/*
- * R0-Key-Data = KDF-384(XXKey, "FT-R0",
+ * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
* XXKey is either the second 256 bits of MSK or PSK; or the first
- * 384 bits of MSK for FT-EAP-SHA384.
+ * 384 bits of MSK for FT-EAP-SHA384; or PMK from SAE.
* PMK-R0 = L(R0-Key-Data, 0, Q)
* PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
- * Q = 384 for FT-EAP-SHA384; otherwise, 256
+ * Q = 384 for FT-EAP-SHA384; the length of the digest generated by H()
+ * for FT-SAE-EXT-KEY; or otherwise, 256
*/
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return -1;
- wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
- use_sha384 ? "SHA384" : "SHA256");
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-SHA%zu", q * 8);
wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
@@ -1896,30 +2094,43 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (q == SHA512_MAC_LEN) {
+ if (xxkey_len != SHA512_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected XXKey length %d (expected %d)",
+ (int) xxkey_len, SHA512_MAC_LEN);
+ return -1;
+ }
+ res = sha512_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len);
+ }
+#endif /* CONFIG_SHA512 */
#ifdef CONFIG_SHA384
- if (use_sha384) {
+ if (q == SHA384_MAC_LEN) {
if (xxkey_len != SHA384_MAC_LEN) {
wpa_printf(MSG_ERROR,
"FT: Unexpected XXKey length %d (expected %d)",
(int) xxkey_len, SHA384_MAC_LEN);
return -1;
}
- if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, r0_key_data_len) < 0)
- return -1;
+ res = sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len);
}
#endif /* CONFIG_SHA384 */
- if (!use_sha384) {
+ if (q == SHA256_MAC_LEN) {
if (xxkey_len != PMK_LEN) {
wpa_printf(MSG_ERROR,
"FT: Unexpected XXKey length %d (expected %d)",
(int) xxkey_len, PMK_LEN);
return -1;
}
- if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, r0_key_data_len) < 0)
- return -1;
+ res = sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, r0_key_data_len);
}
+ if (res < 0)
+ return res;
os_memcpy(pmk_r0, r0_key_data, q);
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
@@ -1932,12 +2143,23 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
addr[1] = &r0_key_data[q];
len[1] = 16;
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (q == SHA512_MAC_LEN)
+ res = sha512_vector(2, addr, len, hash);
+#endif /* CONFIG_SHA512 */
#ifdef CONFIG_SHA384
- if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
- return -1;
+ if (q == SHA384_MAC_LEN)
+ res = sha384_vector(2, addr, len, hash);
#endif /* CONFIG_SHA384 */
- if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
- return -1;
+ if (q == SHA256_MAC_LEN)
+ res = sha256_vector(2, addr, len, hash);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to derive PMKR0Name (PMK-R0 len %zu)",
+ q);
+ return res;
+ }
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
forced_memzero(r0_key_data, sizeof(r0_key_data));
@@ -1951,11 +2173,14 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
+ const u8 *s1kh_id, u8 *pmk_r1_name,
+ size_t pmk_r1_len)
{
- u8 hash[48];
+ u8 hash[64];
const u8 *addr[4];
size_t len[4];
+ int res;
+ const char *title;
/*
* PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
@@ -1970,14 +2195,31 @@ int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (pmk_r1_len == SHA512_MAC_LEN) {
+ title = "FT: PMKR1Name (using SHA512)";
+ res = sha512_vector(4, addr, len, hash);
+ }
+#endif /* CONFIG_SHA512 */
#ifdef CONFIG_SHA384
- if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
- return -1;
+ if (pmk_r1_len == SHA384_MAC_LEN) {
+ title = "FT: PMKR1Name (using SHA384)";
+ res = sha384_vector(4, addr, len, hash);
+ }
#endif /* CONFIG_SHA384 */
- if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
- return -1;
+ if (pmk_r1_len == SHA256_MAC_LEN) {
+ title = "FT: PMKR1Name (using SHA256)";
+ res = sha256_vector(4, addr, len, hash);
+ }
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to derive PMKR1Name (PMK-R1 len %zu)",
+ pmk_r1_len);
+ return res;
+ }
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
+ wpa_hexdump(MSG_DEBUG, title, pmk_r1_name, WPA_PMK_NAME_LEN);
return 0;
}
@@ -1994,10 +2236,11 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
+ int res;
- /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
- wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
- pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
+ /* PMK-R1 = KDF-Hash(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+ wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-SHA%zu",
+ pmk_r0_len * 8);
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
@@ -2007,26 +2250,28 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (pmk_r0_len == SHA512_MAC_LEN)
+ res = sha512_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len);
+#endif /* CONFIG_SHA512 */
#ifdef CONFIG_SHA384
- if (pmk_r0_len == SHA384_MAC_LEN &&
- sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
- buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
- return -1;
+ if (pmk_r0_len == SHA384_MAC_LEN)
+ res = sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len);
#endif /* CONFIG_SHA384 */
- if (pmk_r0_len == PMK_LEN &&
- sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
- buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
- return -1;
- if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
- wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
- (int) pmk_r0_len);
- return -1;
+ if (pmk_r0_len == SHA256_MAC_LEN)
+ res = sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
+ buf, pos - buf, pmk_r1, pmk_r0_len);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FT: Failed to derive PMK-R1");
+ return res;
}
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
- pmk_r1_name,
- pmk_r0_len == SHA384_MAC_LEN);
+ pmk_r1_name, pmk_r0_len);
}
@@ -2049,7 +2294,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
WPA_KDK_MAX_LEN];
size_t ptk_len, offset;
- int use_sha384 = wpa_key_mgmt_sha384(akmp);
+ size_t key_len;
+ int res;
if (kdk_len > WPA_KDK_MAX_LEN) {
wpa_printf(MSG_ERROR,
@@ -2058,12 +2304,20 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
return -1;
}
+ if (akmp == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
+ (pmk_r1_len == SHA256_MAC_LEN || pmk_r1_len == SHA384_MAC_LEN ||
+ pmk_r1_len == SHA512_MAC_LEN))
+ key_len = pmk_r1_len;
+ else if (wpa_key_mgmt_sha384(akmp))
+ key_len = SHA384_MAC_LEN;
+ else
+ key_len = SHA256_MAC_LEN;
+
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
- wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
- use_sha384 ? "SHA384" : "SHA256");
+ wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-SHA%zu", key_len * 8);
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
@@ -2079,39 +2333,52 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
+ ptk->kck_len = wpa_kck_len(akmp, key_len);
ptk->kck2_len = wpa_kck2_len(akmp);
- ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
+ ptk->kek_len = wpa_kek_len(akmp, key_len);
ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk->kdk_len = kdk_len;
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
ptk->kck2_len + ptk->kek2_len + ptk->kdk_len;
+ res = -1;
+#ifdef CONFIG_SHA512
+ if (key_len == SHA512_MAC_LEN) {
+ if (pmk_r1_len != SHA512_MAC_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: Unexpected PMK-R1 length %d (expected %d)",
+ (int) pmk_r1_len, SHA512_MAC_LEN);
+ return -1;
+ }
+ res = sha512_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len);
+ }
+#endif /* CONFIG_SHA512 */
#ifdef CONFIG_SHA384
- if (use_sha384) {
+ if (key_len == SHA384_MAC_LEN) {
if (pmk_r1_len != SHA384_MAC_LEN) {
wpa_printf(MSG_ERROR,
"FT: Unexpected PMK-R1 length %d (expected %d)",
(int) pmk_r1_len, SHA384_MAC_LEN);
return -1;
}
- if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
- buf, pos - buf, tmp, ptk_len) < 0)
- return -1;
+ res = sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len);
}
#endif /* CONFIG_SHA384 */
- if (!use_sha384) {
+ if (key_len == SHA256_MAC_LEN) {
if (pmk_r1_len != PMK_LEN) {
wpa_printf(MSG_ERROR,
"FT: Unexpected PMK-R1 length %d (expected %d)",
(int) pmk_r1_len, PMK_LEN);
return -1;
}
- if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
- buf, pos - buf, tmp, ptk_len) < 0)
- return -1;
+ res = sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
+ buf, pos - buf, tmp, ptk_len);
}
+ if (res < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
/*
@@ -2180,7 +2447,7 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
* @akmp: Negotiated key management protocol
*
* IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy
- * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
+ * AKM: 00-0F-AC:3, 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
* PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA))
* AKM: 00-0F-AC:11
* See rsn_pmkid_suite_b()
@@ -2372,8 +2639,12 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
return "WPS";
case WPA_KEY_MGMT_SAE:
return "SAE";
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ return "SAE-EXT-KEY";
case WPA_KEY_MGMT_FT_SAE:
return "FT-SAE";
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return "FT-SAE-EXT-KEY";
case WPA_KEY_MGMT_OSEN:
return "OSEN";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
@@ -2434,8 +2705,12 @@ u32 wpa_akm_to_suite(int akm)
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
if (akm & WPA_KEY_MGMT_SAE)
return RSN_AUTH_KEY_MGMT_SAE;
+ if (akm & WPA_KEY_MGMT_SAE_EXT_KEY)
+ return RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
if (akm & WPA_KEY_MGMT_FT_SAE)
return RSN_AUTH_KEY_MGMT_FT_SAE;
+ if (akm & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ return RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
if (akm & WPA_KEY_MGMT_OWE)
return RSN_AUTH_KEY_MGMT_OWE;
if (akm & WPA_KEY_MGMT_DPP)
@@ -2595,9 +2870,9 @@ int wpa_cipher_key_len(int cipher)
return 16;
case WPA_CIPHER_TKIP:
return 32;
+ default:
+ return 0;
}
-
- return 0;
}
@@ -2610,9 +2885,9 @@ int wpa_cipher_rsc_len(int cipher)
case WPA_CIPHER_GCMP:
case WPA_CIPHER_TKIP:
return 6;
+ default:
+ return 0;
}
-
- return 0;
}
@@ -2637,8 +2912,9 @@ enum wpa_alg wpa_cipher_to_alg(int cipher)
return WPA_ALG_BIP_GMAC_256;
case WPA_CIPHER_BIP_CMAC_256:
return WPA_ALG_BIP_CMAC_256;
+ default:
+ return WPA_ALG_NONE;
}
- return WPA_ALG_NONE;
}
@@ -3018,120 +3294,190 @@ static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
*/
static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
{
- if (pos[1] == 0)
+ u8 len = pos[1];
+ size_t dlen = 2 + len;
+ u32 selector;
+ const u8 *p;
+ size_t left;
+ u8 link_id;
+ char title[50];
+ int ret;
+
+ if (len == 0)
return 1;
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ if (len < RSN_SELECTOR_LEN)
+ return 2;
+
+ p = pos + 2;
+ selector = RSN_SELECTOR_GET(p);
+ p += RSN_SELECTOR_LEN;
+ left = len - RSN_SELECTOR_LEN;
+
+ if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) {
ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
+ ie->wpa_ie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
ie->wpa_ie, ie->wpa_ie_len);
return 0;
}
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ if (selector == OSEN_IE_VENDOR_TYPE) {
ie->osen = pos;
- ie->osen_len = pos[1] + 2;
+ ie->osen_len = dlen;
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = p;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
- ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= 2 && selector == RSN_KEY_DATA_KEYID) {
+ ie->key_id = p;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = p;
+ ie->gtk_len = left;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= ETH_ALEN && selector == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = p;
+ wpa_printf(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key: " MACSTR,
+ MAC2STR(ie->mac_addr));
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_IGTK) {
+ ie->igtk = p;
+ ie->igtk_len = left;
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
- ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_BIGTK) {
+ ie->bigtk = p;
+ ie->bigtk_len = left;
wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ 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",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ ie->ip_addr_req, left);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ if (left >= 3 * 4 && selector == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = p;
wpa_hexdump(MSG_DEBUG,
"WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ ie->ip_addr_alloc, left);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_OCI) {
+ ie->oci = p;
+ ie->oci_len = left;
wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
- ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
- ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) {
+ ie->transition_disable = p;
+ ie->transition_disable_len = left;
wpa_hexdump(MSG_DEBUG,
"WPA: Transition Disable KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
+ return 0;
+ }
+
+ if (left >= 2 && selector == WFA_KEY_DATA_DPP) {
+ ie->dpp_kde = p;
+ ie->dpp_kde_len = left;
+ wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen);
+ return 0;
+ }
+
+ if (left >= RSN_MLO_GTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_GTK) {
+ link_id = (p[0] & RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK) >>
+ RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_gtks |= BIT(link_id);
+ ie->mlo_gtk[link_id] = p;
+ ie->mlo_gtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO GTK 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_IGTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_IGTK) {
+ link_id = (p[8] & RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+ RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_igtks |= BIT(link_id);
+ ie->mlo_igtk[link_id] = p;
+ ie->mlo_igtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO IGTK KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_DPP) {
- ie->dpp_kde = pos + 2 + RSN_SELECTOR_LEN;
- ie->dpp_kde_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= RSN_MLO_BIGTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_BIGTK) {
+ link_id = (p[8] & RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+ RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_bigtks |= BIT(link_id);
+ ie->mlo_bigtk[link_id] = p;
+ ie->mlo_bigtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO BIGTK 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) >>
+ RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_links |= BIT(link_id);
+ ie->mlo_link[link_id] = p;
+ ie->mlo_link_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO Link KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump(MSG_DEBUG, title, pos, dlen);
return 0;
}
@@ -3150,15 +3496,17 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
{
const u8 *pos, *end;
int ret = 0;
+ size_t dlen = 0;
os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
- if (2 + pos[1] > end - pos) {
+ dlen = 2 + pos[1];
+ if ((int) dlen > end - pos) {
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
@@ -3168,22 +3516,22 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
}
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
+ ie->rsn_ie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
ie->rsn_ie, ie->rsn_ie_len);
} else if (*pos == WLAN_EID_RSNX) {
ie->rsnxe = pos;
- ie->rsnxe_len = pos[1] + 2;
+ ie->rsnxe_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
ie->rsnxe, ie->rsnxe_len);
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
+ ie->mdie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
ie->mdie, ie->mdie_len);
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
+ ie->ftie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
ie->ftie, ie->ftie_len);
} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
@@ -3191,31 +3539,31 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
ie->reassoc_deadline = pos;
wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
"in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
+ ie->reassoc_deadline, dlen);
} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
ie->key_lifetime = pos;
wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
"in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
+ ie->key_lifetime, dlen);
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
"EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
+ pos, dlen);
}
} else if (*pos == WLAN_EID_LINK_ID) {
if (pos[1] >= 18) {
ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
+ ie->lnkid_len = dlen;
}
} else if (*pos == WLAN_EID_EXT_CAPAB) {
ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
+ ie->ext_capab_len = dlen;
} else if (*pos == WLAN_EID_SUPP_RATES) {
ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
+ ie->supp_rates_len = dlen;
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
+ ie->ext_supp_rates_len = dlen;
} else if (*pos == WLAN_EID_HT_CAP &&
pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
ie->ht_capabilities = pos + 2;
@@ -3269,7 +3617,7 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
} else {
wpa_hexdump(MSG_DEBUG,
"WPA: Unrecognized EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
+ pos, dlen);
}
}
@@ -3368,6 +3716,9 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
case WPA_KEY_MGMT_SAE:
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
+ break;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
case WPA_KEY_MGMT_FILS_SHA256:
@@ -3581,6 +3932,7 @@ int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
switch (data->key_mgmt) {
#ifdef CONFIG_SAE
case WPA_KEY_MGMT_SAE:
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
/* fall through */
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
@@ -3734,4 +4086,27 @@ void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab)
wpabuf_put_u8(buf, capab);
}
+
+/*
+ * wpa_pasn_add_extra_ies - Add protocol specific IEs in Authentication
+ * frame for PASN.
+ *
+ * @buf: Buffer in which the elements will be added
+ * @extra_ies: Protocol specific elements to add
+ * @len: Length of the elements
+ * Returns: 0 on success, -1 on failure
+ */
+
+int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len)
+{
+ if (!len || !extra_ies || !buf)
+ return 0;
+
+ if (wpabuf_tailroom(buf) < sizeof(len))
+ return -1;
+
+ wpabuf_put_data(buf, extra_ies, len);
+ return 0;
+}
+
#endif /* CONFIG_PASN */