xref: /freebsd/contrib/wpa/src/common/wpa_common.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * WPA/RSN - Shared functions for supplicant and authenticator
385732ac8SCy Schubert  * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "crypto/md5.h"
13e28a4053SRui Paulo #include "crypto/sha1.h"
14e28a4053SRui Paulo #include "crypto/sha256.h"
155b9c547cSRui Paulo #include "crypto/sha384.h"
1685732ac8SCy Schubert #include "crypto/sha512.h"
17e28a4053SRui Paulo #include "crypto/aes_wrap.h"
18e28a4053SRui Paulo #include "crypto/crypto.h"
1939beb93cSSam Leffler #include "ieee802_11_defs.h"
20*a90b9d01SCy Schubert #include "ieee802_11_common.h"
2139beb93cSSam Leffler #include "defs.h"
2239beb93cSSam Leffler #include "wpa_common.h"
2339beb93cSSam Leffler 
2439beb93cSSam Leffler 
wpa_kck_len(int akmp,size_t pmk_len)2585732ac8SCy Schubert static unsigned int wpa_kck_len(int akmp, size_t pmk_len)
265b9c547cSRui Paulo {
2785732ac8SCy Schubert 	switch (akmp) {
2885732ac8SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
29*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SHA384:
3085732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
315b9c547cSRui Paulo 		return 24;
3285732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
3385732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
3485732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
3585732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
3685732ac8SCy Schubert 		return 0;
3785732ac8SCy Schubert 	case WPA_KEY_MGMT_DPP:
3885732ac8SCy Schubert 		return pmk_len / 2;
3985732ac8SCy Schubert 	case WPA_KEY_MGMT_OWE:
4085732ac8SCy Schubert 		return pmk_len / 2;
41*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
42*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
43*a90b9d01SCy Schubert 		return pmk_len / 2;
4485732ac8SCy Schubert 	default:
455b9c547cSRui Paulo 		return 16;
465b9c547cSRui Paulo 	}
4785732ac8SCy Schubert }
485b9c547cSRui Paulo 
495b9c547cSRui Paulo 
5085732ac8SCy Schubert #ifdef CONFIG_IEEE80211R
wpa_kck2_len(int akmp)5185732ac8SCy Schubert static unsigned int wpa_kck2_len(int akmp)
525b9c547cSRui Paulo {
5385732ac8SCy Schubert 	switch (akmp) {
5485732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
5585732ac8SCy Schubert 		return 16;
5685732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
5785732ac8SCy Schubert 		return 24;
5885732ac8SCy Schubert 	default:
5985732ac8SCy Schubert 		return 0;
6085732ac8SCy Schubert 	}
6185732ac8SCy Schubert }
6285732ac8SCy Schubert #endif /* CONFIG_IEEE80211R */
6385732ac8SCy Schubert 
6485732ac8SCy Schubert 
wpa_kek_len(int akmp,size_t pmk_len)6585732ac8SCy Schubert static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
6685732ac8SCy Schubert {
6785732ac8SCy Schubert 	switch (akmp) {
6885732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
6985732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
7085732ac8SCy Schubert 		return 64;
7185732ac8SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
7285732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
7385732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
7485732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
75*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SHA384:
765b9c547cSRui Paulo 		return 32;
7785732ac8SCy Schubert 	case WPA_KEY_MGMT_DPP:
7885732ac8SCy Schubert 		return pmk_len <= 32 ? 16 : 32;
7985732ac8SCy Schubert 	case WPA_KEY_MGMT_OWE:
8085732ac8SCy Schubert 		return pmk_len <= 32 ? 16 : 32;
81*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
82*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
83*a90b9d01SCy Schubert 		return pmk_len <= 32 ? 16 : 32;
8485732ac8SCy Schubert 	default:
855b9c547cSRui Paulo 		return 16;
865b9c547cSRui Paulo 	}
8785732ac8SCy Schubert }
885b9c547cSRui Paulo 
895b9c547cSRui Paulo 
9085732ac8SCy Schubert #ifdef CONFIG_IEEE80211R
wpa_kek2_len(int akmp)9185732ac8SCy Schubert static unsigned int wpa_kek2_len(int akmp)
925b9c547cSRui Paulo {
9385732ac8SCy Schubert 	switch (akmp) {
9485732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
955b9c547cSRui Paulo 		return 16;
9685732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
9785732ac8SCy Schubert 		return 32;
9885732ac8SCy Schubert 	default:
9985732ac8SCy Schubert 		return 0;
10085732ac8SCy Schubert 	}
10185732ac8SCy Schubert }
10285732ac8SCy Schubert #endif /* CONFIG_IEEE80211R */
10385732ac8SCy Schubert 
10485732ac8SCy Schubert 
wpa_mic_len(int akmp,size_t pmk_len)10585732ac8SCy Schubert unsigned int wpa_mic_len(int akmp, size_t pmk_len)
10685732ac8SCy Schubert {
10785732ac8SCy Schubert 	switch (akmp) {
10885732ac8SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
10985732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
110*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SHA384:
11185732ac8SCy Schubert 		return 24;
11285732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
11385732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
11485732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
11585732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
11685732ac8SCy Schubert 		return 0;
11785732ac8SCy Schubert 	case WPA_KEY_MGMT_DPP:
11885732ac8SCy Schubert 		return pmk_len / 2;
11985732ac8SCy Schubert 	case WPA_KEY_MGMT_OWE:
12085732ac8SCy Schubert 		return pmk_len / 2;
121*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
122*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
123*a90b9d01SCy Schubert 		return pmk_len / 2;
12485732ac8SCy Schubert 	default:
12585732ac8SCy Schubert 		return 16;
12685732ac8SCy Schubert 	}
12785732ac8SCy Schubert }
12885732ac8SCy Schubert 
12985732ac8SCy Schubert 
13085732ac8SCy Schubert /**
13185732ac8SCy Schubert  * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
13285732ac8SCy Schubert  * @akmp: WPA_KEY_MGMT_* used in key derivation
13385732ac8SCy Schubert  * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
13485732ac8SCy Schubert  */
wpa_use_akm_defined(int akmp)13585732ac8SCy Schubert int wpa_use_akm_defined(int akmp)
13685732ac8SCy Schubert {
13785732ac8SCy Schubert 	return akmp == WPA_KEY_MGMT_OSEN ||
13885732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_OWE ||
13985732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_DPP ||
14085732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
141*a90b9d01SCy Schubert 		akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 ||
14285732ac8SCy Schubert 		wpa_key_mgmt_sae(akmp) ||
14385732ac8SCy Schubert 		wpa_key_mgmt_suite_b(akmp) ||
14485732ac8SCy Schubert 		wpa_key_mgmt_fils(akmp);
14585732ac8SCy Schubert }
14685732ac8SCy Schubert 
14785732ac8SCy Schubert 
14885732ac8SCy Schubert /**
14985732ac8SCy Schubert  * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
15085732ac8SCy Schubert  * @akmp: WPA_KEY_MGMT_* used in key derivation
15185732ac8SCy Schubert  * Returns: 1 if CMAC is used; 0 otherwise
15285732ac8SCy Schubert  */
wpa_use_cmac(int akmp)15385732ac8SCy Schubert int wpa_use_cmac(int akmp)
15485732ac8SCy Schubert {
15585732ac8SCy Schubert 	return akmp == WPA_KEY_MGMT_OSEN ||
15685732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_OWE ||
15785732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_DPP ||
15885732ac8SCy Schubert 		wpa_key_mgmt_ft(akmp) ||
15985732ac8SCy Schubert 		wpa_key_mgmt_sha256(akmp) ||
160*a90b9d01SCy Schubert 		(wpa_key_mgmt_sae(akmp) &&
161*a90b9d01SCy Schubert 		 !wpa_key_mgmt_sae_ext_key(akmp)) ||
16285732ac8SCy Schubert 		wpa_key_mgmt_suite_b(akmp);
16385732ac8SCy Schubert }
16485732ac8SCy Schubert 
16585732ac8SCy Schubert 
16685732ac8SCy Schubert /**
16785732ac8SCy Schubert  * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
16885732ac8SCy Schubert  * @akmp: WPA_KEY_MGMT_* used in key derivation
16985732ac8SCy Schubert  * Returns: 1 if AES Keywrap is used; 0 otherwise
17085732ac8SCy Schubert  *
17185732ac8SCy Schubert  * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
17285732ac8SCy Schubert  * to use AES Keywrap based on the negotiated pairwise cipher. This function
17385732ac8SCy Schubert  * does not cover those special cases.
17485732ac8SCy Schubert  */
wpa_use_aes_key_wrap(int akmp)17585732ac8SCy Schubert int wpa_use_aes_key_wrap(int akmp)
17685732ac8SCy Schubert {
17785732ac8SCy Schubert 	return akmp == WPA_KEY_MGMT_OSEN ||
17885732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_OWE ||
17985732ac8SCy Schubert 		akmp == WPA_KEY_MGMT_DPP ||
180*a90b9d01SCy Schubert 		akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 ||
18185732ac8SCy Schubert 		wpa_key_mgmt_ft(akmp) ||
18285732ac8SCy Schubert 		wpa_key_mgmt_sha256(akmp) ||
18385732ac8SCy Schubert 		wpa_key_mgmt_sae(akmp) ||
18485732ac8SCy Schubert 		wpa_key_mgmt_suite_b(akmp);
1855b9c547cSRui Paulo }
1865b9c547cSRui Paulo 
1875b9c547cSRui Paulo 
18839beb93cSSam Leffler /**
18939beb93cSSam Leffler  * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
19039beb93cSSam Leffler  * @key: EAPOL-Key Key Confirmation Key (KCK)
1915b9c547cSRui Paulo  * @key_len: KCK length in octets
1925b9c547cSRui Paulo  * @akmp: WPA_KEY_MGMT_* used in key derivation
19339beb93cSSam Leffler  * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
19439beb93cSSam Leffler  * @buf: Pointer to the beginning of the EAPOL header (version field)
19539beb93cSSam Leffler  * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
19639beb93cSSam Leffler  * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
19739beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
19839beb93cSSam Leffler  *
19939beb93cSSam Leffler  * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
20039beb93cSSam Leffler  * to be cleared (all zeroes) when calling this function.
20139beb93cSSam Leffler  *
20239beb93cSSam Leffler  * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
20339beb93cSSam Leffler  * description of the Key MIC calculation. It includes packet data from the
20439beb93cSSam Leffler  * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
20539beb93cSSam Leffler  * happened during final editing of the standard and the correct behavior is
20639beb93cSSam Leffler  * defined in the last draft (IEEE 802.11i/D10).
20739beb93cSSam Leffler  */
wpa_eapol_key_mic(const u8 * key,size_t key_len,int akmp,int ver,const u8 * buf,size_t len,u8 * mic)2085b9c547cSRui Paulo int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
2095b9c547cSRui Paulo 		      const u8 *buf, size_t len, u8 *mic)
21039beb93cSSam Leffler {
21185732ac8SCy Schubert 	u8 hash[SHA512_MAC_LEN];
21285732ac8SCy Schubert 
21385732ac8SCy Schubert 	if (key_len == 0) {
21485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
21585732ac8SCy Schubert 			   "WPA: KCK not set - cannot calculate MIC");
21685732ac8SCy Schubert 		return -1;
21785732ac8SCy Schubert 	}
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	switch (ver) {
220f05cddf9SRui Paulo #ifndef CONFIG_FIPS
22139beb93cSSam Leffler 	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
22285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5");
2235b9c547cSRui Paulo 		return hmac_md5(key, key_len, buf, len, mic);
224f05cddf9SRui Paulo #endif /* CONFIG_FIPS */
22539beb93cSSam Leffler 	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
22685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1");
2275b9c547cSRui Paulo 		if (hmac_sha1(key, key_len, buf, len, hash))
228e28a4053SRui Paulo 			return -1;
22939beb93cSSam Leffler 		os_memcpy(mic, hash, MD5_MAC_LEN);
23039beb93cSSam Leffler 		break;
23139beb93cSSam Leffler 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
23285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
23339beb93cSSam Leffler 		return omac1_aes_128(key, buf, len, mic);
2345b9c547cSRui Paulo 	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
2355b9c547cSRui Paulo 		switch (akmp) {
23685732ac8SCy Schubert #ifdef CONFIG_SAE
23785732ac8SCy Schubert 		case WPA_KEY_MGMT_SAE:
23885732ac8SCy Schubert 		case WPA_KEY_MGMT_FT_SAE:
23985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
24085732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
24185732ac8SCy Schubert 			return omac1_aes_128(key, buf, len, mic);
242*a90b9d01SCy Schubert 		case WPA_KEY_MGMT_SAE_EXT_KEY:
243*a90b9d01SCy Schubert 		case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
244*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
245*a90b9d01SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - SAE-EXT-KEY)",
246*a90b9d01SCy Schubert 				   (unsigned int) key_len * 8 * 2);
247*a90b9d01SCy Schubert 			if (key_len == 128 / 8) {
248*a90b9d01SCy Schubert 				if (hmac_sha256(key, key_len, buf, len, hash))
249*a90b9d01SCy Schubert 					return -1;
250*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
251*a90b9d01SCy Schubert 			} else if (key_len == 192 / 8) {
252*a90b9d01SCy Schubert 				if (hmac_sha384(key, key_len, buf, len, hash))
253*a90b9d01SCy Schubert 					return -1;
254*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
255*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
256*a90b9d01SCy Schubert 			} else if (key_len == 256 / 8) {
257*a90b9d01SCy Schubert 				if (hmac_sha512(key, key_len, buf, len, hash))
258*a90b9d01SCy Schubert 					return -1;
259*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
260*a90b9d01SCy Schubert 			} else {
261*a90b9d01SCy Schubert 				wpa_printf(MSG_INFO,
262*a90b9d01SCy Schubert 					   "SAE: Unsupported KCK length: %u",
263*a90b9d01SCy Schubert 					   (unsigned int) key_len);
264*a90b9d01SCy Schubert 				return -1;
265*a90b9d01SCy Schubert 			}
266*a90b9d01SCy Schubert 			os_memcpy(mic, hash, key_len);
267*a90b9d01SCy Schubert 			break;
26885732ac8SCy Schubert #endif /* CONFIG_SAE */
2695b9c547cSRui Paulo #ifdef CONFIG_HS20
2705b9c547cSRui Paulo 		case WPA_KEY_MGMT_OSEN:
27185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
27285732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)");
2735b9c547cSRui Paulo 			return omac1_aes_128(key, buf, len, mic);
2745b9c547cSRui Paulo #endif /* CONFIG_HS20 */
2755b9c547cSRui Paulo #ifdef CONFIG_SUITEB
2765b9c547cSRui Paulo 		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
27785732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
27885732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)");
2795b9c547cSRui Paulo 			if (hmac_sha256(key, key_len, buf, len, hash))
2805b9c547cSRui Paulo 				return -1;
2815b9c547cSRui Paulo 			os_memcpy(mic, hash, MD5_MAC_LEN);
2825b9c547cSRui Paulo 			break;
2835b9c547cSRui Paulo #endif /* CONFIG_SUITEB */
2845b9c547cSRui Paulo #ifdef CONFIG_SUITEB192
2855b9c547cSRui Paulo 		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
28685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
28785732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)");
2885b9c547cSRui Paulo 			if (hmac_sha384(key, key_len, buf, len, hash))
2895b9c547cSRui Paulo 				return -1;
2905b9c547cSRui Paulo 			os_memcpy(mic, hash, 24);
2915b9c547cSRui Paulo 			break;
2925b9c547cSRui Paulo #endif /* CONFIG_SUITEB192 */
29385732ac8SCy Schubert #ifdef CONFIG_OWE
29485732ac8SCy Schubert 		case WPA_KEY_MGMT_OWE:
29585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
29685732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)",
29785732ac8SCy Schubert 				   (unsigned int) key_len * 8 * 2);
29885732ac8SCy Schubert 			if (key_len == 128 / 8) {
29985732ac8SCy Schubert 				if (hmac_sha256(key, key_len, buf, len, hash))
30085732ac8SCy Schubert 					return -1;
30185732ac8SCy Schubert 			} else if (key_len == 192 / 8) {
30285732ac8SCy Schubert 				if (hmac_sha384(key, key_len, buf, len, hash))
30385732ac8SCy Schubert 					return -1;
30485732ac8SCy Schubert 			} else if (key_len == 256 / 8) {
30585732ac8SCy Schubert 				if (hmac_sha512(key, key_len, buf, len, hash))
30685732ac8SCy Schubert 					return -1;
30785732ac8SCy Schubert 			} else {
30885732ac8SCy Schubert 				wpa_printf(MSG_INFO,
30985732ac8SCy Schubert 					   "OWE: Unsupported KCK length: %u",
31085732ac8SCy Schubert 					   (unsigned int) key_len);
31185732ac8SCy Schubert 				return -1;
31285732ac8SCy Schubert 			}
31385732ac8SCy Schubert 			os_memcpy(mic, hash, key_len);
31485732ac8SCy Schubert 			break;
31585732ac8SCy Schubert #endif /* CONFIG_OWE */
31685732ac8SCy Schubert #ifdef CONFIG_DPP
31785732ac8SCy Schubert 		case WPA_KEY_MGMT_DPP:
31885732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
31985732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - DPP)",
32085732ac8SCy Schubert 				   (unsigned int) key_len * 8 * 2);
32185732ac8SCy Schubert 			if (key_len == 128 / 8) {
32285732ac8SCy Schubert 				if (hmac_sha256(key, key_len, buf, len, hash))
32385732ac8SCy Schubert 					return -1;
32485732ac8SCy Schubert 			} else if (key_len == 192 / 8) {
32585732ac8SCy Schubert 				if (hmac_sha384(key, key_len, buf, len, hash))
32685732ac8SCy Schubert 					return -1;
32785732ac8SCy Schubert 			} else if (key_len == 256 / 8) {
32885732ac8SCy Schubert 				if (hmac_sha512(key, key_len, buf, len, hash))
32985732ac8SCy Schubert 					return -1;
33085732ac8SCy Schubert 			} else {
33185732ac8SCy Schubert 				wpa_printf(MSG_INFO,
33285732ac8SCy Schubert 					   "DPP: Unsupported KCK length: %u",
33385732ac8SCy Schubert 					   (unsigned int) key_len);
33485732ac8SCy Schubert 				return -1;
33585732ac8SCy Schubert 			}
33685732ac8SCy Schubert 			os_memcpy(mic, hash, key_len);
33785732ac8SCy Schubert 			break;
33885732ac8SCy Schubert #endif /* CONFIG_DPP */
339*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
340*a90b9d01SCy Schubert 		case WPA_KEY_MGMT_IEEE8021X_SHA384:
341*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
34285732ac8SCy Schubert 		case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
343*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
34485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
345*a90b9d01SCy Schubert 				   "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - 802.1X SHA384)");
34685732ac8SCy Schubert 			if (hmac_sha384(key, key_len, buf, len, hash))
34785732ac8SCy Schubert 				return -1;
34885732ac8SCy Schubert 			os_memcpy(mic, hash, 24);
34985732ac8SCy Schubert 			break;
350*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
3515b9c547cSRui Paulo 		default:
35285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
35385732ac8SCy Schubert 				   "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
35485732ac8SCy Schubert 				   akmp);
3555b9c547cSRui Paulo 			return -1;
3565b9c547cSRui Paulo 		}
3575b9c547cSRui Paulo 		break;
35839beb93cSSam Leffler 	default:
35985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
36085732ac8SCy Schubert 			   "WPA: EAPOL-Key MIC algorithm not known (ver=%d)",
36185732ac8SCy Schubert 			   ver);
36239beb93cSSam Leffler 		return -1;
36339beb93cSSam Leffler 	}
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 	return 0;
36639beb93cSSam Leffler }
36739beb93cSSam Leffler 
36839beb93cSSam Leffler 
36939beb93cSSam Leffler /**
37039beb93cSSam Leffler  * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
37139beb93cSSam Leffler  * @pmk: Pairwise master key
37239beb93cSSam Leffler  * @pmk_len: Length of PMK
37339beb93cSSam Leffler  * @label: Label to use in derivation
37439beb93cSSam Leffler  * @addr1: AA or SA
37539beb93cSSam Leffler  * @addr2: SA or AA
37639beb93cSSam Leffler  * @nonce1: ANonce or SNonce
37739beb93cSSam Leffler  * @nonce2: SNonce or ANonce
37839beb93cSSam Leffler  * @ptk: Buffer for pairwise transient key
3795b9c547cSRui Paulo  * @akmp: Negotiated AKM
3805b9c547cSRui Paulo  * @cipher: Negotiated pairwise cipher
381c1d255d3SCy Schubert  * @kdk_len: The length in octets that should be derived for KDK
3825b9c547cSRui Paulo  * Returns: 0 on success, -1 on failure
38339beb93cSSam Leffler  *
38439beb93cSSam Leffler  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
38539beb93cSSam Leffler  * PTK = PRF-X(PMK, "Pairwise key expansion",
38639beb93cSSam Leffler  *             Min(AA, SA) || Max(AA, SA) ||
3874bc52338SCy Schubert  *             Min(ANonce, SNonce) || Max(ANonce, SNonce)
3884bc52338SCy Schubert  *             [ || Z.x ])
3894bc52338SCy Schubert  *
3904bc52338SCy Schubert  * The optional Z.x component is used only with DPP and that part is not defined
3914bc52338SCy Schubert  * in IEEE 802.11.
39239beb93cSSam Leffler  */
wpa_pmk_to_ptk(const u8 * pmk,size_t pmk_len,const char * label,const u8 * addr1,const u8 * addr2,const u8 * nonce1,const u8 * nonce2,struct wpa_ptk * ptk,int akmp,int cipher,const u8 * z,size_t z_len,size_t kdk_len)3935b9c547cSRui Paulo int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
39439beb93cSSam Leffler 		   const u8 *addr1, const u8 *addr2,
39539beb93cSSam Leffler 		   const u8 *nonce1, const u8 *nonce2,
3964bc52338SCy Schubert 		   struct wpa_ptk *ptk, int akmp, int cipher,
397c1d255d3SCy Schubert 		   const u8 *z, size_t z_len, size_t kdk_len)
39839beb93cSSam Leffler {
3994bc52338SCy Schubert #define MAX_Z_LEN 66 /* with NIST P-521 */
4004bc52338SCy Schubert 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
4014bc52338SCy Schubert 	size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
402c1d255d3SCy Schubert 	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
403c1d255d3SCy Schubert 		WPA_KDK_MAX_LEN];
4045b9c547cSRui Paulo 	size_t ptk_len;
405c1d255d3SCy Schubert #ifdef CONFIG_OWE
406c1d255d3SCy Schubert 	int owe_ptk_workaround = 0;
407c1d255d3SCy Schubert 
408c1d255d3SCy Schubert 	if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) {
409c1d255d3SCy Schubert 		owe_ptk_workaround = 1;
410c1d255d3SCy Schubert 		akmp = WPA_KEY_MGMT_OWE;
411c1d255d3SCy Schubert 	}
412c1d255d3SCy Schubert #endif /* CONFIG_OWE */
41339beb93cSSam Leffler 
41485732ac8SCy Schubert 	if (pmk_len == 0) {
41585732ac8SCy Schubert 		wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
41685732ac8SCy Schubert 		return -1;
41785732ac8SCy Schubert 	}
41885732ac8SCy Schubert 
4194bc52338SCy Schubert 	if (z_len > MAX_Z_LEN)
4204bc52338SCy Schubert 		return -1;
4214bc52338SCy Schubert 
42239beb93cSSam Leffler 	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
42339beb93cSSam Leffler 		os_memcpy(data, addr1, ETH_ALEN);
42439beb93cSSam Leffler 		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
42539beb93cSSam Leffler 	} else {
42639beb93cSSam Leffler 		os_memcpy(data, addr2, ETH_ALEN);
42739beb93cSSam Leffler 		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
42839beb93cSSam Leffler 	}
42939beb93cSSam Leffler 
43039beb93cSSam Leffler 	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
43139beb93cSSam Leffler 		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
43239beb93cSSam Leffler 		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
43339beb93cSSam Leffler 			  WPA_NONCE_LEN);
43439beb93cSSam Leffler 	} else {
43539beb93cSSam Leffler 		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
43639beb93cSSam Leffler 		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
43739beb93cSSam Leffler 			  WPA_NONCE_LEN);
43839beb93cSSam Leffler 	}
43939beb93cSSam Leffler 
4404bc52338SCy Schubert 	if (z && z_len) {
4414bc52338SCy Schubert 		os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
4424bc52338SCy Schubert 		data_len += z_len;
4434bc52338SCy Schubert 	}
4444bc52338SCy Schubert 
445c1d255d3SCy Schubert 	if (kdk_len > WPA_KDK_MAX_LEN) {
446c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR,
447c1d255d3SCy Schubert 			   "WPA: KDK len=%zu exceeds max supported len",
448c1d255d3SCy Schubert 			   kdk_len);
449c1d255d3SCy Schubert 		return -1;
450c1d255d3SCy Schubert 	}
451c1d255d3SCy Schubert 
45285732ac8SCy Schubert 	ptk->kck_len = wpa_kck_len(akmp, pmk_len);
45385732ac8SCy Schubert 	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
4545b9c547cSRui Paulo 	ptk->tk_len = wpa_cipher_key_len(cipher);
455c1d255d3SCy Schubert 	ptk->kdk_len = kdk_len;
45685732ac8SCy Schubert 	if (ptk->tk_len == 0) {
45785732ac8SCy Schubert 		wpa_printf(MSG_ERROR,
45885732ac8SCy Schubert 			   "WPA: Unsupported cipher (0x%x) used in PTK derivation",
45985732ac8SCy Schubert 			   cipher);
46085732ac8SCy Schubert 		return -1;
46185732ac8SCy Schubert 	}
462c1d255d3SCy Schubert 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len;
4635b9c547cSRui Paulo 
46485732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp)) {
465*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
46685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
4674bc52338SCy Schubert 		if (sha384_prf(pmk, pmk_len, label, data, data_len,
46885732ac8SCy Schubert 			       tmp, ptk_len) < 0)
46985732ac8SCy Schubert 			return -1;
470*a90b9d01SCy Schubert #else /* CONFIG_SHA384 */
47185732ac8SCy Schubert 		return -1;
472*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
473c1d255d3SCy Schubert 	} else if (wpa_key_mgmt_sha256(akmp)) {
47485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
4754bc52338SCy Schubert 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
47685732ac8SCy Schubert 			       tmp, ptk_len) < 0)
47785732ac8SCy Schubert 			return -1;
478c1d255d3SCy Schubert #ifdef CONFIG_OWE
479c1d255d3SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 ||
480c1d255d3SCy Schubert 						owe_ptk_workaround)) {
481c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
482c1d255d3SCy Schubert 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
483c1d255d3SCy Schubert 			       tmp, ptk_len) < 0)
48485732ac8SCy Schubert 			return -1;
485c1d255d3SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) {
486c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
487c1d255d3SCy Schubert 		if (sha384_prf(pmk, pmk_len, label, data, data_len,
488c1d255d3SCy Schubert 			       tmp, ptk_len) < 0)
489c1d255d3SCy Schubert 			return -1;
490c1d255d3SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) {
491c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
492c1d255d3SCy Schubert 		if (sha512_prf(pmk, pmk_len, label, data, data_len,
493c1d255d3SCy Schubert 			       tmp, ptk_len) < 0)
494c1d255d3SCy Schubert 			return -1;
495c1d255d3SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_OWE) {
496c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u",
497c1d255d3SCy Schubert 			   (unsigned int) pmk_len);
498c1d255d3SCy Schubert 		return -1;
499c1d255d3SCy Schubert #endif /* CONFIG_OWE */
50085732ac8SCy Schubert #ifdef CONFIG_DPP
50185732ac8SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
50285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
5034bc52338SCy Schubert 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
50485732ac8SCy Schubert 			       tmp, ptk_len) < 0)
50585732ac8SCy Schubert 			return -1;
50685732ac8SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
50785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
5084bc52338SCy Schubert 		if (sha384_prf(pmk, pmk_len, label, data, data_len,
50985732ac8SCy Schubert 			       tmp, ptk_len) < 0)
51085732ac8SCy Schubert 			return -1;
51185732ac8SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
51285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
5134bc52338SCy Schubert 		if (sha512_prf(pmk, pmk_len, label, data, data_len,
51485732ac8SCy Schubert 			       tmp, ptk_len) < 0)
51585732ac8SCy Schubert 			return -1;
51685732ac8SCy Schubert 	} else if (akmp == WPA_KEY_MGMT_DPP) {
51785732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u",
51885732ac8SCy Schubert 			   (unsigned int) pmk_len);
51985732ac8SCy Schubert 		return -1;
52085732ac8SCy Schubert #endif /* CONFIG_DPP */
521*a90b9d01SCy Schubert #ifdef CONFIG_SAE
522*a90b9d01SCy Schubert 	} else if (wpa_key_mgmt_sae_ext_key(akmp)) {
523*a90b9d01SCy Schubert 		if (pmk_len == 32) {
524*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
525*a90b9d01SCy Schubert 				   "SAE: PTK derivation using PRF(SHA256)");
526*a90b9d01SCy Schubert 			if (sha256_prf(pmk, pmk_len, label, data, data_len,
527*a90b9d01SCy Schubert 				       tmp, ptk_len) < 0)
528*a90b9d01SCy Schubert 				return -1;
529*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
530*a90b9d01SCy Schubert 		} else if (pmk_len == 48) {
531*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
532*a90b9d01SCy Schubert 				   "SAE: PTK derivation using PRF(SHA384)");
533*a90b9d01SCy Schubert 			if (sha384_prf(pmk, pmk_len, label, data, data_len,
534*a90b9d01SCy Schubert 				       tmp, ptk_len) < 0)
535*a90b9d01SCy Schubert 				return -1;
536*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
537*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
538*a90b9d01SCy Schubert 		} else if (pmk_len == 64) {
539*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
540*a90b9d01SCy Schubert 				   "SAE: PTK derivation using PRF(SHA512)");
541*a90b9d01SCy Schubert 			if (sha512_prf(pmk, pmk_len, label, data, data_len,
542*a90b9d01SCy Schubert 				       tmp, ptk_len) < 0)
543*a90b9d01SCy Schubert 				return -1;
544*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
545*a90b9d01SCy Schubert 		} else {
546*a90b9d01SCy Schubert 			wpa_printf(MSG_INFO, "SAE: Unknown PMK length %u",
547*a90b9d01SCy Schubert 				   (unsigned int) pmk_len);
548*a90b9d01SCy Schubert 			return -1;
549*a90b9d01SCy Schubert 		}
550*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
55185732ac8SCy Schubert 	} else {
55285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
5534bc52338SCy Schubert 		if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
55485732ac8SCy Schubert 			     ptk_len) < 0)
55585732ac8SCy Schubert 			return -1;
55685732ac8SCy Schubert 	}
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
55939beb93cSSam Leffler 		   MAC2STR(addr1), MAC2STR(addr2));
560f05cddf9SRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
561f05cddf9SRui Paulo 	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
5624bc52338SCy Schubert 	if (z && z_len)
5634bc52338SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
56439beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
5655b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
5665b9c547cSRui Paulo 
5675b9c547cSRui Paulo 	os_memcpy(ptk->kck, tmp, ptk->kck_len);
5685b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
5695b9c547cSRui Paulo 
5705b9c547cSRui Paulo 	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
5715b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
5725b9c547cSRui Paulo 
5735b9c547cSRui Paulo 	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
5745b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
5755b9c547cSRui Paulo 
576c1d255d3SCy Schubert 	if (kdk_len) {
577c1d255d3SCy Schubert 		os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len +
578c1d255d3SCy Schubert 			  ptk->tk_len, ptk->kdk_len);
579c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
580c1d255d3SCy Schubert 	}
581c1d255d3SCy Schubert 
58285732ac8SCy Schubert 	ptk->kek2_len = 0;
58385732ac8SCy Schubert 	ptk->kck2_len = 0;
58485732ac8SCy Schubert 
5855b9c547cSRui Paulo 	os_memset(tmp, 0, sizeof(tmp));
5864bc52338SCy Schubert 	os_memset(data, 0, data_len);
5875b9c547cSRui Paulo 	return 0;
58839beb93cSSam Leffler }
58939beb93cSSam Leffler 
59085732ac8SCy Schubert #ifdef CONFIG_FILS
59185732ac8SCy Schubert 
fils_rmsk_to_pmk(int akmp,const u8 * rmsk,size_t rmsk_len,const u8 * snonce,const u8 * anonce,const u8 * dh_ss,size_t dh_ss_len,u8 * pmk,size_t * pmk_len)59285732ac8SCy Schubert int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
59385732ac8SCy Schubert 		     const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
59485732ac8SCy Schubert 		     size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
59585732ac8SCy Schubert {
59685732ac8SCy Schubert 	u8 nonces[2 * FILS_NONCE_LEN];
59785732ac8SCy Schubert 	const u8 *addr[2];
59885732ac8SCy Schubert 	size_t len[2];
59985732ac8SCy Schubert 	size_t num_elem;
60085732ac8SCy Schubert 	int res;
60185732ac8SCy Schubert 
60285732ac8SCy Schubert 	/* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
60385732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
60485732ac8SCy Schubert 
60585732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp))
60685732ac8SCy Schubert 		*pmk_len = SHA384_MAC_LEN;
60785732ac8SCy Schubert 	else if (wpa_key_mgmt_sha256(akmp))
60885732ac8SCy Schubert 		*pmk_len = SHA256_MAC_LEN;
60985732ac8SCy Schubert 	else
61085732ac8SCy Schubert 		return -1;
61185732ac8SCy Schubert 
61285732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
61385732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
61485732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
61585732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
61685732ac8SCy Schubert 
61785732ac8SCy Schubert 	os_memcpy(nonces, snonce, FILS_NONCE_LEN);
61885732ac8SCy Schubert 	os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
61985732ac8SCy Schubert 	addr[0] = rmsk;
62085732ac8SCy Schubert 	len[0] = rmsk_len;
62185732ac8SCy Schubert 	num_elem = 1;
62285732ac8SCy Schubert 	if (dh_ss) {
62385732ac8SCy Schubert 		addr[1] = dh_ss;
62485732ac8SCy Schubert 		len[1] = dh_ss_len;
62585732ac8SCy Schubert 		num_elem++;
62685732ac8SCy Schubert 	}
62785732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp))
62885732ac8SCy Schubert 		res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
62985732ac8SCy Schubert 					 addr, len, pmk);
63085732ac8SCy Schubert 	else
63185732ac8SCy Schubert 		res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
63285732ac8SCy Schubert 					 addr, len, pmk);
63385732ac8SCy Schubert 	if (res == 0)
63485732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
63585732ac8SCy Schubert 	else
63685732ac8SCy Schubert 		*pmk_len = 0;
63785732ac8SCy Schubert 	return res;
63885732ac8SCy Schubert }
63985732ac8SCy Schubert 
64085732ac8SCy Schubert 
fils_pmkid_erp(int akmp,const u8 * reauth,size_t reauth_len,u8 * pmkid)64185732ac8SCy Schubert int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
64285732ac8SCy Schubert 		   u8 *pmkid)
64385732ac8SCy Schubert {
64485732ac8SCy Schubert 	const u8 *addr[1];
64585732ac8SCy Schubert 	size_t len[1];
64685732ac8SCy Schubert 	u8 hash[SHA384_MAC_LEN];
64785732ac8SCy Schubert 	int res;
64885732ac8SCy Schubert 
64985732ac8SCy Schubert 	/* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
65085732ac8SCy Schubert 	addr[0] = reauth;
65185732ac8SCy Schubert 	len[0] = reauth_len;
65285732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp))
65385732ac8SCy Schubert 		res = sha384_vector(1, addr, len, hash);
65485732ac8SCy Schubert 	else if (wpa_key_mgmt_sha256(akmp))
65585732ac8SCy Schubert 		res = sha256_vector(1, addr, len, hash);
65685732ac8SCy Schubert 	else
65785732ac8SCy Schubert 		return -1;
65885732ac8SCy Schubert 	if (res)
65985732ac8SCy Schubert 		return res;
66085732ac8SCy Schubert 	os_memcpy(pmkid, hash, PMKID_LEN);
66185732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
66285732ac8SCy Schubert 	return 0;
66385732ac8SCy Schubert }
66485732ac8SCy Schubert 
66585732ac8SCy Schubert 
fils_pmk_to_ptk(const u8 * pmk,size_t pmk_len,const u8 * spa,const u8 * aa,const u8 * snonce,const u8 * anonce,const u8 * dhss,size_t dhss_len,struct wpa_ptk * ptk,u8 * ick,size_t * ick_len,int akmp,int cipher,u8 * fils_ft,size_t * fils_ft_len,size_t kdk_len)66685732ac8SCy Schubert int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
66785732ac8SCy Schubert 		    const u8 *snonce, const u8 *anonce, const u8 *dhss,
66885732ac8SCy Schubert 		    size_t dhss_len, struct wpa_ptk *ptk,
66985732ac8SCy Schubert 		    u8 *ick, size_t *ick_len, int akmp, int cipher,
670c1d255d3SCy Schubert 		    u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len)
67185732ac8SCy Schubert {
67285732ac8SCy Schubert 	u8 *data, *pos;
67385732ac8SCy Schubert 	size_t data_len;
67485732ac8SCy Schubert 	u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
675c1d255d3SCy Schubert 	       FILS_FT_MAX_LEN + WPA_KDK_MAX_LEN];
67685732ac8SCy Schubert 	size_t key_data_len;
67785732ac8SCy Schubert 	const char *label = "FILS PTK Derivation";
67885732ac8SCy Schubert 	int ret = -1;
679c1d255d3SCy Schubert 	size_t offset;
68085732ac8SCy Schubert 
68185732ac8SCy Schubert 	/*
68285732ac8SCy Schubert 	 * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
68385732ac8SCy Schubert 	 *                       SPA || AA || SNonce || ANonce [ || DHss ])
68485732ac8SCy Schubert 	 * ICK = L(FILS-Key-Data, 0, ICK_bits)
68585732ac8SCy Schubert 	 * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits)
68685732ac8SCy Schubert 	 * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits)
68785732ac8SCy Schubert 	 * If doing FT initial mobility domain association:
68885732ac8SCy Schubert 	 * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
68985732ac8SCy Schubert 	 *             FILS-FT_bits)
690c1d255d3SCy Schubert 	 * When a KDK is derived:
691c1d255d3SCy Schubert 	 * KDK = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits + FILS-FT_bits,
692c1d255d3SCy Schubert 	 *	   KDK_bits)
69385732ac8SCy Schubert 	 */
69485732ac8SCy Schubert 	data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
69585732ac8SCy Schubert 	data = os_malloc(data_len);
69685732ac8SCy Schubert 	if (!data)
69785732ac8SCy Schubert 		goto err;
69885732ac8SCy Schubert 	pos = data;
69985732ac8SCy Schubert 	os_memcpy(pos, spa, ETH_ALEN);
70085732ac8SCy Schubert 	pos += ETH_ALEN;
70185732ac8SCy Schubert 	os_memcpy(pos, aa, ETH_ALEN);
70285732ac8SCy Schubert 	pos += ETH_ALEN;
70385732ac8SCy Schubert 	os_memcpy(pos, snonce, FILS_NONCE_LEN);
70485732ac8SCy Schubert 	pos += FILS_NONCE_LEN;
70585732ac8SCy Schubert 	os_memcpy(pos, anonce, FILS_NONCE_LEN);
70685732ac8SCy Schubert 	pos += FILS_NONCE_LEN;
70785732ac8SCy Schubert 	if (dhss)
70885732ac8SCy Schubert 		os_memcpy(pos, dhss, dhss_len);
70985732ac8SCy Schubert 
71085732ac8SCy Schubert 	ptk->kck_len = 0;
71185732ac8SCy Schubert 	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
71285732ac8SCy Schubert 	ptk->tk_len = wpa_cipher_key_len(cipher);
71385732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp))
71485732ac8SCy Schubert 		*ick_len = 48;
71585732ac8SCy Schubert 	else if (wpa_key_mgmt_sha256(akmp))
71685732ac8SCy Schubert 		*ick_len = 32;
71785732ac8SCy Schubert 	else
71885732ac8SCy Schubert 		goto err;
71985732ac8SCy Schubert 	key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
72085732ac8SCy Schubert 
721c1d255d3SCy Schubert 	if (kdk_len) {
722c1d255d3SCy Schubert 		if (kdk_len > WPA_KDK_MAX_LEN) {
723c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR, "FILS: KDK len=%zu too big",
724c1d255d3SCy Schubert 				   kdk_len);
725c1d255d3SCy Schubert 			goto err;
726c1d255d3SCy Schubert 		}
727c1d255d3SCy Schubert 
728c1d255d3SCy Schubert 		ptk->kdk_len = kdk_len;
729c1d255d3SCy Schubert 		key_data_len += kdk_len;
730c1d255d3SCy Schubert 	} else {
731c1d255d3SCy Schubert 		ptk->kdk_len = 0;
732c1d255d3SCy Schubert 	}
733c1d255d3SCy Schubert 
73485732ac8SCy Schubert 	if (fils_ft && fils_ft_len) {
73585732ac8SCy Schubert 		if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
73685732ac8SCy Schubert 			*fils_ft_len = 32;
73785732ac8SCy Schubert 		} else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) {
73885732ac8SCy Schubert 			*fils_ft_len = 48;
73985732ac8SCy Schubert 		} else {
74085732ac8SCy Schubert 			*fils_ft_len = 0;
74185732ac8SCy Schubert 			fils_ft = NULL;
74285732ac8SCy Schubert 		}
74385732ac8SCy Schubert 		key_data_len += *fils_ft_len;
74485732ac8SCy Schubert 	}
74585732ac8SCy Schubert 
74685732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp)) {
74785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)");
74885732ac8SCy Schubert 		if (sha384_prf(pmk, pmk_len, label, data, data_len,
74985732ac8SCy Schubert 			       tmp, key_data_len) < 0)
75085732ac8SCy Schubert 			goto err;
75185732ac8SCy Schubert 	} else {
75285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)");
75385732ac8SCy Schubert 		if (sha256_prf(pmk, pmk_len, label, data, data_len,
75485732ac8SCy Schubert 			       tmp, key_data_len) < 0)
75585732ac8SCy Schubert 			goto err;
75685732ac8SCy Schubert 	}
75785732ac8SCy Schubert 
75885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR
75985732ac8SCy Schubert 		   " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa));
76085732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
76185732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
76285732ac8SCy Schubert 	if (dhss)
76385732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len);
76485732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len);
76585732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
76685732ac8SCy Schubert 
76785732ac8SCy Schubert 	os_memcpy(ick, tmp, *ick_len);
768c1d255d3SCy Schubert 	offset = *ick_len;
76985732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
77085732ac8SCy Schubert 
771c1d255d3SCy Schubert 	os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
77285732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
773c1d255d3SCy Schubert 	offset += ptk->kek_len;
77485732ac8SCy Schubert 
775c1d255d3SCy Schubert 	os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
77685732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
777c1d255d3SCy Schubert 	offset += ptk->tk_len;
77885732ac8SCy Schubert 
77985732ac8SCy Schubert 	if (fils_ft && fils_ft_len) {
780c1d255d3SCy Schubert 		os_memcpy(fils_ft, tmp + offset, *fils_ft_len);
78185732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
78285732ac8SCy Schubert 				fils_ft, *fils_ft_len);
783c1d255d3SCy Schubert 		offset += *fils_ft_len;
784c1d255d3SCy Schubert 	}
785c1d255d3SCy Schubert 
786c1d255d3SCy Schubert 	if (ptk->kdk_len) {
787c1d255d3SCy Schubert 		os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
788c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FILS: KDK", ptk->kdk, ptk->kdk_len);
78985732ac8SCy Schubert 	}
79085732ac8SCy Schubert 
79185732ac8SCy Schubert 	ptk->kek2_len = 0;
79285732ac8SCy Schubert 	ptk->kck2_len = 0;
79385732ac8SCy Schubert 
79485732ac8SCy Schubert 	os_memset(tmp, 0, sizeof(tmp));
79585732ac8SCy Schubert 	ret = 0;
79685732ac8SCy Schubert err:
79785732ac8SCy Schubert 	bin_clear_free(data, data_len);
79885732ac8SCy Schubert 	return ret;
79985732ac8SCy Schubert }
80085732ac8SCy Schubert 
80185732ac8SCy Schubert 
fils_key_auth_sk(const u8 * ick,size_t ick_len,const u8 * snonce,const u8 * anonce,const u8 * sta_addr,const u8 * bssid,const u8 * g_sta,size_t g_sta_len,const u8 * g_ap,size_t g_ap_len,int akmp,u8 * key_auth_sta,u8 * key_auth_ap,size_t * key_auth_len)80285732ac8SCy Schubert int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
80385732ac8SCy Schubert 		     const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
80485732ac8SCy Schubert 		     const u8 *g_sta, size_t g_sta_len,
80585732ac8SCy Schubert 		     const u8 *g_ap, size_t g_ap_len,
80685732ac8SCy Schubert 		     int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
80785732ac8SCy Schubert 		     size_t *key_auth_len)
80885732ac8SCy Schubert {
80985732ac8SCy Schubert 	const u8 *addr[6];
81085732ac8SCy Schubert 	size_t len[6];
81185732ac8SCy Schubert 	size_t num_elem = 4;
81285732ac8SCy Schubert 	int res;
81385732ac8SCy Schubert 
81485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR
81585732ac8SCy Schubert 		   " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid));
81685732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len);
81785732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
81885732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
81985732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len);
82085732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len);
82185732ac8SCy Schubert 
82285732ac8SCy Schubert 	/*
82385732ac8SCy Schubert 	 * For (Re)Association Request frame (STA->AP):
82485732ac8SCy Schubert 	 * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID
82585732ac8SCy Schubert 	 *                      [ || gSTA || gAP ])
82685732ac8SCy Schubert 	 */
82785732ac8SCy Schubert 	addr[0] = snonce;
82885732ac8SCy Schubert 	len[0] = FILS_NONCE_LEN;
82985732ac8SCy Schubert 	addr[1] = anonce;
83085732ac8SCy Schubert 	len[1] = FILS_NONCE_LEN;
83185732ac8SCy Schubert 	addr[2] = sta_addr;
83285732ac8SCy Schubert 	len[2] = ETH_ALEN;
83385732ac8SCy Schubert 	addr[3] = bssid;
83485732ac8SCy Schubert 	len[3] = ETH_ALEN;
835c1d255d3SCy Schubert 	if (g_sta && g_sta_len && g_ap && g_ap_len) {
83685732ac8SCy Schubert 		addr[4] = g_sta;
83785732ac8SCy Schubert 		len[4] = g_sta_len;
83885732ac8SCy Schubert 		addr[5] = g_ap;
83985732ac8SCy Schubert 		len[5] = g_ap_len;
84085732ac8SCy Schubert 		num_elem = 6;
84185732ac8SCy Schubert 	}
84285732ac8SCy Schubert 
84385732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp)) {
84485732ac8SCy Schubert 		*key_auth_len = 48;
84585732ac8SCy Schubert 		res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
84685732ac8SCy Schubert 					 key_auth_sta);
84785732ac8SCy Schubert 	} else if (wpa_key_mgmt_sha256(akmp)) {
84885732ac8SCy Schubert 		*key_auth_len = 32;
84985732ac8SCy Schubert 		res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
85085732ac8SCy Schubert 					 key_auth_sta);
85185732ac8SCy Schubert 	} else {
85285732ac8SCy Schubert 		return -1;
85385732ac8SCy Schubert 	}
85485732ac8SCy Schubert 	if (res < 0)
85585732ac8SCy Schubert 		return res;
85685732ac8SCy Schubert 
85785732ac8SCy Schubert 	/*
85885732ac8SCy Schubert 	 * For (Re)Association Response frame (AP->STA):
85985732ac8SCy Schubert 	 * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC
86085732ac8SCy Schubert 	 *                      [ || gAP || gSTA ])
86185732ac8SCy Schubert 	 */
86285732ac8SCy Schubert 	addr[0] = anonce;
86385732ac8SCy Schubert 	addr[1] = snonce;
86485732ac8SCy Schubert 	addr[2] = bssid;
86585732ac8SCy Schubert 	addr[3] = sta_addr;
866c1d255d3SCy Schubert 	if (g_sta && g_sta_len && g_ap && g_ap_len) {
86785732ac8SCy Schubert 		addr[4] = g_ap;
86885732ac8SCy Schubert 		len[4] = g_ap_len;
86985732ac8SCy Schubert 		addr[5] = g_sta;
87085732ac8SCy Schubert 		len[5] = g_sta_len;
87185732ac8SCy Schubert 	}
87285732ac8SCy Schubert 
87385732ac8SCy Schubert 	if (wpa_key_mgmt_sha384(akmp))
87485732ac8SCy Schubert 		res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
87585732ac8SCy Schubert 					 key_auth_ap);
87685732ac8SCy Schubert 	else if (wpa_key_mgmt_sha256(akmp))
87785732ac8SCy Schubert 		res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
87885732ac8SCy Schubert 					 key_auth_ap);
87985732ac8SCy Schubert 	if (res < 0)
88085732ac8SCy Schubert 		return res;
88185732ac8SCy Schubert 
88285732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)",
88385732ac8SCy Schubert 		    key_auth_sta, *key_auth_len);
88485732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)",
88585732ac8SCy Schubert 		    key_auth_ap, *key_auth_len);
88685732ac8SCy Schubert 
88785732ac8SCy Schubert 	return 0;
88885732ac8SCy Schubert }
88985732ac8SCy Schubert 
89085732ac8SCy Schubert #endif /* CONFIG_FILS */
89185732ac8SCy Schubert 
89239beb93cSSam Leffler 
89339beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
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,const u8 * rsnie,size_t rsnie_len,const u8 * ric,size_t ric_len,const u8 * rsnxe,size_t rsnxe_len,const struct wpabuf * extra,u8 * mic)894*a90b9d01SCy Schubert int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr,
8955b9c547cSRui Paulo 	       const u8 *ap_addr, u8 transaction_seqnum,
8965b9c547cSRui Paulo 	       const u8 *mdie, size_t mdie_len,
89739beb93cSSam Leffler 	       const u8 *ftie, size_t ftie_len,
89839beb93cSSam Leffler 	       const u8 *rsnie, size_t rsnie_len,
899c1d255d3SCy Schubert 	       const u8 *ric, size_t ric_len,
900c1d255d3SCy Schubert 	       const u8 *rsnxe, size_t rsnxe_len,
901*a90b9d01SCy Schubert 	       const struct wpabuf *extra,
902c1d255d3SCy Schubert 	       u8 *mic)
90339beb93cSSam Leffler {
904*a90b9d01SCy Schubert 	const u8 *addr[11];
905*a90b9d01SCy Schubert 	size_t len[11];
906325151a3SRui Paulo 	size_t i, num_elem = 0;
907*a90b9d01SCy Schubert 	u8 zero_mic[32];
90885732ac8SCy Schubert 	size_t mic_len, fte_fixed_len;
909*a90b9d01SCy Schubert 	int res;
91039beb93cSSam Leffler 
91185732ac8SCy Schubert 	if (kck_len == 16) {
91285732ac8SCy Schubert 		mic_len = 16;
91385732ac8SCy Schubert #ifdef CONFIG_SHA384
91485732ac8SCy Schubert 	} else if (kck_len == 24) {
91585732ac8SCy Schubert 		mic_len = 24;
91685732ac8SCy Schubert #endif /* CONFIG_SHA384 */
917*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
918*a90b9d01SCy Schubert 	} else if (kck_len == 32) {
919*a90b9d01SCy Schubert 		mic_len = 32;
920*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
92185732ac8SCy Schubert 	} else {
9225b9c547cSRui Paulo 		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
9235b9c547cSRui Paulo 			   (unsigned int) kck_len);
9245b9c547cSRui Paulo 		return -1;
9255b9c547cSRui Paulo 	}
9265b9c547cSRui Paulo 
92785732ac8SCy Schubert 	fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
92885732ac8SCy Schubert 
929325151a3SRui Paulo 	addr[num_elem] = sta_addr;
930325151a3SRui Paulo 	len[num_elem] = ETH_ALEN;
931325151a3SRui Paulo 	num_elem++;
93239beb93cSSam Leffler 
933325151a3SRui Paulo 	addr[num_elem] = ap_addr;
934325151a3SRui Paulo 	len[num_elem] = ETH_ALEN;
935325151a3SRui Paulo 	num_elem++;
936325151a3SRui Paulo 
937325151a3SRui Paulo 	addr[num_elem] = &transaction_seqnum;
938325151a3SRui Paulo 	len[num_elem] = 1;
939325151a3SRui Paulo 	num_elem++;
940325151a3SRui Paulo 
94139beb93cSSam Leffler 	if (rsnie) {
942325151a3SRui Paulo 		addr[num_elem] = rsnie;
943325151a3SRui Paulo 		len[num_elem] = rsnie_len;
944325151a3SRui Paulo 		num_elem++;
94539beb93cSSam Leffler 	}
94639beb93cSSam Leffler 	if (mdie) {
947325151a3SRui Paulo 		addr[num_elem] = mdie;
948325151a3SRui Paulo 		len[num_elem] = mdie_len;
949325151a3SRui Paulo 		num_elem++;
95039beb93cSSam Leffler 	}
95139beb93cSSam Leffler 	if (ftie) {
95285732ac8SCy Schubert 		if (ftie_len < 2 + fte_fixed_len)
95339beb93cSSam Leffler 			return -1;
954325151a3SRui Paulo 
955325151a3SRui Paulo 		/* IE hdr and mic_control */
956325151a3SRui Paulo 		addr[num_elem] = ftie;
957325151a3SRui Paulo 		len[num_elem] = 2 + 2;
958325151a3SRui Paulo 		num_elem++;
959325151a3SRui Paulo 
960325151a3SRui Paulo 		/* MIC field with all zeros */
96185732ac8SCy Schubert 		os_memset(zero_mic, 0, mic_len);
962325151a3SRui Paulo 		addr[num_elem] = zero_mic;
96385732ac8SCy Schubert 		len[num_elem] = mic_len;
964325151a3SRui Paulo 		num_elem++;
965325151a3SRui Paulo 
966325151a3SRui Paulo 		/* Rest of FTIE */
96785732ac8SCy Schubert 		addr[num_elem] = ftie + 2 + 2 + mic_len;
96885732ac8SCy Schubert 		len[num_elem] = ftie_len - (2 + 2 + mic_len);
969325151a3SRui Paulo 		num_elem++;
97039beb93cSSam Leffler 	}
97139beb93cSSam Leffler 	if (ric) {
972325151a3SRui Paulo 		addr[num_elem] = ric;
973325151a3SRui Paulo 		len[num_elem] = ric_len;
974325151a3SRui Paulo 		num_elem++;
97539beb93cSSam Leffler 	}
97639beb93cSSam Leffler 
977c1d255d3SCy Schubert 	if (rsnxe) {
978c1d255d3SCy Schubert 		addr[num_elem] = rsnxe;
979c1d255d3SCy Schubert 		len[num_elem] = rsnxe_len;
980c1d255d3SCy Schubert 		num_elem++;
981c1d255d3SCy Schubert 	}
982c1d255d3SCy Schubert 
983*a90b9d01SCy Schubert 	if (extra) {
984*a90b9d01SCy Schubert 		addr[num_elem] = wpabuf_head(extra);
985*a90b9d01SCy Schubert 		len[num_elem] = wpabuf_len(extra);
986*a90b9d01SCy Schubert 		num_elem++;
987*a90b9d01SCy Schubert 	}
988*a90b9d01SCy Schubert 
989325151a3SRui Paulo 	for (i = 0; i < num_elem; i++)
990325151a3SRui Paulo 		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
991*a90b9d01SCy Schubert 	res = -1;
992*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
993*a90b9d01SCy Schubert 	if (kck_len == 32) {
994*a90b9d01SCy Schubert 		u8 hash[SHA512_MAC_LEN];
995*a90b9d01SCy Schubert 
996*a90b9d01SCy Schubert 		if (hmac_sha512_vector(kck, kck_len, num_elem, addr, len, hash))
997*a90b9d01SCy Schubert 			return -1;
998*a90b9d01SCy Schubert 		os_memcpy(mic, hash, 32);
999*a90b9d01SCy Schubert 		res = 0;
1000*a90b9d01SCy Schubert 	}
1001*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
100285732ac8SCy Schubert #ifdef CONFIG_SHA384
100385732ac8SCy Schubert 	if (kck_len == 24) {
100485732ac8SCy Schubert 		u8 hash[SHA384_MAC_LEN];
100585732ac8SCy Schubert 
100685732ac8SCy Schubert 		if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
100785732ac8SCy Schubert 			return -1;
100885732ac8SCy Schubert 		os_memcpy(mic, hash, 24);
1009*a90b9d01SCy Schubert 		res = 0;
101085732ac8SCy Schubert 	}
101185732ac8SCy Schubert #endif /* CONFIG_SHA384 */
1012*a90b9d01SCy Schubert 	if (kck_len == 16 && key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
1013*a90b9d01SCy Schubert 		u8 hash[SHA256_MAC_LEN];
101439beb93cSSam Leffler 
1015*a90b9d01SCy Schubert 		if (hmac_sha256_vector(kck, kck_len, num_elem, addr, len, hash))
1016*a90b9d01SCy Schubert 			return -1;
1017*a90b9d01SCy Schubert 		os_memcpy(mic, hash, 16);
1018*a90b9d01SCy Schubert 		res = 0;
1019*a90b9d01SCy Schubert 	}
1020*a90b9d01SCy Schubert 	if (kck_len == 16 && key_mgmt != WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
1021*a90b9d01SCy Schubert 	    omac1_aes_128_vector(kck, num_elem, addr, len, mic) == 0)
1022*a90b9d01SCy Schubert 		res = 0;
1023*a90b9d01SCy Schubert 
1024*a90b9d01SCy Schubert 	return res;
102539beb93cSSam Leffler }
1026f05cddf9SRui Paulo 
1027f05cddf9SRui Paulo 
wpa_ft_parse_ftie(const u8 * ie,size_t ie_len,struct wpa_ft_ies * parse,const u8 * opt)1028f05cddf9SRui Paulo static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
1029*a90b9d01SCy Schubert 			     struct wpa_ft_ies *parse, const u8 *opt)
1030f05cddf9SRui Paulo {
1031f05cddf9SRui Paulo 	const u8 *end, *pos;
1032*a90b9d01SCy Schubert 	u8 link_id;
1033f05cddf9SRui Paulo 
1034*a90b9d01SCy Schubert 	pos = opt;
1035f05cddf9SRui Paulo 	end = ie + ie_len;
103685732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
1037f05cddf9SRui Paulo 
1038780fb4a2SCy Schubert 	while (end - pos >= 2) {
1039780fb4a2SCy Schubert 		u8 id, len;
1040780fb4a2SCy Schubert 
1041780fb4a2SCy Schubert 		id = *pos++;
1042780fb4a2SCy Schubert 		len = *pos++;
104385732ac8SCy Schubert 		if (len > end - pos) {
104485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
1045*a90b9d01SCy Schubert 			return -1;
104685732ac8SCy Schubert 		}
1047780fb4a2SCy Schubert 
1048780fb4a2SCy Schubert 		switch (id) {
1049f05cddf9SRui Paulo 		case FTIE_SUBELEM_R1KH_ID:
1050780fb4a2SCy Schubert 			if (len != FT_R1KH_ID_LEN) {
1051780fb4a2SCy Schubert 				wpa_printf(MSG_DEBUG,
1052780fb4a2SCy Schubert 					   "FT: Invalid R1KH-ID length in FTIE: %d",
1053780fb4a2SCy Schubert 					   len);
1054f05cddf9SRui Paulo 				return -1;
1055f05cddf9SRui Paulo 			}
1056780fb4a2SCy Schubert 			parse->r1kh_id = pos;
1057*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
1058*a90b9d01SCy Schubert 				    parse->r1kh_id, FT_R1KH_ID_LEN);
1059f05cddf9SRui Paulo 			break;
1060f05cddf9SRui Paulo 		case FTIE_SUBELEM_GTK:
1061*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: GTK");
1062780fb4a2SCy Schubert 			parse->gtk = pos;
1063780fb4a2SCy Schubert 			parse->gtk_len = len;
1064f05cddf9SRui Paulo 			break;
1065f05cddf9SRui Paulo 		case FTIE_SUBELEM_R0KH_ID:
1066780fb4a2SCy Schubert 			if (len < 1 || len > FT_R0KH_ID_MAX_LEN) {
1067780fb4a2SCy Schubert 				wpa_printf(MSG_DEBUG,
1068780fb4a2SCy Schubert 					   "FT: Invalid R0KH-ID length in FTIE: %d",
1069780fb4a2SCy Schubert 					   len);
1070f05cddf9SRui Paulo 				return -1;
1071f05cddf9SRui Paulo 			}
1072780fb4a2SCy Schubert 			parse->r0kh_id = pos;
1073780fb4a2SCy Schubert 			parse->r0kh_id_len = len;
1074*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
1075*a90b9d01SCy Schubert 				    parse->r0kh_id, parse->r0kh_id_len);
1076f05cddf9SRui Paulo 			break;
1077f05cddf9SRui Paulo 		case FTIE_SUBELEM_IGTK:
1078*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: IGTK");
1079780fb4a2SCy Schubert 			parse->igtk = pos;
1080780fb4a2SCy Schubert 			parse->igtk_len = len;
1081f05cddf9SRui Paulo 			break;
10824bc52338SCy Schubert #ifdef CONFIG_OCV
10834bc52338SCy Schubert 		case FTIE_SUBELEM_OCI:
10844bc52338SCy Schubert 			parse->oci = pos;
10854bc52338SCy Schubert 			parse->oci_len = len;
1086*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: OCI",
1087*a90b9d01SCy Schubert 				    parse->oci, parse->oci_len);
10884bc52338SCy Schubert 			break;
10894bc52338SCy Schubert #endif /* CONFIG_OCV */
1090c1d255d3SCy Schubert 		case FTIE_SUBELEM_BIGTK:
1091*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: BIGTK");
1092c1d255d3SCy Schubert 			parse->bigtk = pos;
1093c1d255d3SCy Schubert 			parse->bigtk_len = len;
1094c1d255d3SCy Schubert 			break;
1095*a90b9d01SCy Schubert 		case FTIE_SUBELEM_MLO_GTK:
1096*a90b9d01SCy Schubert 			if (len < 2 + 1 + 1 + 8) {
1097*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1098*a90b9d01SCy Schubert 					   "FT: Too short MLO GTK in FTE");
1099*a90b9d01SCy Schubert 				return -1;
1100*a90b9d01SCy Schubert 			}
1101*a90b9d01SCy Schubert 			link_id = pos[2] & 0x0f;
1102*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: MLO GTK (Link ID %u)",
1103*a90b9d01SCy Schubert 				   link_id);
1104*a90b9d01SCy Schubert 			if (link_id >= MAX_NUM_MLD_LINKS)
1105*a90b9d01SCy Schubert 				break;
1106*a90b9d01SCy Schubert 			parse->valid_mlo_gtks |= BIT(link_id);
1107*a90b9d01SCy Schubert 			parse->mlo_gtk[link_id] = pos;
1108*a90b9d01SCy Schubert 			parse->mlo_gtk_len[link_id] = len;
1109*a90b9d01SCy Schubert 			break;
1110*a90b9d01SCy Schubert 		case FTIE_SUBELEM_MLO_IGTK:
1111*a90b9d01SCy Schubert 			if (len < 2 + 6 + 1 + 1) {
1112*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1113*a90b9d01SCy Schubert 					   "FT: Too short MLO IGTK in FTE");
1114*a90b9d01SCy Schubert 				return -1;
1115*a90b9d01SCy Schubert 			}
1116*a90b9d01SCy Schubert 			link_id = pos[2 + 6] & 0x0f;
1117*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: MLO IGTK (Link ID %u)",
1118*a90b9d01SCy Schubert 				   link_id);
1119*a90b9d01SCy Schubert 			if (link_id >= MAX_NUM_MLD_LINKS)
1120*a90b9d01SCy Schubert 				break;
1121*a90b9d01SCy Schubert 			parse->valid_mlo_igtks |= BIT(link_id);
1122*a90b9d01SCy Schubert 			parse->mlo_igtk[link_id] = pos;
1123*a90b9d01SCy Schubert 			parse->mlo_igtk_len[link_id] = len;
1124*a90b9d01SCy Schubert 			break;
1125*a90b9d01SCy Schubert 		case FTIE_SUBELEM_MLO_BIGTK:
1126*a90b9d01SCy Schubert 			if (len < 2 + 6 + 1 + 1) {
1127*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1128*a90b9d01SCy Schubert 					   "FT: Too short MLO BIGTK in FTE");
1129*a90b9d01SCy Schubert 				return -1;
1130*a90b9d01SCy Schubert 			}
1131*a90b9d01SCy Schubert 			link_id = pos[2 + 6] & 0x0f;
1132*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: MLO BIGTK (Link ID %u)",
1133*a90b9d01SCy Schubert 				   link_id);
1134*a90b9d01SCy Schubert 			if (link_id >= MAX_NUM_MLD_LINKS)
1135*a90b9d01SCy Schubert 				break;
1136*a90b9d01SCy Schubert 			parse->valid_mlo_bigtks |= BIT(link_id);
1137*a90b9d01SCy Schubert 			parse->mlo_bigtk[link_id] = pos;
1138*a90b9d01SCy Schubert 			parse->mlo_bigtk_len[link_id] = len;
1139*a90b9d01SCy Schubert 			break;
114085732ac8SCy Schubert 		default:
114185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
114285732ac8SCy Schubert 			break;
1143f05cddf9SRui Paulo 		}
1144f05cddf9SRui Paulo 
1145780fb4a2SCy Schubert 		pos += len;
1146f05cddf9SRui Paulo 	}
1147f05cddf9SRui Paulo 
1148f05cddf9SRui Paulo 	return 0;
1149f05cddf9SRui Paulo }
1150f05cddf9SRui Paulo 
1151f05cddf9SRui Paulo 
wpa_ft_parse_fte(int key_mgmt,const u8 * ie,size_t len,struct wpa_ft_ies * parse)1152*a90b9d01SCy Schubert static int wpa_ft_parse_fte(int key_mgmt, const u8 *ie, size_t len,
1153*a90b9d01SCy Schubert 			    struct wpa_ft_ies *parse)
1154*a90b9d01SCy Schubert {
1155*a90b9d01SCy Schubert 	size_t mic_len;
1156*a90b9d01SCy Schubert 	u8 mic_len_info;
1157*a90b9d01SCy Schubert 	const u8 *pos = ie;
1158*a90b9d01SCy Schubert 	const u8 *end = pos + len;
1159*a90b9d01SCy Schubert 
1160*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", pos, 2);
1161*a90b9d01SCy Schubert 	parse->fte_rsnxe_used = pos[0] & FTE_MIC_CTRL_RSNXE_USED;
1162*a90b9d01SCy Schubert 	mic_len_info = (pos[0] & FTE_MIC_CTRL_MIC_LEN_MASK) >>
1163*a90b9d01SCy Schubert 		FTE_MIC_CTRL_MIC_LEN_SHIFT;
1164*a90b9d01SCy Schubert 	parse->fte_elem_count = pos[1];
1165*a90b9d01SCy Schubert 	pos += 2;
1166*a90b9d01SCy Schubert 
1167*a90b9d01SCy Schubert 	if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
1168*a90b9d01SCy Schubert 		switch (mic_len_info) {
1169*a90b9d01SCy Schubert 		case FTE_MIC_LEN_16:
1170*a90b9d01SCy Schubert 			mic_len = 16;
1171*a90b9d01SCy Schubert 			break;
1172*a90b9d01SCy Schubert 		case FTE_MIC_LEN_24:
1173*a90b9d01SCy Schubert 			mic_len = 24;
1174*a90b9d01SCy Schubert 			break;
1175*a90b9d01SCy Schubert 		case FTE_MIC_LEN_32:
1176*a90b9d01SCy Schubert 			mic_len = 32;
1177*a90b9d01SCy Schubert 			break;
1178*a90b9d01SCy Schubert 		default:
1179*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
1180*a90b9d01SCy Schubert 				   "FT: Unknown MIC Length subfield value %u",
1181*a90b9d01SCy Schubert 				   mic_len_info);
1182*a90b9d01SCy Schubert 			return -1;
1183*a90b9d01SCy Schubert 		}
1184*a90b9d01SCy Schubert 	} else {
1185*a90b9d01SCy Schubert 		mic_len = wpa_key_mgmt_sha384(key_mgmt) ? 24 : 16;
1186*a90b9d01SCy Schubert 	}
1187*a90b9d01SCy Schubert 	if (mic_len > (size_t) (end - pos)) {
1188*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "FT: No room for %zu octet MIC in FTE",
1189*a90b9d01SCy Schubert 			   mic_len);
1190*a90b9d01SCy Schubert 		return -1;
1191*a90b9d01SCy Schubert 	}
1192*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len);
1193*a90b9d01SCy Schubert 	parse->fte_mic = pos;
1194*a90b9d01SCy Schubert 	parse->fte_mic_len = mic_len;
1195*a90b9d01SCy Schubert 	pos += mic_len;
1196*a90b9d01SCy Schubert 
1197*a90b9d01SCy Schubert 	if (2 * WPA_NONCE_LEN > end - pos)
1198*a90b9d01SCy Schubert 		return -1;
1199*a90b9d01SCy Schubert 	parse->fte_anonce = pos;
1200*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
1201*a90b9d01SCy Schubert 		    parse->fte_anonce, WPA_NONCE_LEN);
1202*a90b9d01SCy Schubert 	pos += WPA_NONCE_LEN;
1203*a90b9d01SCy Schubert 	parse->fte_snonce = pos;
1204*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
1205*a90b9d01SCy Schubert 		    parse->fte_snonce, WPA_NONCE_LEN);
1206*a90b9d01SCy Schubert 	pos += WPA_NONCE_LEN;
1207*a90b9d01SCy Schubert 
1208*a90b9d01SCy Schubert 	return wpa_ft_parse_ftie(ie, len, parse, pos);
1209*a90b9d01SCy Schubert }
1210*a90b9d01SCy Schubert 
1211*a90b9d01SCy Schubert 
wpa_ft_parse_ies(const u8 * ies,size_t ies_len,struct wpa_ft_ies * parse,int key_mgmt,bool reassoc_resp)1212*a90b9d01SCy Schubert int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
1213*a90b9d01SCy Schubert 		     int key_mgmt, bool reassoc_resp)
1214f05cddf9SRui Paulo {
1215f05cddf9SRui Paulo 	const u8 *end, *pos;
1216f05cddf9SRui Paulo 	struct wpa_ie_data data;
1217f05cddf9SRui Paulo 	int ret;
1218f05cddf9SRui Paulo 	int prot_ie_count = 0;
1219*a90b9d01SCy Schubert 	const u8 *fte = NULL;
1220*a90b9d01SCy Schubert 	size_t fte_len = 0;
1221*a90b9d01SCy Schubert 	bool is_fte = false;
1222*a90b9d01SCy Schubert 	struct ieee802_11_elems elems;
1223f05cddf9SRui Paulo 
1224f05cddf9SRui Paulo 	os_memset(parse, 0, sizeof(*parse));
1225f05cddf9SRui Paulo 	if (ies == NULL)
1226f05cddf9SRui Paulo 		return 0;
1227f05cddf9SRui Paulo 
1228*a90b9d01SCy Schubert 	if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed) {
1229*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "FT: Failed to parse elements");
1230*a90b9d01SCy Schubert 		goto fail;
1231*a90b9d01SCy Schubert 	}
1232*a90b9d01SCy Schubert 
1233f05cddf9SRui Paulo 	pos = ies;
1234f05cddf9SRui Paulo 	end = ies + ies_len;
1235780fb4a2SCy Schubert 	while (end - pos >= 2) {
1236780fb4a2SCy Schubert 		u8 id, len;
1237780fb4a2SCy Schubert 
1238780fb4a2SCy Schubert 		id = *pos++;
1239780fb4a2SCy Schubert 		len = *pos++;
1240780fb4a2SCy Schubert 		if (len > end - pos)
1241780fb4a2SCy Schubert 			break;
1242780fb4a2SCy Schubert 
1243*a90b9d01SCy Schubert 		if (id != WLAN_EID_FAST_BSS_TRANSITION &&
1244*a90b9d01SCy Schubert 		    id != WLAN_EID_FRAGMENT)
1245*a90b9d01SCy Schubert 			is_fte = false;
1246*a90b9d01SCy Schubert 
1247780fb4a2SCy Schubert 		switch (id) {
1248f05cddf9SRui Paulo 		case WLAN_EID_RSN:
124985732ac8SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
1250780fb4a2SCy Schubert 			parse->rsn = pos;
1251780fb4a2SCy Schubert 			parse->rsn_len = len;
1252f05cddf9SRui Paulo 			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
1253f05cddf9SRui Paulo 						   parse->rsn_len + 2,
1254f05cddf9SRui Paulo 						   &data);
1255f05cddf9SRui Paulo 			if (ret < 0) {
1256f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
1257f05cddf9SRui Paulo 					   "RSN IE: %d", ret);
1258*a90b9d01SCy Schubert 				goto fail;
1259f05cddf9SRui Paulo 			}
1260c1d255d3SCy Schubert 			parse->rsn_capab = data.capabilities;
1261f05cddf9SRui Paulo 			if (data.num_pmkid == 1 && data.pmkid)
1262f05cddf9SRui Paulo 				parse->rsn_pmkid = data.pmkid;
126385732ac8SCy Schubert 			parse->key_mgmt = data.key_mgmt;
126485732ac8SCy Schubert 			parse->pairwise_cipher = data.pairwise_cipher;
1265*a90b9d01SCy Schubert 			if (!key_mgmt)
1266*a90b9d01SCy Schubert 				key_mgmt = parse->key_mgmt;
1267f05cddf9SRui Paulo 			break;
1268c1d255d3SCy Schubert 		case WLAN_EID_RSNX:
1269c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
1270c1d255d3SCy Schubert 			if (len < 1)
1271c1d255d3SCy Schubert 				break;
1272c1d255d3SCy Schubert 			parse->rsnxe = pos;
1273c1d255d3SCy Schubert 			parse->rsnxe_len = len;
1274c1d255d3SCy Schubert 			break;
1275f05cddf9SRui Paulo 		case WLAN_EID_MOBILITY_DOMAIN:
127685732ac8SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
1277780fb4a2SCy Schubert 			if (len < sizeof(struct rsn_mdie))
1278*a90b9d01SCy Schubert 				goto fail;
1279780fb4a2SCy Schubert 			parse->mdie = pos;
1280780fb4a2SCy Schubert 			parse->mdie_len = len;
1281f05cddf9SRui Paulo 			break;
1282f05cddf9SRui Paulo 		case WLAN_EID_FAST_BSS_TRANSITION:
128385732ac8SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
1284*a90b9d01SCy Schubert 			/* The first two octets (MIC Control field) is in the
1285*a90b9d01SCy Schubert 			 * same offset for all cases, but the second field (MIC)
1286*a90b9d01SCy Schubert 			 * has variable length with three different values.
1287*a90b9d01SCy Schubert 			 * In particular the FT-SAE-EXT-KEY is inconvinient to
1288*a90b9d01SCy Schubert 			 * parse, so try to handle this in pieces instead of
1289*a90b9d01SCy Schubert 			 * using the struct rsn_ftie* definitions. */
129085732ac8SCy Schubert 
1291*a90b9d01SCy Schubert 			if (len < 2)
1292*a90b9d01SCy Schubert 				goto fail;
1293*a90b9d01SCy Schubert 			prot_ie_count = pos[1]; /* Element Count field in
1294*a90b9d01SCy Schubert 						 * MIC Control */
1295*a90b9d01SCy Schubert 			is_fte = true;
1296*a90b9d01SCy Schubert 			fte = pos;
1297*a90b9d01SCy Schubert 			fte_len = len;
129885732ac8SCy Schubert 			break;
1299*a90b9d01SCy Schubert 		case WLAN_EID_FRAGMENT:
1300*a90b9d01SCy Schubert 			if (is_fte) {
1301*a90b9d01SCy Schubert 				wpa_hexdump(MSG_DEBUG, "FT: FTE fragment",
1302*a90b9d01SCy Schubert 					    pos, len);
1303*a90b9d01SCy Schubert 				fte_len += 2 + len;
130485732ac8SCy Schubert 			}
1305f05cddf9SRui Paulo 			break;
1306f05cddf9SRui Paulo 		case WLAN_EID_TIMEOUT_INTERVAL:
130785732ac8SCy Schubert 			wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
130885732ac8SCy Schubert 				    pos, len);
1309780fb4a2SCy Schubert 			if (len != 5)
1310325151a3SRui Paulo 				break;
1311780fb4a2SCy Schubert 			parse->tie = pos;
1312780fb4a2SCy Schubert 			parse->tie_len = len;
1313f05cddf9SRui Paulo 			break;
1314f05cddf9SRui Paulo 		case WLAN_EID_RIC_DATA:
1315f05cddf9SRui Paulo 			if (parse->ric == NULL)
1316780fb4a2SCy Schubert 				parse->ric = pos - 2;
1317f05cddf9SRui Paulo 			break;
1318f05cddf9SRui Paulo 		}
1319f05cddf9SRui Paulo 
1320780fb4a2SCy Schubert 		pos += len;
1321f05cddf9SRui Paulo 	}
1322f05cddf9SRui Paulo 
1323*a90b9d01SCy Schubert 	if (fte) {
1324*a90b9d01SCy Schubert 		int res;
1325*a90b9d01SCy Schubert 
1326*a90b9d01SCy Schubert 		if (fte_len < 255) {
1327*a90b9d01SCy Schubert 			res = wpa_ft_parse_fte(key_mgmt, fte, fte_len, parse);
1328*a90b9d01SCy Schubert 		} else {
1329*a90b9d01SCy Schubert 			parse->fte_buf = ieee802_11_defrag(fte, fte_len, false);
1330*a90b9d01SCy Schubert 			if (!parse->fte_buf)
1331*a90b9d01SCy Schubert 				goto fail;
1332*a90b9d01SCy Schubert 			res = wpa_ft_parse_fte(key_mgmt,
1333*a90b9d01SCy Schubert 					       wpabuf_head(parse->fte_buf),
1334*a90b9d01SCy Schubert 					       wpabuf_len(parse->fte_buf),
1335*a90b9d01SCy Schubert 					       parse);
1336*a90b9d01SCy Schubert 		}
1337*a90b9d01SCy Schubert 		if (res < 0)
1338*a90b9d01SCy Schubert 			goto fail;
1339*a90b9d01SCy Schubert 
1340*a90b9d01SCy Schubert 		/* FTE might be fragmented. If it is, the separate Fragment
1341*a90b9d01SCy Schubert 		 * elements are included in MIC calculation as full elements. */
1342*a90b9d01SCy Schubert 		parse->ftie = fte;
1343*a90b9d01SCy Schubert 		parse->ftie_len = fte_len;
1344*a90b9d01SCy Schubert 	}
1345*a90b9d01SCy Schubert 
1346f05cddf9SRui Paulo 	if (prot_ie_count == 0)
1347f05cddf9SRui Paulo 		return 0; /* no MIC */
1348f05cddf9SRui Paulo 
1349f05cddf9SRui Paulo 	/*
1350f05cddf9SRui Paulo 	 * Check that the protected IE count matches with IEs included in the
1351f05cddf9SRui Paulo 	 * frame.
1352f05cddf9SRui Paulo 	 */
1353*a90b9d01SCy Schubert 	if (reassoc_resp && elems.basic_mle) {
1354*a90b9d01SCy Schubert 		unsigned int link_id;
1355*a90b9d01SCy Schubert 
1356*a90b9d01SCy Schubert 		/* TODO: This count should be done based on all _requested_,
1357*a90b9d01SCy Schubert 		 * not _accepted_ links. */
1358*a90b9d01SCy Schubert 		for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
1359*a90b9d01SCy Schubert 			if (parse->mlo_gtk[link_id]) {
1360f05cddf9SRui Paulo 				if (parse->rsn)
1361f05cddf9SRui Paulo 					prot_ie_count--;
1362*a90b9d01SCy Schubert 				if (parse->rsnxe)
1363*a90b9d01SCy Schubert 					prot_ie_count--;
1364*a90b9d01SCy Schubert 			}
1365*a90b9d01SCy Schubert 		}
1366*a90b9d01SCy Schubert 	} else {
1367*a90b9d01SCy Schubert 		if (parse->rsn)
1368*a90b9d01SCy Schubert 			prot_ie_count--;
1369*a90b9d01SCy Schubert 		if (parse->rsnxe)
1370*a90b9d01SCy Schubert 			prot_ie_count--;
1371*a90b9d01SCy Schubert 	}
1372f05cddf9SRui Paulo 	if (parse->mdie)
1373f05cddf9SRui Paulo 		prot_ie_count--;
1374f05cddf9SRui Paulo 	if (parse->ftie)
1375f05cddf9SRui Paulo 		prot_ie_count--;
1376f05cddf9SRui Paulo 	if (prot_ie_count < 0) {
1377f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
1378f05cddf9SRui Paulo 			   "the protected IE count");
1379*a90b9d01SCy Schubert 		goto fail;
1380f05cddf9SRui Paulo 	}
1381f05cddf9SRui Paulo 
1382f05cddf9SRui Paulo 	if (prot_ie_count == 0 && parse->ric) {
1383f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
1384f05cddf9SRui Paulo 			   "included in protected IE count");
1385*a90b9d01SCy Schubert 		goto fail;
1386f05cddf9SRui Paulo 	}
1387f05cddf9SRui Paulo 
1388f05cddf9SRui Paulo 	/* Determine the end of the RIC IE(s) */
1389780fb4a2SCy Schubert 	if (parse->ric) {
1390f05cddf9SRui Paulo 		pos = parse->ric;
1391780fb4a2SCy Schubert 		while (end - pos >= 2 && 2 + pos[1] <= end - pos &&
1392f05cddf9SRui Paulo 		       prot_ie_count) {
1393f05cddf9SRui Paulo 			prot_ie_count--;
1394f05cddf9SRui Paulo 			pos += 2 + pos[1];
1395f05cddf9SRui Paulo 		}
1396f05cddf9SRui Paulo 		parse->ric_len = pos - parse->ric;
1397780fb4a2SCy Schubert 	}
1398f05cddf9SRui Paulo 	if (prot_ie_count) {
1399f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
1400f05cddf9SRui Paulo 			   "frame", (int) prot_ie_count);
1401*a90b9d01SCy Schubert 		goto fail;
1402f05cddf9SRui Paulo 	}
1403f05cddf9SRui Paulo 
1404f05cddf9SRui Paulo 	return 0;
1405*a90b9d01SCy Schubert 
1406*a90b9d01SCy Schubert fail:
1407*a90b9d01SCy Schubert 	wpa_ft_parse_ies_free(parse);
1408*a90b9d01SCy Schubert 	return -1;
1409f05cddf9SRui Paulo }
1410*a90b9d01SCy Schubert 
1411*a90b9d01SCy Schubert 
wpa_ft_parse_ies_free(struct wpa_ft_ies * parse)1412*a90b9d01SCy Schubert void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse)
1413*a90b9d01SCy Schubert {
1414*a90b9d01SCy Schubert 	if (!parse)
1415*a90b9d01SCy Schubert 		return;
1416*a90b9d01SCy Schubert 	wpabuf_free(parse->fte_buf);
1417*a90b9d01SCy Schubert 	parse->fte_buf = NULL;
1418*a90b9d01SCy Schubert }
1419*a90b9d01SCy Schubert 
142039beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
142139beb93cSSam Leffler 
142239beb93cSSam Leffler 
1423c1d255d3SCy Schubert #ifdef CONFIG_PASN
1424c1d255d3SCy Schubert 
1425c1d255d3SCy Schubert /*
1426c1d255d3SCy Schubert  * pasn_use_sha384 - Should SHA384 be used or SHA256
1427c1d255d3SCy Schubert  *
1428c1d255d3SCy Schubert  * @akmp: Authentication and key management protocol
1429c1d255d3SCy Schubert  * @cipher: The cipher suite
1430c1d255d3SCy Schubert  *
1431c1d255d3SCy Schubert  * According to IEEE P802.11az/D2.7, 12.12.7, the hash algorithm to use is the
1432c1d255d3SCy Schubert  * hash algorithm defined for the Base AKM (see Table 9-151 (AKM suite
1433c1d255d3SCy Schubert  * selectors)). When there is no Base AKM, the hash algorithm is selected based
1434c1d255d3SCy Schubert  * on the pairwise cipher suite provided in the RSNE by the AP in the second
1435c1d255d3SCy Schubert  * PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers
1436c1d255d3SCy Schubert  * 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used.
1437c1d255d3SCy Schubert  */
pasn_use_sha384(int akmp,int cipher)1438*a90b9d01SCy Schubert bool pasn_use_sha384(int akmp, int cipher)
1439c1d255d3SCy Schubert {
1440c1d255d3SCy Schubert 	return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 ||
1441c1d255d3SCy Schubert 					      cipher == WPA_CIPHER_GCMP_256)) ||
1442c1d255d3SCy Schubert 		wpa_key_mgmt_sha384(akmp);
1443c1d255d3SCy Schubert }
1444c1d255d3SCy Schubert 
1445c1d255d3SCy Schubert 
1446c1d255d3SCy Schubert /**
1447c1d255d3SCy Schubert  * pasn_pmk_to_ptk - Calculate PASN PTK from PMK, addresses, etc.
1448c1d255d3SCy Schubert  * @pmk: Pairwise master key
1449c1d255d3SCy Schubert  * @pmk_len: Length of PMK
1450c1d255d3SCy Schubert  * @spa: Suppplicant address
1451c1d255d3SCy Schubert  * @bssid: AP BSSID
1452c1d255d3SCy Schubert  * @dhss: Is the shared secret (DHss) derived from the PASN ephemeral key
1453c1d255d3SCy Schubert  *	exchange encoded as an octet string
1454c1d255d3SCy Schubert  * @dhss_len: The length of dhss in octets
1455c1d255d3SCy Schubert  * @ptk: Buffer for pairwise transient key
1456c1d255d3SCy Schubert  * @akmp: Negotiated AKM
1457c1d255d3SCy Schubert  * @cipher: Negotiated pairwise cipher
1458c1d255d3SCy Schubert  * @kdk_len: the length in octets that should be derived for HTLK. Can be zero.
1459c1d255d3SCy Schubert  * Returns: 0 on success, -1 on failure
1460c1d255d3SCy Schubert  */
pasn_pmk_to_ptk(const u8 * pmk,size_t pmk_len,const u8 * spa,const u8 * bssid,const u8 * dhss,size_t dhss_len,struct wpa_ptk * ptk,int akmp,int cipher,size_t kdk_len)1461c1d255d3SCy Schubert int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
1462c1d255d3SCy Schubert 		    const u8 *spa, const u8 *bssid,
1463c1d255d3SCy Schubert 		    const u8 *dhss, size_t dhss_len,
1464c1d255d3SCy Schubert 		    struct wpa_ptk *ptk, int akmp, int cipher,
1465c1d255d3SCy Schubert 		    size_t kdk_len)
1466c1d255d3SCy Schubert {
1467c1d255d3SCy Schubert 	u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
1468c1d255d3SCy Schubert 	u8 *data;
1469c1d255d3SCy Schubert 	size_t data_len, ptk_len;
1470c1d255d3SCy Schubert 	int ret = -1;
1471c1d255d3SCy Schubert 	const char *label = "PASN PTK Derivation";
1472c1d255d3SCy Schubert 
1473c1d255d3SCy Schubert 	if (!pmk || !pmk_len) {
1474c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation");
1475c1d255d3SCy Schubert 		return -1;
1476c1d255d3SCy Schubert 	}
1477c1d255d3SCy Schubert 
1478c1d255d3SCy Schubert 	if (!dhss || !dhss_len) {
1479c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: No DHss set for PTK derivation");
1480c1d255d3SCy Schubert 		return -1;
1481c1d255d3SCy Schubert 	}
1482c1d255d3SCy Schubert 
1483c1d255d3SCy Schubert 	/*
1484c1d255d3SCy Schubert 	 * PASN-PTK = KDF(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss)
1485c1d255d3SCy Schubert 	 *
1486c1d255d3SCy Schubert 	 * KCK = L(PASN-PTK, 0, 256)
1487c1d255d3SCy Schubert 	 * TK = L(PASN-PTK, 256, TK_bits)
1488c1d255d3SCy Schubert 	 * KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8)
1489c1d255d3SCy Schubert 	 */
1490c1d255d3SCy Schubert 	data_len = 2 * ETH_ALEN + dhss_len;
1491c1d255d3SCy Schubert 	data = os_zalloc(data_len);
1492c1d255d3SCy Schubert 	if (!data)
1493c1d255d3SCy Schubert 		return -1;
1494c1d255d3SCy Schubert 
1495c1d255d3SCy Schubert 	os_memcpy(data, spa, ETH_ALEN);
1496c1d255d3SCy Schubert 	os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN);
1497c1d255d3SCy Schubert 	os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len);
1498c1d255d3SCy Schubert 
1499c1d255d3SCy Schubert 	ptk->kck_len = WPA_PASN_KCK_LEN;
1500c1d255d3SCy Schubert 	ptk->tk_len = wpa_cipher_key_len(cipher);
1501c1d255d3SCy Schubert 	ptk->kdk_len = kdk_len;
1502c1d255d3SCy Schubert 	ptk->kek_len = 0;
1503c1d255d3SCy Schubert 	ptk->kek2_len = 0;
1504c1d255d3SCy Schubert 	ptk->kck2_len = 0;
1505c1d255d3SCy Schubert 
1506c1d255d3SCy Schubert 	if (ptk->tk_len == 0) {
1507c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR,
1508c1d255d3SCy Schubert 			   "PASN: Unsupported cipher (0x%x) used in PTK derivation",
1509c1d255d3SCy Schubert 			   cipher);
1510c1d255d3SCy Schubert 		goto err;
1511c1d255d3SCy Schubert 	}
1512c1d255d3SCy Schubert 
1513c1d255d3SCy Schubert 	ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
1514c1d255d3SCy Schubert 	if (ptk_len > sizeof(tmp))
1515c1d255d3SCy Schubert 		goto err;
1516c1d255d3SCy Schubert 
1517c1d255d3SCy Schubert 	if (pasn_use_sha384(akmp, cipher)) {
1518c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA384");
1519c1d255d3SCy Schubert 
1520c1d255d3SCy Schubert 		if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp,
1521c1d255d3SCy Schubert 			       ptk_len) < 0)
1522c1d255d3SCy Schubert 			goto err;
1523c1d255d3SCy Schubert 	} else {
1524c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA256");
1525c1d255d3SCy Schubert 
1526c1d255d3SCy Schubert 		if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp,
1527c1d255d3SCy Schubert 			       ptk_len) < 0)
1528c1d255d3SCy Schubert 			goto err;
1529c1d255d3SCy Schubert 	}
1530c1d255d3SCy Schubert 
1531c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
1532c1d255d3SCy Schubert 		   "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR,
1533c1d255d3SCy Schubert 		   MAC2STR(spa), MAC2STR(bssid));
1534c1d255d3SCy Schubert 
1535c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len);
1536c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len);
1537c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len);
1538c1d255d3SCy Schubert 
1539c1d255d3SCy Schubert 	os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
1540c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
1541c1d255d3SCy Schubert 
1542c1d255d3SCy Schubert 	os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
1543c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
1544c1d255d3SCy Schubert 
1545c1d255d3SCy Schubert 	if (kdk_len) {
1546c1d255d3SCy Schubert 		os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
1547c1d255d3SCy Schubert 			  ptk->kdk_len);
1548c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
1549c1d255d3SCy Schubert 				ptk->kdk, ptk->kdk_len);
1550c1d255d3SCy Schubert 	}
1551c1d255d3SCy Schubert 
1552c1d255d3SCy Schubert 	forced_memzero(tmp, sizeof(tmp));
1553c1d255d3SCy Schubert 	ret = 0;
1554c1d255d3SCy Schubert err:
1555c1d255d3SCy Schubert 	bin_clear_free(data, data_len);
1556c1d255d3SCy Schubert 	return ret;
1557c1d255d3SCy Schubert }
1558c1d255d3SCy Schubert 
1559c1d255d3SCy Schubert 
1560c1d255d3SCy Schubert /*
1561c1d255d3SCy Schubert  * pasn_mic_len - Returns the MIC length for PASN authentication
1562c1d255d3SCy Schubert  */
pasn_mic_len(int akmp,int cipher)1563c1d255d3SCy Schubert u8 pasn_mic_len(int akmp, int cipher)
1564c1d255d3SCy Schubert {
1565c1d255d3SCy Schubert 	if (pasn_use_sha384(akmp, cipher))
1566c1d255d3SCy Schubert 		return 24;
1567c1d255d3SCy Schubert 
1568c1d255d3SCy Schubert 	return 16;
1569c1d255d3SCy Schubert }
1570c1d255d3SCy Schubert 
1571c1d255d3SCy Schubert 
1572c1d255d3SCy Schubert /**
1573*a90b9d01SCy Schubert  * wpa_ltf_keyseed - Compute LTF keyseed from KDK
1574*a90b9d01SCy Schubert  * @ptk: Buffer that holds pairwise transient key
1575*a90b9d01SCy Schubert  * @akmp: Negotiated AKM
1576*a90b9d01SCy Schubert  * @cipher: Negotiated pairwise cipher
1577*a90b9d01SCy Schubert  * Returns: 0 on success, -1 on failure
1578*a90b9d01SCy Schubert  */
wpa_ltf_keyseed(struct wpa_ptk * ptk,int akmp,int cipher)1579*a90b9d01SCy Schubert int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher)
1580*a90b9d01SCy Schubert {
1581*a90b9d01SCy Schubert 	u8 *buf;
1582*a90b9d01SCy Schubert 	size_t buf_len;
1583*a90b9d01SCy Schubert 	u8 hash[SHA384_MAC_LEN];
1584*a90b9d01SCy Schubert 	const u8 *kdk = ptk->kdk;
1585*a90b9d01SCy Schubert 	size_t kdk_len = ptk->kdk_len;
1586*a90b9d01SCy Schubert 	const char *label = "Secure LTF key seed";
1587*a90b9d01SCy Schubert 
1588*a90b9d01SCy Schubert 	if (!kdk || !kdk_len) {
1589*a90b9d01SCy Schubert 		wpa_printf(MSG_ERROR, "WPA: No KDK for LTF keyseed generation");
1590*a90b9d01SCy Schubert 		return -1;
1591*a90b9d01SCy Schubert 	}
1592*a90b9d01SCy Schubert 
1593*a90b9d01SCy Schubert 	buf = (u8 *)label;
1594*a90b9d01SCy Schubert 	buf_len = os_strlen(label);
1595*a90b9d01SCy Schubert 
1596*a90b9d01SCy Schubert 	if (pasn_use_sha384(akmp, cipher)) {
1597*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1598*a90b9d01SCy Schubert 			   "WPA: Secure LTF keyseed using HMAC-SHA384");
1599*a90b9d01SCy Schubert 
1600*a90b9d01SCy Schubert 		if (hmac_sha384(kdk, kdk_len, buf, buf_len, hash)) {
1601*a90b9d01SCy Schubert 			wpa_printf(MSG_ERROR,
1602*a90b9d01SCy Schubert 				   "WPA: HMAC-SHA384 compute failed");
1603*a90b9d01SCy Schubert 			return -1;
1604*a90b9d01SCy Schubert 		}
1605*a90b9d01SCy Schubert 		os_memcpy(ptk->ltf_keyseed, hash, SHA384_MAC_LEN);
1606*a90b9d01SCy Schubert 		ptk->ltf_keyseed_len = SHA384_MAC_LEN;
1607*a90b9d01SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
1608*a90b9d01SCy Schubert 				ptk->ltf_keyseed, ptk->ltf_keyseed_len);
1609*a90b9d01SCy Schubert 
1610*a90b9d01SCy Schubert 	} else {
1611*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: LTF keyseed using HMAC-SHA256");
1612*a90b9d01SCy Schubert 
1613*a90b9d01SCy Schubert 		if (hmac_sha256(kdk, kdk_len, buf, buf_len, hash)) {
1614*a90b9d01SCy Schubert 			wpa_printf(MSG_ERROR,
1615*a90b9d01SCy Schubert 				   "WPA: HMAC-SHA256 compute failed");
1616*a90b9d01SCy Schubert 			return -1;
1617*a90b9d01SCy Schubert 		}
1618*a90b9d01SCy Schubert 		os_memcpy(ptk->ltf_keyseed, hash, SHA256_MAC_LEN);
1619*a90b9d01SCy Schubert 		ptk->ltf_keyseed_len = SHA256_MAC_LEN;
1620*a90b9d01SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
1621*a90b9d01SCy Schubert 				ptk->ltf_keyseed, ptk->ltf_keyseed_len);
1622*a90b9d01SCy Schubert 	}
1623*a90b9d01SCy Schubert 
1624*a90b9d01SCy Schubert 	return 0;
1625*a90b9d01SCy Schubert }
1626*a90b9d01SCy Schubert 
1627*a90b9d01SCy Schubert 
1628*a90b9d01SCy Schubert /**
1629c1d255d3SCy Schubert  * pasn_mic - Calculate PASN MIC
1630c1d255d3SCy Schubert  * @kck: The key confirmation key for the PASN PTKSA
1631c1d255d3SCy Schubert  * @akmp: Negotiated AKM
1632c1d255d3SCy Schubert  * @cipher: Negotiated pairwise cipher
1633c1d255d3SCy Schubert  * @addr1: For the 2nd PASN frame supplicant address; for the 3rd frame the
1634c1d255d3SCy Schubert  *	BSSID
1635c1d255d3SCy Schubert  * @addr2: For the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
1636c1d255d3SCy Schubert  *	address
1637c1d255d3SCy Schubert  * @data: For calculating the MIC for the 2nd PASN frame, this should hold the
1638c1d255d3SCy Schubert  *	Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN
1639c1d255d3SCy Schubert  *	frame, this should hold the hash of the body of the PASN 1st frame.
1640c1d255d3SCy Schubert  * @data_len: The length of data
1641c1d255d3SCy Schubert  * @frame: The body of the PASN frame including the MIC element with the octets
1642c1d255d3SCy Schubert  *	in the MIC field of the MIC element set to 0.
1643c1d255d3SCy Schubert  * @frame_len: The length of frame
1644c1d255d3SCy Schubert  * @mic: Buffer to hold the MIC on success. Should be big enough to handle the
1645c1d255d3SCy Schubert  *	maximal MIC length
1646c1d255d3SCy Schubert  * Returns: 0 on success, -1 on failure
1647c1d255d3SCy Schubert  */
pasn_mic(const u8 * kck,int akmp,int cipher,const u8 * addr1,const u8 * addr2,const u8 * data,size_t data_len,const u8 * frame,size_t frame_len,u8 * mic)1648c1d255d3SCy Schubert int pasn_mic(const u8 *kck, int akmp, int cipher,
1649c1d255d3SCy Schubert 	     const u8 *addr1, const u8 *addr2,
1650c1d255d3SCy Schubert 	     const u8 *data, size_t data_len,
1651c1d255d3SCy Schubert 	     const u8 *frame, size_t frame_len, u8 *mic)
1652c1d255d3SCy Schubert {
1653c1d255d3SCy Schubert 	u8 *buf;
1654c1d255d3SCy Schubert 	u8 hash[SHA384_MAC_LEN];
1655c1d255d3SCy Schubert 	size_t buf_len = 2 * ETH_ALEN + data_len + frame_len;
1656c1d255d3SCy Schubert 	int ret = -1;
1657c1d255d3SCy Schubert 
1658c1d255d3SCy Schubert 	if (!kck) {
1659c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation");
1660c1d255d3SCy Schubert 		return -1;
1661c1d255d3SCy Schubert 	}
1662c1d255d3SCy Schubert 
1663c1d255d3SCy Schubert 	if (!data || !data_len) {
1664c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
1665c1d255d3SCy Schubert 		return -1;
1666c1d255d3SCy Schubert 	}
1667c1d255d3SCy Schubert 
1668c1d255d3SCy Schubert 	if (!frame || !frame_len) {
1669c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
1670c1d255d3SCy Schubert 		return -1;
1671c1d255d3SCy Schubert 	}
1672c1d255d3SCy Schubert 
1673c1d255d3SCy Schubert 	buf = os_zalloc(buf_len);
1674c1d255d3SCy Schubert 	if (!buf)
1675c1d255d3SCy Schubert 		return -1;
1676c1d255d3SCy Schubert 
1677c1d255d3SCy Schubert 	os_memcpy(buf, addr1, ETH_ALEN);
1678c1d255d3SCy Schubert 	os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN);
1679c1d255d3SCy Schubert 
1680c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data", data, data_len);
1681c1d255d3SCy Schubert 	os_memcpy(buf + 2 * ETH_ALEN, data, data_len);
1682c1d255d3SCy Schubert 
1683c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame", frame, frame_len);
1684c1d255d3SCy Schubert 	os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len);
1685c1d255d3SCy Schubert 
1686c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK", kck, WPA_PASN_KCK_LEN);
1687c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf", buf, buf_len);
1688c1d255d3SCy Schubert 
1689c1d255d3SCy Schubert 	if (pasn_use_sha384(akmp, cipher)) {
1690c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384");
1691c1d255d3SCy Schubert 
1692c1d255d3SCy Schubert 		if (hmac_sha384(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
1693c1d255d3SCy Schubert 			goto err;
1694c1d255d3SCy Schubert 
1695c1d255d3SCy Schubert 		os_memcpy(mic, hash, 24);
1696c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 24);
1697c1d255d3SCy Schubert 	} else {
1698c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256");
1699c1d255d3SCy Schubert 
1700c1d255d3SCy Schubert 		if (hmac_sha256(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
1701c1d255d3SCy Schubert 			goto err;
1702c1d255d3SCy Schubert 
1703c1d255d3SCy Schubert 		os_memcpy(mic, hash, 16);
1704c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 16);
1705c1d255d3SCy Schubert 	}
1706c1d255d3SCy Schubert 
1707c1d255d3SCy Schubert 	ret = 0;
1708c1d255d3SCy Schubert err:
1709c1d255d3SCy Schubert 	bin_clear_free(buf, buf_len);
1710c1d255d3SCy Schubert 	return ret;
1711c1d255d3SCy Schubert }
1712c1d255d3SCy Schubert 
1713c1d255d3SCy Schubert 
1714c1d255d3SCy Schubert /**
1715c1d255d3SCy Schubert  * pasn_auth_frame_hash - Computes a hash of an Authentication frame body
1716c1d255d3SCy Schubert  * @akmp: Negotiated AKM
1717c1d255d3SCy Schubert  * @cipher: Negotiated pairwise cipher
1718c1d255d3SCy Schubert  * @data: Pointer to the Authentication frame body
1719c1d255d3SCy Schubert  * @len: Length of the Authentication frame body
1720c1d255d3SCy Schubert  * @hash: On return would hold the computed hash. Should be big enough to handle
1721c1d255d3SCy Schubert  *	SHA384.
1722c1d255d3SCy Schubert  * Returns: 0 on success, -1 on failure
1723c1d255d3SCy Schubert  */
pasn_auth_frame_hash(int akmp,int cipher,const u8 * data,size_t len,u8 * hash)1724c1d255d3SCy Schubert int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
1725c1d255d3SCy Schubert 			 u8 *hash)
1726c1d255d3SCy Schubert {
1727c1d255d3SCy Schubert 	if (pasn_use_sha384(akmp, cipher)) {
1728c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-384");
1729c1d255d3SCy Schubert 		return sha384_vector(1, &data, &len, hash);
1730c1d255d3SCy Schubert 	} else {
1731c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-256");
1732c1d255d3SCy Schubert 		return sha256_vector(1, &data, &len, hash);
1733c1d255d3SCy Schubert 	}
1734c1d255d3SCy Schubert }
1735c1d255d3SCy Schubert 
1736c1d255d3SCy Schubert #endif /* CONFIG_PASN */
1737c1d255d3SCy Schubert 
1738c1d255d3SCy Schubert 
rsn_selector_to_bitfield(const u8 * s)173939beb93cSSam Leffler static int rsn_selector_to_bitfield(const u8 *s)
174039beb93cSSam Leffler {
174139beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
174239beb93cSSam Leffler 		return WPA_CIPHER_NONE;
174339beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
174439beb93cSSam Leffler 		return WPA_CIPHER_TKIP;
174539beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
174639beb93cSSam Leffler 		return WPA_CIPHER_CCMP;
174739beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
174839beb93cSSam Leffler 		return WPA_CIPHER_AES_128_CMAC;
1749f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
1750f05cddf9SRui Paulo 		return WPA_CIPHER_GCMP;
17515b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
17525b9c547cSRui Paulo 		return WPA_CIPHER_CCMP_256;
17535b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
17545b9c547cSRui Paulo 		return WPA_CIPHER_GCMP_256;
17555b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
17565b9c547cSRui Paulo 		return WPA_CIPHER_BIP_GMAC_128;
17575b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
17585b9c547cSRui Paulo 		return WPA_CIPHER_BIP_GMAC_256;
17595b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
17605b9c547cSRui Paulo 		return WPA_CIPHER_BIP_CMAC_256;
17615b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
17625b9c547cSRui Paulo 		return WPA_CIPHER_GTK_NOT_USED;
176339beb93cSSam Leffler 	return 0;
176439beb93cSSam Leffler }
176539beb93cSSam Leffler 
176639beb93cSSam Leffler 
rsn_key_mgmt_to_bitfield(const u8 * s)176739beb93cSSam Leffler static int rsn_key_mgmt_to_bitfield(const u8 *s)
176839beb93cSSam Leffler {
176939beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
177039beb93cSSam Leffler 		return WPA_KEY_MGMT_IEEE8021X;
177139beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
177239beb93cSSam Leffler 		return WPA_KEY_MGMT_PSK;
177339beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
177439beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
177539beb93cSSam Leffler 		return WPA_KEY_MGMT_FT_IEEE8021X;
177639beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
177739beb93cSSam Leffler 		return WPA_KEY_MGMT_FT_PSK;
177885732ac8SCy Schubert #ifdef CONFIG_SHA384
177985732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
178085732ac8SCy Schubert 		return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
178185732ac8SCy Schubert #endif /* CONFIG_SHA384 */
178239beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
1783*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
1784*a90b9d01SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA384)
1785*a90b9d01SCy Schubert 		return WPA_KEY_MGMT_IEEE8021X_SHA384;
1786*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
178739beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
178839beb93cSSam Leffler 		return WPA_KEY_MGMT_IEEE8021X_SHA256;
178939beb93cSSam Leffler 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
179039beb93cSSam Leffler 		return WPA_KEY_MGMT_PSK_SHA256;
1791f05cddf9SRui Paulo #ifdef CONFIG_SAE
1792f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
1793f05cddf9SRui Paulo 		return WPA_KEY_MGMT_SAE;
1794*a90b9d01SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
1795*a90b9d01SCy Schubert 		return WPA_KEY_MGMT_SAE_EXT_KEY;
1796f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
1797f05cddf9SRui Paulo 		return WPA_KEY_MGMT_FT_SAE;
1798*a90b9d01SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
1799*a90b9d01SCy Schubert 		return WPA_KEY_MGMT_FT_SAE_EXT_KEY;
1800f05cddf9SRui Paulo #endif /* CONFIG_SAE */
18015b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
18025b9c547cSRui Paulo 		return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
18035b9c547cSRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
18045b9c547cSRui Paulo 		return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
180585732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256)
180685732ac8SCy Schubert 		return WPA_KEY_MGMT_FILS_SHA256;
180785732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384)
180885732ac8SCy Schubert 		return WPA_KEY_MGMT_FILS_SHA384;
180985732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256)
181085732ac8SCy Schubert 		return WPA_KEY_MGMT_FT_FILS_SHA256;
181185732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384)
181285732ac8SCy Schubert 		return WPA_KEY_MGMT_FT_FILS_SHA384;
181385732ac8SCy Schubert #ifdef CONFIG_OWE
181485732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE)
181585732ac8SCy Schubert 		return WPA_KEY_MGMT_OWE;
181685732ac8SCy Schubert #endif /* CONFIG_OWE */
181785732ac8SCy Schubert #ifdef CONFIG_DPP
181885732ac8SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP)
181985732ac8SCy Schubert 		return WPA_KEY_MGMT_DPP;
182085732ac8SCy Schubert #endif /* CONFIG_DPP */
1821325151a3SRui Paulo 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
1822325151a3SRui Paulo 		return WPA_KEY_MGMT_OSEN;
1823c1d255d3SCy Schubert #ifdef CONFIG_PASN
1824c1d255d3SCy Schubert 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PASN)
1825c1d255d3SCy Schubert 		return WPA_KEY_MGMT_PASN;
1826c1d255d3SCy Schubert #endif /* CONFIG_PASN */
182739beb93cSSam Leffler 	return 0;
182839beb93cSSam Leffler }
18295b9c547cSRui Paulo 
18305b9c547cSRui Paulo 
wpa_cipher_valid_group(int cipher)1831325151a3SRui Paulo int wpa_cipher_valid_group(int cipher)
18325b9c547cSRui Paulo {
18335b9c547cSRui Paulo 	return wpa_cipher_valid_pairwise(cipher) ||
18345b9c547cSRui Paulo 		cipher == WPA_CIPHER_GTK_NOT_USED;
18355b9c547cSRui Paulo }
18365b9c547cSRui Paulo 
18375b9c547cSRui Paulo 
wpa_cipher_valid_mgmt_group(int cipher)18385b9c547cSRui Paulo int wpa_cipher_valid_mgmt_group(int cipher)
18395b9c547cSRui Paulo {
1840c1d255d3SCy Schubert 	return cipher == WPA_CIPHER_GTK_NOT_USED ||
1841c1d255d3SCy Schubert 		cipher == WPA_CIPHER_AES_128_CMAC ||
18425b9c547cSRui Paulo 		cipher == WPA_CIPHER_BIP_GMAC_128 ||
18435b9c547cSRui Paulo 		cipher == WPA_CIPHER_BIP_GMAC_256 ||
18445b9c547cSRui Paulo 		cipher == WPA_CIPHER_BIP_CMAC_256;
18455b9c547cSRui Paulo }
184639beb93cSSam Leffler 
184739beb93cSSam Leffler 
184839beb93cSSam Leffler /**
184939beb93cSSam Leffler  * wpa_parse_wpa_ie_rsn - Parse RSN IE
185039beb93cSSam Leffler  * @rsn_ie: Buffer containing RSN IE
185139beb93cSSam Leffler  * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
185239beb93cSSam Leffler  * @data: Pointer to structure that will be filled in with parsed data
185339beb93cSSam Leffler  * Returns: 0 on success, <0 on failure
185439beb93cSSam Leffler  */
wpa_parse_wpa_ie_rsn(const u8 * rsn_ie,size_t rsn_ie_len,struct wpa_ie_data * data)185539beb93cSSam Leffler int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
185639beb93cSSam Leffler 			 struct wpa_ie_data *data)
185739beb93cSSam Leffler {
185839beb93cSSam Leffler 	const u8 *pos;
185939beb93cSSam Leffler 	int left;
186039beb93cSSam Leffler 	int i, count;
186139beb93cSSam Leffler 
186239beb93cSSam Leffler 	os_memset(data, 0, sizeof(*data));
186339beb93cSSam Leffler 	data->proto = WPA_PROTO_RSN;
186439beb93cSSam Leffler 	data->pairwise_cipher = WPA_CIPHER_CCMP;
186539beb93cSSam Leffler 	data->group_cipher = WPA_CIPHER_CCMP;
186639beb93cSSam Leffler 	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
186739beb93cSSam Leffler 	data->capabilities = 0;
186839beb93cSSam Leffler 	data->pmkid = NULL;
186939beb93cSSam Leffler 	data->num_pmkid = 0;
187039beb93cSSam Leffler 	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
187139beb93cSSam Leffler 
187239beb93cSSam Leffler 	if (rsn_ie_len == 0) {
187339beb93cSSam Leffler 		/* No RSN IE - fail silently */
187439beb93cSSam Leffler 		return -1;
187539beb93cSSam Leffler 	}
187639beb93cSSam Leffler 
187739beb93cSSam Leffler 	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
187839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
187939beb93cSSam Leffler 			   __func__, (unsigned long) rsn_ie_len);
188039beb93cSSam Leffler 		return -1;
188139beb93cSSam Leffler 	}
188239beb93cSSam Leffler 
1883325151a3SRui Paulo 	if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
1884325151a3SRui Paulo 	    rsn_ie[1] == rsn_ie_len - 2 &&
1885325151a3SRui Paulo 	    WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
1886325151a3SRui Paulo 		pos = rsn_ie + 6;
1887325151a3SRui Paulo 		left = rsn_ie_len - 6;
1888325151a3SRui Paulo 
188985732ac8SCy Schubert 		data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
18904bc52338SCy Schubert 		data->has_group = 1;
189185732ac8SCy Schubert 		data->key_mgmt = WPA_KEY_MGMT_OSEN;
1892325151a3SRui Paulo 		data->proto = WPA_PROTO_OSEN;
1893325151a3SRui Paulo 	} else {
1894325151a3SRui Paulo 		const struct rsn_ie_hdr *hdr;
1895325151a3SRui Paulo 
189639beb93cSSam Leffler 		hdr = (const struct rsn_ie_hdr *) rsn_ie;
189739beb93cSSam Leffler 
189839beb93cSSam Leffler 		if (hdr->elem_id != WLAN_EID_RSN ||
189939beb93cSSam Leffler 		    hdr->len != rsn_ie_len - 2 ||
190039beb93cSSam Leffler 		    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
190139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
190239beb93cSSam Leffler 				   __func__);
190339beb93cSSam Leffler 			return -2;
190439beb93cSSam Leffler 		}
190539beb93cSSam Leffler 
190639beb93cSSam Leffler 		pos = (const u8 *) (hdr + 1);
190739beb93cSSam Leffler 		left = rsn_ie_len - sizeof(*hdr);
1908325151a3SRui Paulo 	}
190939beb93cSSam Leffler 
191039beb93cSSam Leffler 	if (left >= RSN_SELECTOR_LEN) {
191139beb93cSSam Leffler 		data->group_cipher = rsn_selector_to_bitfield(pos);
19124bc52338SCy Schubert 		data->has_group = 1;
19135b9c547cSRui Paulo 		if (!wpa_cipher_valid_group(data->group_cipher)) {
1914780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1915780fb4a2SCy Schubert 				   "%s: invalid group cipher 0x%x (%08x)",
1916780fb4a2SCy Schubert 				   __func__, data->group_cipher,
1917780fb4a2SCy Schubert 				   WPA_GET_BE32(pos));
1918*a90b9d01SCy Schubert #ifdef CONFIG_NO_TKIP
1919*a90b9d01SCy Schubert 			if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) {
1920*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
1921*a90b9d01SCy Schubert 					   "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build",
1922*a90b9d01SCy Schubert 					   __func__);
1923*a90b9d01SCy Schubert 			}
1924*a90b9d01SCy Schubert #endif /* CONFIG_NO_TKIP */
192539beb93cSSam Leffler 			return -1;
192639beb93cSSam Leffler 		}
192739beb93cSSam Leffler 		pos += RSN_SELECTOR_LEN;
192839beb93cSSam Leffler 		left -= RSN_SELECTOR_LEN;
192939beb93cSSam Leffler 	} else if (left > 0) {
193039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
193139beb93cSSam Leffler 			   __func__, left);
193239beb93cSSam Leffler 		return -3;
193339beb93cSSam Leffler 	}
193439beb93cSSam Leffler 
193539beb93cSSam Leffler 	if (left >= 2) {
193639beb93cSSam Leffler 		data->pairwise_cipher = 0;
193739beb93cSSam Leffler 		count = WPA_GET_LE16(pos);
193839beb93cSSam Leffler 		pos += 2;
193939beb93cSSam Leffler 		left -= 2;
19405b9c547cSRui Paulo 		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
194139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
194239beb93cSSam Leffler 				   "count %u left %u", __func__, count, left);
194339beb93cSSam Leffler 			return -4;
194439beb93cSSam Leffler 		}
19454bc52338SCy Schubert 		if (count)
19464bc52338SCy Schubert 			data->has_pairwise = 1;
194739beb93cSSam Leffler 		for (i = 0; i < count; i++) {
194839beb93cSSam Leffler 			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
194939beb93cSSam Leffler 			pos += RSN_SELECTOR_LEN;
195039beb93cSSam Leffler 			left -= RSN_SELECTOR_LEN;
195139beb93cSSam Leffler 		}
195239beb93cSSam Leffler 		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
195339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
195439beb93cSSam Leffler 				   "pairwise cipher", __func__);
195539beb93cSSam Leffler 			return -1;
195639beb93cSSam Leffler 		}
195739beb93cSSam Leffler 	} else if (left == 1) {
195839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
195939beb93cSSam Leffler 			   __func__);
196039beb93cSSam Leffler 		return -5;
196139beb93cSSam Leffler 	}
196239beb93cSSam Leffler 
196339beb93cSSam Leffler 	if (left >= 2) {
196439beb93cSSam Leffler 		data->key_mgmt = 0;
196539beb93cSSam Leffler 		count = WPA_GET_LE16(pos);
196639beb93cSSam Leffler 		pos += 2;
196739beb93cSSam Leffler 		left -= 2;
19685b9c547cSRui Paulo 		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
196939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
197039beb93cSSam Leffler 				   "count %u left %u", __func__, count, left);
197139beb93cSSam Leffler 			return -6;
197239beb93cSSam Leffler 		}
197339beb93cSSam Leffler 		for (i = 0; i < count; i++) {
197439beb93cSSam Leffler 			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
197539beb93cSSam Leffler 			pos += RSN_SELECTOR_LEN;
197639beb93cSSam Leffler 			left -= RSN_SELECTOR_LEN;
197739beb93cSSam Leffler 		}
197839beb93cSSam Leffler 	} else if (left == 1) {
197939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
198039beb93cSSam Leffler 			   __func__);
198139beb93cSSam Leffler 		return -7;
198239beb93cSSam Leffler 	}
198339beb93cSSam Leffler 
198439beb93cSSam Leffler 	if (left >= 2) {
198539beb93cSSam Leffler 		data->capabilities = WPA_GET_LE16(pos);
198639beb93cSSam Leffler 		pos += 2;
198739beb93cSSam Leffler 		left -= 2;
198839beb93cSSam Leffler 	}
198939beb93cSSam Leffler 
199039beb93cSSam Leffler 	if (left >= 2) {
19915b9c547cSRui Paulo 		u16 num_pmkid = WPA_GET_LE16(pos);
199239beb93cSSam Leffler 		pos += 2;
199339beb93cSSam Leffler 		left -= 2;
19945b9c547cSRui Paulo 		if (num_pmkid > (unsigned int) left / PMKID_LEN) {
199539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
19965b9c547cSRui Paulo 				   "(num_pmkid=%u left=%d)",
19975b9c547cSRui Paulo 				   __func__, num_pmkid, left);
199839beb93cSSam Leffler 			data->num_pmkid = 0;
199939beb93cSSam Leffler 			return -9;
200039beb93cSSam Leffler 		} else {
20015b9c547cSRui Paulo 			data->num_pmkid = num_pmkid;
200239beb93cSSam Leffler 			data->pmkid = pos;
200339beb93cSSam Leffler 			pos += data->num_pmkid * PMKID_LEN;
200439beb93cSSam Leffler 			left -= data->num_pmkid * PMKID_LEN;
200539beb93cSSam Leffler 		}
200639beb93cSSam Leffler 	}
200739beb93cSSam Leffler 
200839beb93cSSam Leffler 	if (left >= 4) {
200939beb93cSSam Leffler 		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
20105b9c547cSRui Paulo 		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
2011780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
2012780fb4a2SCy Schubert 				   "%s: Unsupported management group cipher 0x%x (%08x)",
2013780fb4a2SCy Schubert 				   __func__, data->mgmt_group_cipher,
2014780fb4a2SCy Schubert 				   WPA_GET_BE32(pos));
201539beb93cSSam Leffler 			return -10;
201639beb93cSSam Leffler 		}
201739beb93cSSam Leffler 		pos += RSN_SELECTOR_LEN;
201839beb93cSSam Leffler 		left -= RSN_SELECTOR_LEN;
201939beb93cSSam Leffler 	}
202039beb93cSSam Leffler 
202139beb93cSSam Leffler 	if (left > 0) {
20225b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG,
20235b9c547cSRui Paulo 			    "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
20245b9c547cSRui Paulo 			    pos, left);
202539beb93cSSam Leffler 	}
202639beb93cSSam Leffler 
202739beb93cSSam Leffler 	return 0;
202839beb93cSSam Leffler }
202939beb93cSSam Leffler 
203039beb93cSSam Leffler 
wpa_selector_to_bitfield(const u8 * s)2031f05cddf9SRui Paulo static int wpa_selector_to_bitfield(const u8 *s)
2032f05cddf9SRui Paulo {
2033f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
2034f05cddf9SRui Paulo 		return WPA_CIPHER_NONE;
2035f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
2036f05cddf9SRui Paulo 		return WPA_CIPHER_TKIP;
2037f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
2038f05cddf9SRui Paulo 		return WPA_CIPHER_CCMP;
2039f05cddf9SRui Paulo 	return 0;
2040f05cddf9SRui Paulo }
2041f05cddf9SRui Paulo 
2042f05cddf9SRui Paulo 
wpa_key_mgmt_to_bitfield(const u8 * s)2043f05cddf9SRui Paulo static int wpa_key_mgmt_to_bitfield(const u8 *s)
2044f05cddf9SRui Paulo {
2045f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
2046f05cddf9SRui Paulo 		return WPA_KEY_MGMT_IEEE8021X;
2047f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
2048f05cddf9SRui Paulo 		return WPA_KEY_MGMT_PSK;
2049f05cddf9SRui Paulo 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
2050f05cddf9SRui Paulo 		return WPA_KEY_MGMT_WPA_NONE;
2051f05cddf9SRui Paulo 	return 0;
2052f05cddf9SRui Paulo }
2053f05cddf9SRui Paulo 
2054f05cddf9SRui Paulo 
wpa_parse_wpa_ie_wpa(const u8 * wpa_ie,size_t wpa_ie_len,struct wpa_ie_data * data)2055f05cddf9SRui Paulo int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
2056f05cddf9SRui Paulo 			 struct wpa_ie_data *data)
2057f05cddf9SRui Paulo {
2058f05cddf9SRui Paulo 	const struct wpa_ie_hdr *hdr;
2059f05cddf9SRui Paulo 	const u8 *pos;
2060f05cddf9SRui Paulo 	int left;
2061f05cddf9SRui Paulo 	int i, count;
2062f05cddf9SRui Paulo 
2063f05cddf9SRui Paulo 	os_memset(data, 0, sizeof(*data));
2064f05cddf9SRui Paulo 	data->proto = WPA_PROTO_WPA;
2065f05cddf9SRui Paulo 	data->pairwise_cipher = WPA_CIPHER_TKIP;
2066f05cddf9SRui Paulo 	data->group_cipher = WPA_CIPHER_TKIP;
2067f05cddf9SRui Paulo 	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
2068f05cddf9SRui Paulo 	data->capabilities = 0;
2069f05cddf9SRui Paulo 	data->pmkid = NULL;
2070f05cddf9SRui Paulo 	data->num_pmkid = 0;
2071f05cddf9SRui Paulo 	data->mgmt_group_cipher = 0;
2072f05cddf9SRui Paulo 
2073f05cddf9SRui Paulo 	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
2074f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
2075f05cddf9SRui Paulo 			   __func__, (unsigned long) wpa_ie_len);
2076f05cddf9SRui Paulo 		return -1;
2077f05cddf9SRui Paulo 	}
2078f05cddf9SRui Paulo 
2079f05cddf9SRui Paulo 	hdr = (const struct wpa_ie_hdr *) wpa_ie;
2080f05cddf9SRui Paulo 
2081f05cddf9SRui Paulo 	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
2082f05cddf9SRui Paulo 	    hdr->len != wpa_ie_len - 2 ||
2083f05cddf9SRui Paulo 	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
2084f05cddf9SRui Paulo 	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
2085f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
2086f05cddf9SRui Paulo 			   __func__);
2087f05cddf9SRui Paulo 		return -2;
2088f05cddf9SRui Paulo 	}
2089f05cddf9SRui Paulo 
2090f05cddf9SRui Paulo 	pos = (const u8 *) (hdr + 1);
2091f05cddf9SRui Paulo 	left = wpa_ie_len - sizeof(*hdr);
2092f05cddf9SRui Paulo 
2093f05cddf9SRui Paulo 	if (left >= WPA_SELECTOR_LEN) {
2094f05cddf9SRui Paulo 		data->group_cipher = wpa_selector_to_bitfield(pos);
2095f05cddf9SRui Paulo 		pos += WPA_SELECTOR_LEN;
2096f05cddf9SRui Paulo 		left -= WPA_SELECTOR_LEN;
2097f05cddf9SRui Paulo 	} else if (left > 0) {
2098f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
2099f05cddf9SRui Paulo 			   __func__, left);
2100f05cddf9SRui Paulo 		return -3;
2101f05cddf9SRui Paulo 	}
2102f05cddf9SRui Paulo 
2103f05cddf9SRui Paulo 	if (left >= 2) {
2104f05cddf9SRui Paulo 		data->pairwise_cipher = 0;
2105f05cddf9SRui Paulo 		count = WPA_GET_LE16(pos);
2106f05cddf9SRui Paulo 		pos += 2;
2107f05cddf9SRui Paulo 		left -= 2;
21085b9c547cSRui Paulo 		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
2109f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
2110f05cddf9SRui Paulo 				   "count %u left %u", __func__, count, left);
2111f05cddf9SRui Paulo 			return -4;
2112f05cddf9SRui Paulo 		}
2113f05cddf9SRui Paulo 		for (i = 0; i < count; i++) {
2114f05cddf9SRui Paulo 			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
2115f05cddf9SRui Paulo 			pos += WPA_SELECTOR_LEN;
2116f05cddf9SRui Paulo 			left -= WPA_SELECTOR_LEN;
2117f05cddf9SRui Paulo 		}
2118f05cddf9SRui Paulo 	} else if (left == 1) {
2119f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
2120f05cddf9SRui Paulo 			   __func__);
2121f05cddf9SRui Paulo 		return -5;
2122f05cddf9SRui Paulo 	}
2123f05cddf9SRui Paulo 
2124f05cddf9SRui Paulo 	if (left >= 2) {
2125f05cddf9SRui Paulo 		data->key_mgmt = 0;
2126f05cddf9SRui Paulo 		count = WPA_GET_LE16(pos);
2127f05cddf9SRui Paulo 		pos += 2;
2128f05cddf9SRui Paulo 		left -= 2;
21295b9c547cSRui Paulo 		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
2130f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
2131f05cddf9SRui Paulo 				   "count %u left %u", __func__, count, left);
2132f05cddf9SRui Paulo 			return -6;
2133f05cddf9SRui Paulo 		}
2134f05cddf9SRui Paulo 		for (i = 0; i < count; i++) {
2135f05cddf9SRui Paulo 			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
2136f05cddf9SRui Paulo 			pos += WPA_SELECTOR_LEN;
2137f05cddf9SRui Paulo 			left -= WPA_SELECTOR_LEN;
2138f05cddf9SRui Paulo 		}
2139f05cddf9SRui Paulo 	} else if (left == 1) {
2140f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
2141f05cddf9SRui Paulo 			   __func__);
2142f05cddf9SRui Paulo 		return -7;
2143f05cddf9SRui Paulo 	}
2144f05cddf9SRui Paulo 
2145f05cddf9SRui Paulo 	if (left >= 2) {
2146f05cddf9SRui Paulo 		data->capabilities = WPA_GET_LE16(pos);
2147f05cddf9SRui Paulo 		pos += 2;
2148f05cddf9SRui Paulo 		left -= 2;
2149f05cddf9SRui Paulo 	}
2150f05cddf9SRui Paulo 
2151f05cddf9SRui Paulo 	if (left > 0) {
21525b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG,
21535b9c547cSRui Paulo 			    "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
21545b9c547cSRui Paulo 			    pos, left);
2155f05cddf9SRui Paulo 	}
2156f05cddf9SRui Paulo 
2157f05cddf9SRui Paulo 	return 0;
2158f05cddf9SRui Paulo }
2159f05cddf9SRui Paulo 
2160f05cddf9SRui Paulo 
wpa_default_rsn_cipher(int freq)21614bc52338SCy Schubert int wpa_default_rsn_cipher(int freq)
21624bc52338SCy Schubert {
21634bc52338SCy Schubert 	if (freq > 56160)
21644bc52338SCy Schubert 		return WPA_CIPHER_GCMP; /* DMG */
21654bc52338SCy Schubert 
21664bc52338SCy Schubert 	return WPA_CIPHER_CCMP;
21674bc52338SCy Schubert }
21684bc52338SCy Schubert 
21694bc52338SCy Schubert 
217039beb93cSSam Leffler #ifdef CONFIG_IEEE80211R
217139beb93cSSam Leffler 
217239beb93cSSam Leffler /**
217339beb93cSSam Leffler  * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
217439beb93cSSam Leffler  *
217539beb93cSSam Leffler  * IEEE Std 802.11r-2008 - 8.5.1.5.3
217639beb93cSSam Leffler  */
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 key_mgmt)217785732ac8SCy Schubert int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
217839beb93cSSam Leffler 		      const u8 *ssid, size_t ssid_len,
217939beb93cSSam Leffler 		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
218085732ac8SCy Schubert 		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
2181*a90b9d01SCy Schubert 		      int key_mgmt)
218239beb93cSSam Leffler {
2183325151a3SRui Paulo 	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
218439beb93cSSam Leffler 	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
2185*a90b9d01SCy Schubert 	u8 *pos, r0_key_data[64 + 16], hash[64];
218639beb93cSSam Leffler 	const u8 *addr[2];
218739beb93cSSam Leffler 	size_t len[2];
2188*a90b9d01SCy Schubert 	size_t q, r0_key_data_len;
2189*a90b9d01SCy Schubert 	int res;
2190*a90b9d01SCy Schubert 
2191*a90b9d01SCy Schubert 	if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
2192*a90b9d01SCy Schubert 	    (xxkey_len == SHA256_MAC_LEN || xxkey_len == SHA384_MAC_LEN ||
2193*a90b9d01SCy Schubert 	     xxkey_len == SHA512_MAC_LEN))
2194*a90b9d01SCy Schubert 		q = xxkey_len;
2195*a90b9d01SCy Schubert 	else if (wpa_key_mgmt_sha384(key_mgmt))
2196*a90b9d01SCy Schubert 		q = SHA384_MAC_LEN;
2197*a90b9d01SCy Schubert 	else
2198*a90b9d01SCy Schubert 		q = SHA256_MAC_LEN;
2199*a90b9d01SCy Schubert 	r0_key_data_len = q + 16;
220039beb93cSSam Leffler 
220139beb93cSSam Leffler 	/*
2202*a90b9d01SCy Schubert 	 * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0",
220339beb93cSSam Leffler 	 *                       SSIDlength || SSID || MDID || R0KHlength ||
220439beb93cSSam Leffler 	 *                       R0KH-ID || S0KH-ID)
220585732ac8SCy Schubert 	 * XXKey is either the second 256 bits of MSK or PSK; or the first
2206*a90b9d01SCy Schubert 	 * 384 bits of MSK for FT-EAP-SHA384; or PMK from SAE.
220785732ac8SCy Schubert 	 * PMK-R0 = L(R0-Key-Data, 0, Q)
220885732ac8SCy Schubert 	 * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
2209*a90b9d01SCy Schubert 	 * Q = 384 for FT-EAP-SHA384; the length of the digest generated by H()
2210*a90b9d01SCy Schubert 	 * for FT-SAE-EXT-KEY; or otherwise, 256
221139beb93cSSam Leffler 	 */
2212325151a3SRui Paulo 	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
221385732ac8SCy Schubert 		return -1;
2214*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-SHA%zu", q * 8);
221585732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
221685732ac8SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
221785732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
221885732ac8SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
221985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
222039beb93cSSam Leffler 	pos = buf;
222139beb93cSSam Leffler 	*pos++ = ssid_len;
222239beb93cSSam Leffler 	os_memcpy(pos, ssid, ssid_len);
222339beb93cSSam Leffler 	pos += ssid_len;
222439beb93cSSam Leffler 	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
222539beb93cSSam Leffler 	pos += MOBILITY_DOMAIN_ID_LEN;
222639beb93cSSam Leffler 	*pos++ = r0kh_id_len;
222739beb93cSSam Leffler 	os_memcpy(pos, r0kh_id, r0kh_id_len);
222839beb93cSSam Leffler 	pos += r0kh_id_len;
222939beb93cSSam Leffler 	os_memcpy(pos, s0kh_id, ETH_ALEN);
223039beb93cSSam Leffler 	pos += ETH_ALEN;
223139beb93cSSam Leffler 
2232*a90b9d01SCy Schubert 	res = -1;
2233*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
2234*a90b9d01SCy Schubert 	if (q == SHA512_MAC_LEN) {
2235*a90b9d01SCy Schubert 		if (xxkey_len != SHA512_MAC_LEN) {
2236*a90b9d01SCy Schubert 			wpa_printf(MSG_ERROR,
2237*a90b9d01SCy Schubert 				   "FT: Unexpected XXKey length %d (expected %d)",
2238*a90b9d01SCy Schubert 				   (int) xxkey_len, SHA512_MAC_LEN);
2239*a90b9d01SCy Schubert 			return -1;
2240*a90b9d01SCy Schubert 		}
2241*a90b9d01SCy Schubert 		res = sha512_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
2242*a90b9d01SCy Schubert 				 r0_key_data, r0_key_data_len);
2243*a90b9d01SCy Schubert 	}
2244*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
224585732ac8SCy Schubert #ifdef CONFIG_SHA384
2246*a90b9d01SCy Schubert 	if (q == SHA384_MAC_LEN) {
224785732ac8SCy Schubert 		if (xxkey_len != SHA384_MAC_LEN) {
224885732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
224985732ac8SCy Schubert 				   "FT: Unexpected XXKey length %d (expected %d)",
225085732ac8SCy Schubert 				   (int) xxkey_len, SHA384_MAC_LEN);
225185732ac8SCy Schubert 			return -1;
225285732ac8SCy Schubert 		}
2253*a90b9d01SCy Schubert 		res = sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
2254*a90b9d01SCy Schubert 				 r0_key_data, r0_key_data_len);
225585732ac8SCy Schubert 	}
225685732ac8SCy Schubert #endif /* CONFIG_SHA384 */
2257*a90b9d01SCy Schubert 	if (q == SHA256_MAC_LEN) {
225885732ac8SCy Schubert 		if (xxkey_len != PMK_LEN) {
225985732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
226085732ac8SCy Schubert 				   "FT: Unexpected XXKey length %d (expected %d)",
226185732ac8SCy Schubert 				   (int) xxkey_len, PMK_LEN);
226285732ac8SCy Schubert 			return -1;
226385732ac8SCy Schubert 		}
2264*a90b9d01SCy Schubert 		res = sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
2265*a90b9d01SCy Schubert 				 r0_key_data, r0_key_data_len);
226685732ac8SCy Schubert 	}
2267*a90b9d01SCy Schubert 	if (res < 0)
2268*a90b9d01SCy Schubert 		return res;
226985732ac8SCy Schubert 	os_memcpy(pmk_r0, r0_key_data, q);
227085732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
227185732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
227239beb93cSSam Leffler 
227339beb93cSSam Leffler 	/*
227485732ac8SCy Schubert 	 * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
227539beb93cSSam Leffler 	 */
227639beb93cSSam Leffler 	addr[0] = (const u8 *) "FT-R0N";
227739beb93cSSam Leffler 	len[0] = 6;
227885732ac8SCy Schubert 	addr[1] = &r0_key_data[q];
227939beb93cSSam Leffler 	len[1] = 16;
228039beb93cSSam Leffler 
2281*a90b9d01SCy Schubert 	res = -1;
2282*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
2283*a90b9d01SCy Schubert 	if (q == SHA512_MAC_LEN)
2284*a90b9d01SCy Schubert 		res = sha512_vector(2, addr, len, hash);
2285*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
228685732ac8SCy Schubert #ifdef CONFIG_SHA384
2287*a90b9d01SCy Schubert 	if (q == SHA384_MAC_LEN)
2288*a90b9d01SCy Schubert 		res = sha384_vector(2, addr, len, hash);
228985732ac8SCy Schubert #endif /* CONFIG_SHA384 */
2290*a90b9d01SCy Schubert 	if (q == SHA256_MAC_LEN)
2291*a90b9d01SCy Schubert 		res = sha256_vector(2, addr, len, hash);
2292*a90b9d01SCy Schubert 	if (res < 0) {
2293*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
2294*a90b9d01SCy Schubert 			   "FT: Failed to derive PMKR0Name (PMK-R0 len %zu)",
2295*a90b9d01SCy Schubert 			   q);
2296*a90b9d01SCy Schubert 		return res;
2297*a90b9d01SCy Schubert 	}
229839beb93cSSam Leffler 	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
2299c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
2300c1d255d3SCy Schubert 	forced_memzero(r0_key_data, sizeof(r0_key_data));
230185732ac8SCy Schubert 	return 0;
230239beb93cSSam Leffler }
230339beb93cSSam Leffler 
230439beb93cSSam Leffler 
230539beb93cSSam Leffler /**
230639beb93cSSam Leffler  * wpa_derive_pmk_r1_name - Derive PMKR1Name
230739beb93cSSam Leffler  *
230839beb93cSSam Leffler  * IEEE Std 802.11r-2008 - 8.5.1.5.4
230939beb93cSSam Leffler  */
wpa_derive_pmk_r1_name(const u8 * pmk_r0_name,const u8 * r1kh_id,const u8 * s1kh_id,u8 * pmk_r1_name,size_t pmk_r1_len)231085732ac8SCy Schubert int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
2311*a90b9d01SCy Schubert 			   const u8 *s1kh_id, u8 *pmk_r1_name,
2312*a90b9d01SCy Schubert 			   size_t pmk_r1_len)
231339beb93cSSam Leffler {
2314*a90b9d01SCy Schubert 	u8 hash[64];
231539beb93cSSam Leffler 	const u8 *addr[4];
231639beb93cSSam Leffler 	size_t len[4];
2317*a90b9d01SCy Schubert 	int res;
2318*a90b9d01SCy Schubert 	const char *title;
231939beb93cSSam Leffler 
232039beb93cSSam Leffler 	/*
232185732ac8SCy Schubert 	 * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
232239beb93cSSam Leffler 	 *                               R1KH-ID || S1KH-ID))
232339beb93cSSam Leffler 	 */
232439beb93cSSam Leffler 	addr[0] = (const u8 *) "FT-R1N";
232539beb93cSSam Leffler 	len[0] = 6;
232639beb93cSSam Leffler 	addr[1] = pmk_r0_name;
232739beb93cSSam Leffler 	len[1] = WPA_PMK_NAME_LEN;
232839beb93cSSam Leffler 	addr[2] = r1kh_id;
232939beb93cSSam Leffler 	len[2] = FT_R1KH_ID_LEN;
233039beb93cSSam Leffler 	addr[3] = s1kh_id;
233139beb93cSSam Leffler 	len[3] = ETH_ALEN;
233239beb93cSSam Leffler 
2333*a90b9d01SCy Schubert 	res = -1;
2334*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
2335*a90b9d01SCy Schubert 	if (pmk_r1_len == SHA512_MAC_LEN) {
2336*a90b9d01SCy Schubert 		title = "FT: PMKR1Name (using SHA512)";
2337*a90b9d01SCy Schubert 		res = sha512_vector(4, addr, len, hash);
2338*a90b9d01SCy Schubert 	}
2339*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
234085732ac8SCy Schubert #ifdef CONFIG_SHA384
2341*a90b9d01SCy Schubert 	if (pmk_r1_len == SHA384_MAC_LEN) {
2342*a90b9d01SCy Schubert 		title = "FT: PMKR1Name (using SHA384)";
2343*a90b9d01SCy Schubert 		res = sha384_vector(4, addr, len, hash);
2344*a90b9d01SCy Schubert 	}
234585732ac8SCy Schubert #endif /* CONFIG_SHA384 */
2346*a90b9d01SCy Schubert 	if (pmk_r1_len == SHA256_MAC_LEN) {
2347*a90b9d01SCy Schubert 		title = "FT: PMKR1Name (using SHA256)";
2348*a90b9d01SCy Schubert 		res = sha256_vector(4, addr, len, hash);
2349*a90b9d01SCy Schubert 	}
2350*a90b9d01SCy Schubert 	if (res < 0) {
2351*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
2352*a90b9d01SCy Schubert 			   "FT: Failed to derive PMKR1Name (PMK-R1 len %zu)",
2353*a90b9d01SCy Schubert 			   pmk_r1_len);
2354*a90b9d01SCy Schubert 		return res;
2355*a90b9d01SCy Schubert 	}
235639beb93cSSam Leffler 	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
2357*a90b9d01SCy Schubert 	wpa_hexdump(MSG_DEBUG, title, pmk_r1_name, WPA_PMK_NAME_LEN);
235885732ac8SCy Schubert 	return 0;
235939beb93cSSam Leffler }
236039beb93cSSam Leffler 
236139beb93cSSam Leffler 
236239beb93cSSam Leffler /**
236339beb93cSSam Leffler  * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
236439beb93cSSam Leffler  *
236539beb93cSSam Leffler  * IEEE Std 802.11r-2008 - 8.5.1.5.4
236639beb93cSSam Leffler  */
wpa_derive_pmk_r1(const u8 * pmk_r0,size_t pmk_r0_len,const u8 * pmk_r0_name,const u8 * r1kh_id,const u8 * s1kh_id,u8 * pmk_r1,u8 * pmk_r1_name)236785732ac8SCy Schubert int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
236885732ac8SCy Schubert 		      const u8 *pmk_r0_name,
236939beb93cSSam Leffler 		      const u8 *r1kh_id, const u8 *s1kh_id,
237039beb93cSSam Leffler 		      u8 *pmk_r1, u8 *pmk_r1_name)
237139beb93cSSam Leffler {
237239beb93cSSam Leffler 	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
237339beb93cSSam Leffler 	u8 *pos;
2374*a90b9d01SCy Schubert 	int res;
237539beb93cSSam Leffler 
2376*a90b9d01SCy Schubert 	/* PMK-R1 = KDF-Hash(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
2377*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-SHA%zu",
2378*a90b9d01SCy Schubert 		   pmk_r0_len * 8);
237985732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
238085732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
238185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
238239beb93cSSam Leffler 	pos = buf;
238339beb93cSSam Leffler 	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
238439beb93cSSam Leffler 	pos += FT_R1KH_ID_LEN;
238539beb93cSSam Leffler 	os_memcpy(pos, s1kh_id, ETH_ALEN);
238639beb93cSSam Leffler 	pos += ETH_ALEN;
238739beb93cSSam Leffler 
2388*a90b9d01SCy Schubert 	res = -1;
2389*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
2390*a90b9d01SCy Schubert 	if (pmk_r0_len == SHA512_MAC_LEN)
2391*a90b9d01SCy Schubert 		res = sha512_prf(pmk_r0, pmk_r0_len, "FT-R1",
2392*a90b9d01SCy Schubert 				 buf, pos - buf, pmk_r1, pmk_r0_len);
2393*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
239485732ac8SCy Schubert #ifdef CONFIG_SHA384
2395*a90b9d01SCy Schubert 	if (pmk_r0_len == SHA384_MAC_LEN)
2396*a90b9d01SCy Schubert 		res = sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
2397*a90b9d01SCy Schubert 				 buf, pos - buf, pmk_r1, pmk_r0_len);
239885732ac8SCy Schubert #endif /* CONFIG_SHA384 */
2399*a90b9d01SCy Schubert 	if (pmk_r0_len == SHA256_MAC_LEN)
2400*a90b9d01SCy Schubert 		res = sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
2401*a90b9d01SCy Schubert 				 buf, pos - buf, pmk_r1, pmk_r0_len);
2402*a90b9d01SCy Schubert 	if (res < 0) {
2403*a90b9d01SCy Schubert 		wpa_printf(MSG_ERROR, "FT: Failed to derive PMK-R1");
2404*a90b9d01SCy Schubert 		return res;
240585732ac8SCy Schubert 	}
240685732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
240739beb93cSSam Leffler 
240885732ac8SCy Schubert 	return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
2409*a90b9d01SCy Schubert 				      pmk_r1_name, pmk_r0_len);
241039beb93cSSam Leffler }
241139beb93cSSam Leffler 
241239beb93cSSam Leffler 
241339beb93cSSam Leffler /**
241439beb93cSSam Leffler  * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
241539beb93cSSam Leffler  *
241639beb93cSSam Leffler  * IEEE Std 802.11r-2008 - 8.5.1.5.5
241739beb93cSSam Leffler  */
wpa_pmk_r1_to_ptk(const u8 * pmk_r1,size_t pmk_r1_len,const u8 * snonce,const u8 * anonce,const u8 * sta_addr,const u8 * bssid,const u8 * pmk_r1_name,struct wpa_ptk * ptk,u8 * ptk_name,int akmp,int cipher,size_t kdk_len)241885732ac8SCy Schubert int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
241985732ac8SCy Schubert 		      const u8 *snonce, const u8 *anonce,
242039beb93cSSam Leffler 		      const u8 *sta_addr, const u8 *bssid,
242139beb93cSSam Leffler 		      const u8 *pmk_r1_name,
2422c1d255d3SCy Schubert 		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
2423c1d255d3SCy Schubert 		      size_t kdk_len)
242439beb93cSSam Leffler {
242539beb93cSSam Leffler 	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
242639beb93cSSam Leffler 	u8 *pos, hash[32];
242739beb93cSSam Leffler 	const u8 *addr[6];
242839beb93cSSam Leffler 	size_t len[6];
2429c1d255d3SCy Schubert 	u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
2430c1d255d3SCy Schubert 	       WPA_KDK_MAX_LEN];
243185732ac8SCy Schubert 	size_t ptk_len, offset;
2432*a90b9d01SCy Schubert 	size_t key_len;
2433*a90b9d01SCy Schubert 	int res;
243439beb93cSSam Leffler 
2435c1d255d3SCy Schubert 	if (kdk_len > WPA_KDK_MAX_LEN) {
2436c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR,
2437c1d255d3SCy Schubert 			   "FT: KDK len=%zu exceeds max supported len",
2438c1d255d3SCy Schubert 			   kdk_len);
2439c1d255d3SCy Schubert 		return -1;
2440c1d255d3SCy Schubert 	}
2441c1d255d3SCy Schubert 
2442*a90b9d01SCy Schubert 	if (akmp == WPA_KEY_MGMT_FT_SAE_EXT_KEY &&
2443*a90b9d01SCy Schubert 	    (pmk_r1_len == SHA256_MAC_LEN || pmk_r1_len == SHA384_MAC_LEN ||
2444*a90b9d01SCy Schubert 	     pmk_r1_len == SHA512_MAC_LEN))
2445*a90b9d01SCy Schubert 		key_len = pmk_r1_len;
2446*a90b9d01SCy Schubert 	else if (wpa_key_mgmt_sha384(akmp))
2447*a90b9d01SCy Schubert 		key_len = SHA384_MAC_LEN;
2448*a90b9d01SCy Schubert 	else
2449*a90b9d01SCy Schubert 		key_len = SHA256_MAC_LEN;
2450*a90b9d01SCy Schubert 
245139beb93cSSam Leffler 	/*
245239beb93cSSam Leffler 	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
245339beb93cSSam Leffler 	 *                  BSSID || STA-ADDR)
245439beb93cSSam Leffler 	 */
2455*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-SHA%zu", key_len * 8);
245685732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
245785732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
245885732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
245985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
246085732ac8SCy Schubert 		   MAC2STR(bssid), MAC2STR(sta_addr));
246139beb93cSSam Leffler 	pos = buf;
246239beb93cSSam Leffler 	os_memcpy(pos, snonce, WPA_NONCE_LEN);
246339beb93cSSam Leffler 	pos += WPA_NONCE_LEN;
246439beb93cSSam Leffler 	os_memcpy(pos, anonce, WPA_NONCE_LEN);
246539beb93cSSam Leffler 	pos += WPA_NONCE_LEN;
246639beb93cSSam Leffler 	os_memcpy(pos, bssid, ETH_ALEN);
246739beb93cSSam Leffler 	pos += ETH_ALEN;
246839beb93cSSam Leffler 	os_memcpy(pos, sta_addr, ETH_ALEN);
246939beb93cSSam Leffler 	pos += ETH_ALEN;
247039beb93cSSam Leffler 
2471*a90b9d01SCy Schubert 	ptk->kck_len = wpa_kck_len(akmp, key_len);
247285732ac8SCy Schubert 	ptk->kck2_len = wpa_kck2_len(akmp);
2473*a90b9d01SCy Schubert 	ptk->kek_len = wpa_kek_len(akmp, key_len);
247485732ac8SCy Schubert 	ptk->kek2_len = wpa_kek2_len(akmp);
24755b9c547cSRui Paulo 	ptk->tk_len = wpa_cipher_key_len(cipher);
2476c1d255d3SCy Schubert 	ptk->kdk_len = kdk_len;
247785732ac8SCy Schubert 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
2478c1d255d3SCy Schubert 		ptk->kck2_len + ptk->kek2_len + ptk->kdk_len;
24795b9c547cSRui Paulo 
2480*a90b9d01SCy Schubert 	res = -1;
2481*a90b9d01SCy Schubert #ifdef CONFIG_SHA512
2482*a90b9d01SCy Schubert 	if (key_len == SHA512_MAC_LEN) {
2483*a90b9d01SCy Schubert 		if (pmk_r1_len != SHA512_MAC_LEN) {
2484*a90b9d01SCy Schubert 			wpa_printf(MSG_ERROR,
2485*a90b9d01SCy Schubert 				   "FT: Unexpected PMK-R1 length %d (expected %d)",
2486*a90b9d01SCy Schubert 				   (int) pmk_r1_len, SHA512_MAC_LEN);
2487*a90b9d01SCy Schubert 			return -1;
2488*a90b9d01SCy Schubert 		}
2489*a90b9d01SCy Schubert 		res = sha512_prf(pmk_r1, pmk_r1_len, "FT-PTK",
2490*a90b9d01SCy Schubert 				 buf, pos - buf, tmp, ptk_len);
2491*a90b9d01SCy Schubert 	}
2492*a90b9d01SCy Schubert #endif /* CONFIG_SHA512 */
249385732ac8SCy Schubert #ifdef CONFIG_SHA384
2494*a90b9d01SCy Schubert 	if (key_len == SHA384_MAC_LEN) {
249585732ac8SCy Schubert 		if (pmk_r1_len != SHA384_MAC_LEN) {
249685732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
249785732ac8SCy Schubert 				   "FT: Unexpected PMK-R1 length %d (expected %d)",
249885732ac8SCy Schubert 				   (int) pmk_r1_len, SHA384_MAC_LEN);
249985732ac8SCy Schubert 			return -1;
250085732ac8SCy Schubert 		}
2501*a90b9d01SCy Schubert 		res = sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
2502*a90b9d01SCy Schubert 				 buf, pos - buf, tmp, ptk_len);
250385732ac8SCy Schubert 	}
250485732ac8SCy Schubert #endif /* CONFIG_SHA384 */
2505*a90b9d01SCy Schubert 	if (key_len == SHA256_MAC_LEN) {
250685732ac8SCy Schubert 		if (pmk_r1_len != PMK_LEN) {
250785732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
250885732ac8SCy Schubert 				   "FT: Unexpected PMK-R1 length %d (expected %d)",
250985732ac8SCy Schubert 				   (int) pmk_r1_len, PMK_LEN);
251085732ac8SCy Schubert 			return -1;
251185732ac8SCy Schubert 		}
2512*a90b9d01SCy Schubert 		res = sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
2513*a90b9d01SCy Schubert 				 buf, pos - buf, tmp, ptk_len);
251485732ac8SCy Schubert 	}
2515*a90b9d01SCy Schubert 	if (res < 0)
2516*a90b9d01SCy Schubert 		return -1;
251785732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
251839beb93cSSam Leffler 
251939beb93cSSam Leffler 	/*
252039beb93cSSam Leffler 	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
252139beb93cSSam Leffler 	 *                                ANonce || BSSID || STA-ADDR))
252239beb93cSSam Leffler 	 */
252385732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
252439beb93cSSam Leffler 	addr[0] = pmk_r1_name;
252539beb93cSSam Leffler 	len[0] = WPA_PMK_NAME_LEN;
252639beb93cSSam Leffler 	addr[1] = (const u8 *) "FT-PTKN";
252739beb93cSSam Leffler 	len[1] = 7;
252839beb93cSSam Leffler 	addr[2] = snonce;
252939beb93cSSam Leffler 	len[2] = WPA_NONCE_LEN;
253039beb93cSSam Leffler 	addr[3] = anonce;
253139beb93cSSam Leffler 	len[3] = WPA_NONCE_LEN;
253239beb93cSSam Leffler 	addr[4] = bssid;
253339beb93cSSam Leffler 	len[4] = ETH_ALEN;
253439beb93cSSam Leffler 	addr[5] = sta_addr;
253539beb93cSSam Leffler 	len[5] = ETH_ALEN;
253639beb93cSSam Leffler 
253785732ac8SCy Schubert 	if (sha256_vector(6, addr, len, hash) < 0)
253885732ac8SCy Schubert 		return -1;
253939beb93cSSam Leffler 	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
25405b9c547cSRui Paulo 
25415b9c547cSRui Paulo 	os_memcpy(ptk->kck, tmp, ptk->kck_len);
254285732ac8SCy Schubert 	offset = ptk->kck_len;
254385732ac8SCy Schubert 	os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
254485732ac8SCy Schubert 	offset += ptk->kek_len;
254585732ac8SCy Schubert 	os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
254685732ac8SCy Schubert 	offset += ptk->tk_len;
254785732ac8SCy Schubert 	os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
25484bc52338SCy Schubert 	offset += ptk->kck2_len;
254985732ac8SCy Schubert 	os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
2550c1d255d3SCy Schubert 	offset += ptk->kek2_len;
2551c1d255d3SCy Schubert 	os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
25525b9c547cSRui Paulo 
25535b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
25545b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
255585732ac8SCy Schubert 	if (ptk->kck2_len)
255685732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
255785732ac8SCy Schubert 				ptk->kck2, ptk->kck2_len);
255885732ac8SCy Schubert 	if (ptk->kek2_len)
255985732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
256085732ac8SCy Schubert 				ptk->kek2, ptk->kek2_len);
2561c1d255d3SCy Schubert 	if (ptk->kdk_len)
2562c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "FT: KDK", ptk->kdk, ptk->kdk_len);
2563c1d255d3SCy Schubert 
25645b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
25655b9c547cSRui Paulo 	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
25665b9c547cSRui Paulo 
2567c1d255d3SCy Schubert 	forced_memzero(tmp, sizeof(tmp));
25685b9c547cSRui Paulo 
25695b9c547cSRui Paulo 	return 0;
257039beb93cSSam Leffler }
257139beb93cSSam Leffler 
257239beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */
2573e28a4053SRui Paulo 
2574e28a4053SRui Paulo 
2575e28a4053SRui Paulo /**
2576e28a4053SRui Paulo  * rsn_pmkid - Calculate PMK identifier
2577e28a4053SRui Paulo  * @pmk: Pairwise master key
2578e28a4053SRui Paulo  * @pmk_len: Length of pmk in bytes
2579e28a4053SRui Paulo  * @aa: Authenticator address
2580e28a4053SRui Paulo  * @spa: Supplicant address
2581e28a4053SRui Paulo  * @pmkid: Buffer for PMKID
258285732ac8SCy Schubert  * @akmp: Negotiated key management protocol
2583e28a4053SRui Paulo  *
258485732ac8SCy Schubert  * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy
2585*a90b9d01SCy Schubert  * AKM: 00-0F-AC:3, 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
258685732ac8SCy Schubert  * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA))
258785732ac8SCy Schubert  * AKM: 00-0F-AC:11
258885732ac8SCy Schubert  * See rsn_pmkid_suite_b()
258985732ac8SCy Schubert  * AKM: 00-0F-AC:12
259085732ac8SCy Schubert  * See rsn_pmkid_suite_b_192()
259185732ac8SCy Schubert  * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
259285732ac8SCy Schubert  * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
259385732ac8SCy Schubert  * Otherwise:
259485732ac8SCy Schubert  * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
2595e28a4053SRui Paulo  */
rsn_pmkid(const u8 * pmk,size_t pmk_len,const u8 * aa,const u8 * spa,u8 * pmkid,int akmp)2596e28a4053SRui Paulo void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
259785732ac8SCy Schubert 	       u8 *pmkid, int akmp)
2598e28a4053SRui Paulo {
2599e28a4053SRui Paulo 	char *title = "PMK Name";
2600e28a4053SRui Paulo 	const u8 *addr[3];
2601e28a4053SRui Paulo 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
260285732ac8SCy Schubert 	unsigned char hash[SHA384_MAC_LEN];
2603e28a4053SRui Paulo 
2604e28a4053SRui Paulo 	addr[0] = (u8 *) title;
2605e28a4053SRui Paulo 	addr[1] = aa;
2606e28a4053SRui Paulo 	addr[2] = spa;
2607e28a4053SRui Paulo 
260885732ac8SCy Schubert 	if (0) {
260985732ac8SCy Schubert #if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
261085732ac8SCy Schubert 	} else if (wpa_key_mgmt_sha384(akmp)) {
261185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
261285732ac8SCy Schubert 		hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
261385732ac8SCy Schubert #endif /* CONFIG_FILS || CONFIG_SHA384 */
261485732ac8SCy Schubert 	} else if (wpa_key_mgmt_sha256(akmp)) {
261585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
2616e28a4053SRui Paulo 		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
261785732ac8SCy Schubert 	} else {
261885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
2619e28a4053SRui Paulo 		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
262085732ac8SCy Schubert 	}
262185732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN);
2622e28a4053SRui Paulo 	os_memcpy(pmkid, hash, PMKID_LEN);
2623e28a4053SRui Paulo }
2624e28a4053SRui Paulo 
2625e28a4053SRui Paulo 
26265b9c547cSRui Paulo #ifdef CONFIG_SUITEB
26275b9c547cSRui Paulo /**
26285b9c547cSRui Paulo  * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
26295b9c547cSRui Paulo  * @kck: Key confirmation key
26305b9c547cSRui Paulo  * @kck_len: Length of kck in bytes
26315b9c547cSRui Paulo  * @aa: Authenticator address
26325b9c547cSRui Paulo  * @spa: Supplicant address
26335b9c547cSRui Paulo  * @pmkid: Buffer for PMKID
26345b9c547cSRui Paulo  * Returns: 0 on success, -1 on failure
26355b9c547cSRui Paulo  *
26365b9c547cSRui Paulo  * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
26375b9c547cSRui Paulo  * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
26385b9c547cSRui Paulo  */
rsn_pmkid_suite_b(const u8 * kck,size_t kck_len,const u8 * aa,const u8 * spa,u8 * pmkid)26395b9c547cSRui Paulo int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
26405b9c547cSRui Paulo 		      const u8 *spa, u8 *pmkid)
26415b9c547cSRui Paulo {
26425b9c547cSRui Paulo 	char *title = "PMK Name";
26435b9c547cSRui Paulo 	const u8 *addr[3];
26445b9c547cSRui Paulo 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
26455b9c547cSRui Paulo 	unsigned char hash[SHA256_MAC_LEN];
26465b9c547cSRui Paulo 
26475b9c547cSRui Paulo 	addr[0] = (u8 *) title;
26485b9c547cSRui Paulo 	addr[1] = aa;
26495b9c547cSRui Paulo 	addr[2] = spa;
26505b9c547cSRui Paulo 
26515b9c547cSRui Paulo 	if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
26525b9c547cSRui Paulo 		return -1;
26535b9c547cSRui Paulo 	os_memcpy(pmkid, hash, PMKID_LEN);
26545b9c547cSRui Paulo 	return 0;
26555b9c547cSRui Paulo }
26565b9c547cSRui Paulo #endif /* CONFIG_SUITEB */
26575b9c547cSRui Paulo 
26585b9c547cSRui Paulo 
26595b9c547cSRui Paulo #ifdef CONFIG_SUITEB192
26605b9c547cSRui Paulo /**
26615b9c547cSRui Paulo  * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
26625b9c547cSRui Paulo  * @kck: Key confirmation key
26635b9c547cSRui Paulo  * @kck_len: Length of kck in bytes
26645b9c547cSRui Paulo  * @aa: Authenticator address
26655b9c547cSRui Paulo  * @spa: Supplicant address
26665b9c547cSRui Paulo  * @pmkid: Buffer for PMKID
26675b9c547cSRui Paulo  * Returns: 0 on success, -1 on failure
26685b9c547cSRui Paulo  *
26695b9c547cSRui Paulo  * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
26705b9c547cSRui Paulo  * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
26715b9c547cSRui Paulo  */
rsn_pmkid_suite_b_192(const u8 * kck,size_t kck_len,const u8 * aa,const u8 * spa,u8 * pmkid)26725b9c547cSRui Paulo int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
26735b9c547cSRui Paulo 			  const u8 *spa, u8 *pmkid)
26745b9c547cSRui Paulo {
26755b9c547cSRui Paulo 	char *title = "PMK Name";
26765b9c547cSRui Paulo 	const u8 *addr[3];
26775b9c547cSRui Paulo 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
26785b9c547cSRui Paulo 	unsigned char hash[SHA384_MAC_LEN];
26795b9c547cSRui Paulo 
26805b9c547cSRui Paulo 	addr[0] = (u8 *) title;
26815b9c547cSRui Paulo 	addr[1] = aa;
26825b9c547cSRui Paulo 	addr[2] = spa;
26835b9c547cSRui Paulo 
26845b9c547cSRui Paulo 	if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
26855b9c547cSRui Paulo 		return -1;
26865b9c547cSRui Paulo 	os_memcpy(pmkid, hash, PMKID_LEN);
26875b9c547cSRui Paulo 	return 0;
26885b9c547cSRui Paulo }
26895b9c547cSRui Paulo #endif /* CONFIG_SUITEB192 */
26905b9c547cSRui Paulo 
26915b9c547cSRui Paulo 
2692e28a4053SRui Paulo /**
2693e28a4053SRui Paulo  * wpa_cipher_txt - Convert cipher suite to a text string
2694e28a4053SRui Paulo  * @cipher: Cipher suite (WPA_CIPHER_* enum)
2695e28a4053SRui Paulo  * Returns: Pointer to a text string of the cipher suite name
2696e28a4053SRui Paulo  */
wpa_cipher_txt(int cipher)2697e28a4053SRui Paulo const char * wpa_cipher_txt(int cipher)
2698e28a4053SRui Paulo {
2699e28a4053SRui Paulo 	switch (cipher) {
2700e28a4053SRui Paulo 	case WPA_CIPHER_NONE:
2701e28a4053SRui Paulo 		return "NONE";
2702c1d255d3SCy Schubert #ifdef CONFIG_WEP
2703e28a4053SRui Paulo 	case WPA_CIPHER_WEP40:
2704e28a4053SRui Paulo 		return "WEP-40";
2705e28a4053SRui Paulo 	case WPA_CIPHER_WEP104:
2706e28a4053SRui Paulo 		return "WEP-104";
2707c1d255d3SCy Schubert #endif /* CONFIG_WEP */
2708e28a4053SRui Paulo 	case WPA_CIPHER_TKIP:
2709e28a4053SRui Paulo 		return "TKIP";
2710e28a4053SRui Paulo 	case WPA_CIPHER_CCMP:
2711e28a4053SRui Paulo 		return "CCMP";
2712e28a4053SRui Paulo 	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
2713e28a4053SRui Paulo 		return "CCMP+TKIP";
2714f05cddf9SRui Paulo 	case WPA_CIPHER_GCMP:
2715f05cddf9SRui Paulo 		return "GCMP";
27165b9c547cSRui Paulo 	case WPA_CIPHER_GCMP_256:
27175b9c547cSRui Paulo 		return "GCMP-256";
27185b9c547cSRui Paulo 	case WPA_CIPHER_CCMP_256:
27195b9c547cSRui Paulo 		return "CCMP-256";
272085732ac8SCy Schubert 	case WPA_CIPHER_AES_128_CMAC:
272185732ac8SCy Schubert 		return "BIP";
272285732ac8SCy Schubert 	case WPA_CIPHER_BIP_GMAC_128:
272385732ac8SCy Schubert 		return "BIP-GMAC-128";
272485732ac8SCy Schubert 	case WPA_CIPHER_BIP_GMAC_256:
272585732ac8SCy Schubert 		return "BIP-GMAC-256";
272685732ac8SCy Schubert 	case WPA_CIPHER_BIP_CMAC_256:
272785732ac8SCy Schubert 		return "BIP-CMAC-256";
27285b9c547cSRui Paulo 	case WPA_CIPHER_GTK_NOT_USED:
27295b9c547cSRui Paulo 		return "GTK_NOT_USED";
2730e28a4053SRui Paulo 	default:
2731e28a4053SRui Paulo 		return "UNKNOWN";
2732e28a4053SRui Paulo 	}
2733e28a4053SRui Paulo }
2734e28a4053SRui Paulo 
2735e28a4053SRui Paulo 
2736e28a4053SRui Paulo /**
2737e28a4053SRui Paulo  * wpa_key_mgmt_txt - Convert key management suite to a text string
2738e28a4053SRui Paulo  * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
2739e28a4053SRui Paulo  * @proto: WPA/WPA2 version (WPA_PROTO_*)
2740e28a4053SRui Paulo  * Returns: Pointer to a text string of the key management suite name
2741e28a4053SRui Paulo  */
wpa_key_mgmt_txt(int key_mgmt,int proto)2742e28a4053SRui Paulo const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
2743e28a4053SRui Paulo {
2744e28a4053SRui Paulo 	switch (key_mgmt) {
2745e28a4053SRui Paulo 	case WPA_KEY_MGMT_IEEE8021X:
2746e28a4053SRui Paulo 		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
2747e28a4053SRui Paulo 			return "WPA2+WPA/IEEE 802.1X/EAP";
2748e28a4053SRui Paulo 		return proto == WPA_PROTO_RSN ?
2749e28a4053SRui Paulo 			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
2750e28a4053SRui Paulo 	case WPA_KEY_MGMT_PSK:
2751e28a4053SRui Paulo 		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
2752e28a4053SRui Paulo 			return "WPA2-PSK+WPA-PSK";
2753e28a4053SRui Paulo 		return proto == WPA_PROTO_RSN ?
2754e28a4053SRui Paulo 			"WPA2-PSK" : "WPA-PSK";
2755e28a4053SRui Paulo 	case WPA_KEY_MGMT_NONE:
2756e28a4053SRui Paulo 		return "NONE";
2757780fb4a2SCy Schubert 	case WPA_KEY_MGMT_WPA_NONE:
2758780fb4a2SCy Schubert 		return "WPA-NONE";
2759e28a4053SRui Paulo 	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
2760e28a4053SRui Paulo 		return "IEEE 802.1X (no WPA)";
2761e28a4053SRui Paulo #ifdef CONFIG_IEEE80211R
2762e28a4053SRui Paulo 	case WPA_KEY_MGMT_FT_IEEE8021X:
2763e28a4053SRui Paulo 		return "FT-EAP";
276485732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
276585732ac8SCy Schubert 		return "FT-EAP-SHA384";
2766e28a4053SRui Paulo 	case WPA_KEY_MGMT_FT_PSK:
2767e28a4053SRui Paulo 		return "FT-PSK";
2768e28a4053SRui Paulo #endif /* CONFIG_IEEE80211R */
2769e28a4053SRui Paulo 	case WPA_KEY_MGMT_IEEE8021X_SHA256:
2770e28a4053SRui Paulo 		return "WPA2-EAP-SHA256";
2771e28a4053SRui Paulo 	case WPA_KEY_MGMT_PSK_SHA256:
2772e28a4053SRui Paulo 		return "WPA2-PSK-SHA256";
27735b9c547cSRui Paulo 	case WPA_KEY_MGMT_WPS:
27745b9c547cSRui Paulo 		return "WPS";
27755b9c547cSRui Paulo 	case WPA_KEY_MGMT_SAE:
27765b9c547cSRui Paulo 		return "SAE";
2777*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
2778*a90b9d01SCy Schubert 		return "SAE-EXT-KEY";
27795b9c547cSRui Paulo 	case WPA_KEY_MGMT_FT_SAE:
27805b9c547cSRui Paulo 		return "FT-SAE";
2781*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
2782*a90b9d01SCy Schubert 		return "FT-SAE-EXT-KEY";
27835b9c547cSRui Paulo 	case WPA_KEY_MGMT_OSEN:
27845b9c547cSRui Paulo 		return "OSEN";
27855b9c547cSRui Paulo 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
27865b9c547cSRui Paulo 		return "WPA2-EAP-SUITE-B";
27875b9c547cSRui Paulo 	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
27885b9c547cSRui Paulo 		return "WPA2-EAP-SUITE-B-192";
278985732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
279085732ac8SCy Schubert 		return "FILS-SHA256";
279185732ac8SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
279285732ac8SCy Schubert 		return "FILS-SHA384";
279385732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA256:
279485732ac8SCy Schubert 		return "FT-FILS-SHA256";
279585732ac8SCy Schubert 	case WPA_KEY_MGMT_FT_FILS_SHA384:
279685732ac8SCy Schubert 		return "FT-FILS-SHA384";
279785732ac8SCy Schubert 	case WPA_KEY_MGMT_OWE:
279885732ac8SCy Schubert 		return "OWE";
279985732ac8SCy Schubert 	case WPA_KEY_MGMT_DPP:
280085732ac8SCy Schubert 		return "DPP";
2801c1d255d3SCy Schubert 	case WPA_KEY_MGMT_PASN:
2802c1d255d3SCy Schubert 		return "PASN";
2803*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_IEEE8021X_SHA384:
2804*a90b9d01SCy Schubert 		return "WPA2-EAP-SHA384";
2805e28a4053SRui Paulo 	default:
2806e28a4053SRui Paulo 		return "UNKNOWN";
2807e28a4053SRui Paulo 	}
2808e28a4053SRui Paulo }
2809e28a4053SRui Paulo 
2810e28a4053SRui Paulo 
wpa_akm_to_suite(int akm)28115b9c547cSRui Paulo u32 wpa_akm_to_suite(int akm)
28125b9c547cSRui Paulo {
281385732ac8SCy Schubert 	if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
281485732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
28155b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
281685732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_802_1X;
28175b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_FT_PSK)
281885732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_PSK;
2819*a90b9d01SCy Schubert 	if (akm & WPA_KEY_MGMT_IEEE8021X_SHA384)
2820*a90b9d01SCy Schubert 		return RSN_AUTH_KEY_MGMT_802_1X_SHA384;
28215b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
282285732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
28235b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_IEEE8021X)
282485732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
28255b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_PSK_SHA256)
282685732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
28275b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_PSK)
282885732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
28295b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_CCKM)
283085732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_CCKM;
28315b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_OSEN)
283285732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_OSEN;
28335b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
283485732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
28355b9c547cSRui Paulo 	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
283685732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
283785732ac8SCy Schubert 	if (akm & WPA_KEY_MGMT_FILS_SHA256)
283885732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FILS_SHA256;
283985732ac8SCy Schubert 	if (akm & WPA_KEY_MGMT_FILS_SHA384)
284085732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FILS_SHA384;
284185732ac8SCy Schubert 	if (akm & WPA_KEY_MGMT_FT_FILS_SHA256)
284285732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
284385732ac8SCy Schubert 	if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
284485732ac8SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
2845206b73d0SCy Schubert 	if (akm & WPA_KEY_MGMT_SAE)
2846206b73d0SCy Schubert 		return RSN_AUTH_KEY_MGMT_SAE;
2847*a90b9d01SCy Schubert 	if (akm & WPA_KEY_MGMT_SAE_EXT_KEY)
2848*a90b9d01SCy Schubert 		return RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
2849206b73d0SCy Schubert 	if (akm & WPA_KEY_MGMT_FT_SAE)
2850206b73d0SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_SAE;
2851*a90b9d01SCy Schubert 	if (akm & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
2852*a90b9d01SCy Schubert 		return RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
2853206b73d0SCy Schubert 	if (akm & WPA_KEY_MGMT_OWE)
2854206b73d0SCy Schubert 		return RSN_AUTH_KEY_MGMT_OWE;
2855206b73d0SCy Schubert 	if (akm & WPA_KEY_MGMT_DPP)
2856206b73d0SCy Schubert 		return RSN_AUTH_KEY_MGMT_DPP;
28575b9c547cSRui Paulo 	return 0;
28585b9c547cSRui Paulo }
28595b9c547cSRui Paulo 
28605b9c547cSRui Paulo 
wpa_compare_rsn_ie(int ft_initial_assoc,const u8 * ie1,size_t ie1len,const u8 * ie2,size_t ie2len)2861e28a4053SRui Paulo int wpa_compare_rsn_ie(int ft_initial_assoc,
2862e28a4053SRui Paulo 		       const u8 *ie1, size_t ie1len,
2863e28a4053SRui Paulo 		       const u8 *ie2, size_t ie2len)
2864e28a4053SRui Paulo {
2865e28a4053SRui Paulo 	if (ie1 == NULL || ie2 == NULL)
2866e28a4053SRui Paulo 		return -1;
2867e28a4053SRui Paulo 
2868e28a4053SRui Paulo 	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
2869e28a4053SRui Paulo 		return 0; /* identical IEs */
2870e28a4053SRui Paulo 
2871e28a4053SRui Paulo #ifdef CONFIG_IEEE80211R
2872e28a4053SRui Paulo 	if (ft_initial_assoc) {
2873e28a4053SRui Paulo 		struct wpa_ie_data ie1d, ie2d;
2874e28a4053SRui Paulo 		/*
2875e28a4053SRui Paulo 		 * The PMKID-List in RSN IE is different between Beacon/Probe
2876e28a4053SRui Paulo 		 * Response/(Re)Association Request frames and EAPOL-Key
2877e28a4053SRui Paulo 		 * messages in FT initial mobility domain association. Allow
2878e28a4053SRui Paulo 		 * for this, but verify that other parts of the RSN IEs are
2879e28a4053SRui Paulo 		 * identical.
2880e28a4053SRui Paulo 		 */
2881e28a4053SRui Paulo 		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
2882e28a4053SRui Paulo 		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
2883e28a4053SRui Paulo 			return -1;
2884e28a4053SRui Paulo 		if (ie1d.proto == ie2d.proto &&
2885e28a4053SRui Paulo 		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
2886e28a4053SRui Paulo 		    ie1d.group_cipher == ie2d.group_cipher &&
2887e28a4053SRui Paulo 		    ie1d.key_mgmt == ie2d.key_mgmt &&
2888e28a4053SRui Paulo 		    ie1d.capabilities == ie2d.capabilities &&
2889e28a4053SRui Paulo 		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
2890e28a4053SRui Paulo 			return 0;
2891e28a4053SRui Paulo 	}
2892e28a4053SRui Paulo #endif /* CONFIG_IEEE80211R */
2893e28a4053SRui Paulo 
2894e28a4053SRui Paulo 	return -1;
2895e28a4053SRui Paulo }
2896e28a4053SRui Paulo 
2897e28a4053SRui Paulo 
wpa_insert_pmkid(u8 * ies,size_t * ies_len,const u8 * pmkid,bool replace)2898*a90b9d01SCy Schubert int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid, bool replace)
2899e28a4053SRui Paulo {
2900e28a4053SRui Paulo 	u8 *start, *end, *rpos, *rend;
2901e28a4053SRui Paulo 	int added = 0;
2902e28a4053SRui Paulo 
2903e28a4053SRui Paulo 	start = ies;
2904780fb4a2SCy Schubert 	end = ies + *ies_len;
2905e28a4053SRui Paulo 
2906e28a4053SRui Paulo 	while (start < end) {
2907e28a4053SRui Paulo 		if (*start == WLAN_EID_RSN)
2908e28a4053SRui Paulo 			break;
2909e28a4053SRui Paulo 		start += 2 + start[1];
2910e28a4053SRui Paulo 	}
2911e28a4053SRui Paulo 	if (start >= end) {
2912c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
2913e28a4053SRui Paulo 		return -1;
2914e28a4053SRui Paulo 	}
2915c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
2916e28a4053SRui Paulo 		    start, 2 + start[1]);
2917e28a4053SRui Paulo 
2918e28a4053SRui Paulo 	/* Find start of PMKID-Count */
2919e28a4053SRui Paulo 	rpos = start + 2;
2920e28a4053SRui Paulo 	rend = rpos + start[1];
2921e28a4053SRui Paulo 
2922e28a4053SRui Paulo 	/* Skip Version and Group Data Cipher Suite */
2923e28a4053SRui Paulo 	rpos += 2 + 4;
2924e28a4053SRui Paulo 	/* Skip Pairwise Cipher Suite Count and List */
2925e28a4053SRui Paulo 	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2926e28a4053SRui Paulo 	/* Skip AKM Suite Count and List */
2927e28a4053SRui Paulo 	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2928e28a4053SRui Paulo 
2929e28a4053SRui Paulo 	if (rpos == rend) {
2930e28a4053SRui Paulo 		/* Add RSN Capabilities */
2931e28a4053SRui Paulo 		os_memmove(rpos + 2, rpos, end - rpos);
2932e28a4053SRui Paulo 		*rpos++ = 0;
2933e28a4053SRui Paulo 		*rpos++ = 0;
2934325151a3SRui Paulo 		added += 2;
2935325151a3SRui Paulo 		start[1] += 2;
2936325151a3SRui Paulo 		rend = rpos;
2937e28a4053SRui Paulo 	} else {
2938e28a4053SRui Paulo 		/* Skip RSN Capabilities */
2939e28a4053SRui Paulo 		rpos += 2;
2940e28a4053SRui Paulo 		if (rpos > rend) {
2941c1d255d3SCy Schubert 			wpa_printf(MSG_ERROR,
2942c1d255d3SCy Schubert 				   "RSN: Could not parse RSNE in IEs data");
2943e28a4053SRui Paulo 			return -1;
2944e28a4053SRui Paulo 		}
2945e28a4053SRui Paulo 	}
2946e28a4053SRui Paulo 
2947e28a4053SRui Paulo 	if (rpos == rend) {
2948e28a4053SRui Paulo 		/* No PMKID-Count field included; add it */
2949325151a3SRui Paulo 		os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
2950e28a4053SRui Paulo 		WPA_PUT_LE16(rpos, 1);
2951e28a4053SRui Paulo 		rpos += 2;
2952e28a4053SRui Paulo 		os_memcpy(rpos, pmkid, PMKID_LEN);
2953e28a4053SRui Paulo 		added += 2 + PMKID_LEN;
2954e28a4053SRui Paulo 		start[1] += 2 + PMKID_LEN;
2955e28a4053SRui Paulo 	} else {
2956780fb4a2SCy Schubert 		u16 num_pmkid;
2957780fb4a2SCy Schubert 
2958780fb4a2SCy Schubert 		if (rend - rpos < 2)
2959e28a4053SRui Paulo 			return -1;
2960780fb4a2SCy Schubert 		num_pmkid = WPA_GET_LE16(rpos);
2961780fb4a2SCy Schubert 		if (num_pmkid * PMKID_LEN > rend - rpos - 2)
2962780fb4a2SCy Schubert 			return -1;
2963*a90b9d01SCy Schubert 		/* PMKID-Count was included; use it */
2964*a90b9d01SCy Schubert 		if (replace && num_pmkid != 0) {
2965*a90b9d01SCy Schubert 			u8 *after;
2966*a90b9d01SCy Schubert 
2967780fb4a2SCy Schubert 			/*
2968780fb4a2SCy Schubert 			 * PMKID may have been included in RSN IE in
2969780fb4a2SCy Schubert 			 * (Re)Association Request frame, so remove the old
2970780fb4a2SCy Schubert 			 * PMKID(s) first before adding the new one.
2971780fb4a2SCy Schubert 			 */
2972780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
2973c1d255d3SCy Schubert 				   "RSN: Remove %u old PMKID(s) from RSNE",
2974780fb4a2SCy Schubert 				   num_pmkid);
2975780fb4a2SCy Schubert 			after = rpos + 2 + num_pmkid * PMKID_LEN;
2976c1d255d3SCy Schubert 			os_memmove(rpos + 2, after, end - after);
2977780fb4a2SCy Schubert 			start[1] -= num_pmkid * PMKID_LEN;
2978780fb4a2SCy Schubert 			added -= num_pmkid * PMKID_LEN;
2979*a90b9d01SCy Schubert 			num_pmkid = 0;
2980e28a4053SRui Paulo 		}
2981*a90b9d01SCy Schubert 		WPA_PUT_LE16(rpos, num_pmkid + 1);
2982e28a4053SRui Paulo 		rpos += 2;
2983325151a3SRui Paulo 		os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
2984e28a4053SRui Paulo 		os_memcpy(rpos, pmkid, PMKID_LEN);
2985e28a4053SRui Paulo 		added += PMKID_LEN;
2986e28a4053SRui Paulo 		start[1] += PMKID_LEN;
2987e28a4053SRui Paulo 	}
2988e28a4053SRui Paulo 
2989c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
2990c1d255d3SCy Schubert 		    start, 2 + start[1]);
2991e28a4053SRui Paulo 
2992780fb4a2SCy Schubert 	*ies_len += added;
2993780fb4a2SCy Schubert 
2994780fb4a2SCy Schubert 	return 0;
2995e28a4053SRui Paulo }
2996f05cddf9SRui Paulo 
2997f05cddf9SRui Paulo 
wpa_cipher_key_len(int cipher)2998f05cddf9SRui Paulo int wpa_cipher_key_len(int cipher)
2999f05cddf9SRui Paulo {
3000f05cddf9SRui Paulo 	switch (cipher) {
30015b9c547cSRui Paulo 	case WPA_CIPHER_CCMP_256:
30025b9c547cSRui Paulo 	case WPA_CIPHER_GCMP_256:
30035b9c547cSRui Paulo 	case WPA_CIPHER_BIP_GMAC_256:
30045b9c547cSRui Paulo 	case WPA_CIPHER_BIP_CMAC_256:
30055b9c547cSRui Paulo 		return 32;
3006f05cddf9SRui Paulo 	case WPA_CIPHER_CCMP:
3007f05cddf9SRui Paulo 	case WPA_CIPHER_GCMP:
30085b9c547cSRui Paulo 	case WPA_CIPHER_AES_128_CMAC:
30095b9c547cSRui Paulo 	case WPA_CIPHER_BIP_GMAC_128:
3010f05cddf9SRui Paulo 		return 16;
3011f05cddf9SRui Paulo 	case WPA_CIPHER_TKIP:
3012f05cddf9SRui Paulo 		return 32;
3013*a90b9d01SCy Schubert 	default:
3014f05cddf9SRui Paulo 		return 0;
3015f05cddf9SRui Paulo 	}
3016*a90b9d01SCy Schubert }
3017f05cddf9SRui Paulo 
3018f05cddf9SRui Paulo 
wpa_cipher_rsc_len(int cipher)3019f05cddf9SRui Paulo int wpa_cipher_rsc_len(int cipher)
3020f05cddf9SRui Paulo {
3021f05cddf9SRui Paulo 	switch (cipher) {
30225b9c547cSRui Paulo 	case WPA_CIPHER_CCMP_256:
30235b9c547cSRui Paulo 	case WPA_CIPHER_GCMP_256:
3024f05cddf9SRui Paulo 	case WPA_CIPHER_CCMP:
3025f05cddf9SRui Paulo 	case WPA_CIPHER_GCMP:
3026f05cddf9SRui Paulo 	case WPA_CIPHER_TKIP:
3027f05cddf9SRui Paulo 		return 6;
3028*a90b9d01SCy Schubert 	default:
3029f05cddf9SRui Paulo 		return 0;
3030f05cddf9SRui Paulo 	}
3031*a90b9d01SCy Schubert }
3032f05cddf9SRui Paulo 
3033f05cddf9SRui Paulo 
wpa_cipher_to_alg(int cipher)303485732ac8SCy Schubert enum wpa_alg wpa_cipher_to_alg(int cipher)
3035f05cddf9SRui Paulo {
3036f05cddf9SRui Paulo 	switch (cipher) {
30375b9c547cSRui Paulo 	case WPA_CIPHER_CCMP_256:
30385b9c547cSRui Paulo 		return WPA_ALG_CCMP_256;
30395b9c547cSRui Paulo 	case WPA_CIPHER_GCMP_256:
30405b9c547cSRui Paulo 		return WPA_ALG_GCMP_256;
3041f05cddf9SRui Paulo 	case WPA_CIPHER_CCMP:
3042f05cddf9SRui Paulo 		return WPA_ALG_CCMP;
3043f05cddf9SRui Paulo 	case WPA_CIPHER_GCMP:
3044f05cddf9SRui Paulo 		return WPA_ALG_GCMP;
3045f05cddf9SRui Paulo 	case WPA_CIPHER_TKIP:
3046f05cddf9SRui Paulo 		return WPA_ALG_TKIP;
30475b9c547cSRui Paulo 	case WPA_CIPHER_AES_128_CMAC:
3048c1d255d3SCy Schubert 		return WPA_ALG_BIP_CMAC_128;
30495b9c547cSRui Paulo 	case WPA_CIPHER_BIP_GMAC_128:
30505b9c547cSRui Paulo 		return WPA_ALG_BIP_GMAC_128;
30515b9c547cSRui Paulo 	case WPA_CIPHER_BIP_GMAC_256:
30525b9c547cSRui Paulo 		return WPA_ALG_BIP_GMAC_256;
30535b9c547cSRui Paulo 	case WPA_CIPHER_BIP_CMAC_256:
30545b9c547cSRui Paulo 		return WPA_ALG_BIP_CMAC_256;
3055*a90b9d01SCy Schubert 	default:
3056f05cddf9SRui Paulo 		return WPA_ALG_NONE;
3057f05cddf9SRui Paulo 	}
3058*a90b9d01SCy Schubert }
3059f05cddf9SRui Paulo 
3060f05cddf9SRui Paulo 
wpa_cipher_valid_pairwise(int cipher)3061f05cddf9SRui Paulo int wpa_cipher_valid_pairwise(int cipher)
3062f05cddf9SRui Paulo {
3063c1d255d3SCy Schubert #ifdef CONFIG_NO_TKIP
3064c1d255d3SCy Schubert 	return cipher == WPA_CIPHER_CCMP_256 ||
3065c1d255d3SCy Schubert 		cipher == WPA_CIPHER_GCMP_256 ||
3066c1d255d3SCy Schubert 		cipher == WPA_CIPHER_CCMP ||
3067c1d255d3SCy Schubert 		cipher == WPA_CIPHER_GCMP;
3068c1d255d3SCy Schubert #else /* CONFIG_NO_TKIP */
30695b9c547cSRui Paulo 	return cipher == WPA_CIPHER_CCMP_256 ||
30705b9c547cSRui Paulo 		cipher == WPA_CIPHER_GCMP_256 ||
30715b9c547cSRui Paulo 		cipher == WPA_CIPHER_CCMP ||
3072f05cddf9SRui Paulo 		cipher == WPA_CIPHER_GCMP ||
3073f05cddf9SRui Paulo 		cipher == WPA_CIPHER_TKIP;
3074c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
3075f05cddf9SRui Paulo }
3076f05cddf9SRui Paulo 
3077f05cddf9SRui Paulo 
wpa_cipher_to_suite(int proto,int cipher)3078f05cddf9SRui Paulo u32 wpa_cipher_to_suite(int proto, int cipher)
3079f05cddf9SRui Paulo {
30805b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_CCMP_256)
30815b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_CCMP_256;
30825b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_GCMP_256)
30835b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_GCMP_256;
3084f05cddf9SRui Paulo 	if (cipher & WPA_CIPHER_CCMP)
3085f05cddf9SRui Paulo 		return (proto == WPA_PROTO_RSN ?
3086f05cddf9SRui Paulo 			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
3087f05cddf9SRui Paulo 	if (cipher & WPA_CIPHER_GCMP)
3088f05cddf9SRui Paulo 		return RSN_CIPHER_SUITE_GCMP;
3089f05cddf9SRui Paulo 	if (cipher & WPA_CIPHER_TKIP)
3090f05cddf9SRui Paulo 		return (proto == WPA_PROTO_RSN ?
3091f05cddf9SRui Paulo 			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
3092f05cddf9SRui Paulo 	if (cipher & WPA_CIPHER_NONE)
3093f05cddf9SRui Paulo 		return (proto == WPA_PROTO_RSN ?
3094f05cddf9SRui Paulo 			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
30955b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_GTK_NOT_USED)
30965b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
30975b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_AES_128_CMAC)
30985b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_AES_128_CMAC;
30995b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_BIP_GMAC_128)
31005b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_BIP_GMAC_128;
31015b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_BIP_GMAC_256)
31025b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_BIP_GMAC_256;
31035b9c547cSRui Paulo 	if (cipher & WPA_CIPHER_BIP_CMAC_256)
31045b9c547cSRui Paulo 		return RSN_CIPHER_SUITE_BIP_CMAC_256;
3105f05cddf9SRui Paulo 	return 0;
3106f05cddf9SRui Paulo }
3107f05cddf9SRui Paulo 
3108f05cddf9SRui Paulo 
rsn_cipher_put_suites(u8 * start,int ciphers)31095b9c547cSRui Paulo int rsn_cipher_put_suites(u8 *start, int ciphers)
3110f05cddf9SRui Paulo {
31115b9c547cSRui Paulo 	u8 *pos = start;
3112f05cddf9SRui Paulo 
31135b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP_256) {
31145b9c547cSRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
31155b9c547cSRui Paulo 		pos += RSN_SELECTOR_LEN;
31165b9c547cSRui Paulo 	}
31175b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP_256) {
31185b9c547cSRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
31195b9c547cSRui Paulo 		pos += RSN_SELECTOR_LEN;
31205b9c547cSRui Paulo 	}
3121f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_CCMP) {
3122f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
3123f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
3124f05cddf9SRui Paulo 	}
3125f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_GCMP) {
3126f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
3127f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
3128f05cddf9SRui Paulo 	}
3129f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_TKIP) {
3130f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
3131f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
3132f05cddf9SRui Paulo 	}
3133f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_NONE) {
3134f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
3135f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
3136f05cddf9SRui Paulo 	}
3137f05cddf9SRui Paulo 
31385b9c547cSRui Paulo 	return (pos - start) / RSN_SELECTOR_LEN;
3139f05cddf9SRui Paulo }
3140f05cddf9SRui Paulo 
3141f05cddf9SRui Paulo 
wpa_cipher_put_suites(u8 * start,int ciphers)31425b9c547cSRui Paulo int wpa_cipher_put_suites(u8 *start, int ciphers)
3143f05cddf9SRui Paulo {
31445b9c547cSRui Paulo 	u8 *pos = start;
3145f05cddf9SRui Paulo 
3146f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_CCMP) {
3147f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
3148f05cddf9SRui Paulo 		pos += WPA_SELECTOR_LEN;
3149f05cddf9SRui Paulo 	}
3150f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_TKIP) {
3151f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
3152f05cddf9SRui Paulo 		pos += WPA_SELECTOR_LEN;
3153f05cddf9SRui Paulo 	}
3154f05cddf9SRui Paulo 	if (ciphers & WPA_CIPHER_NONE) {
3155f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
3156f05cddf9SRui Paulo 		pos += WPA_SELECTOR_LEN;
3157f05cddf9SRui Paulo 	}
3158f05cddf9SRui Paulo 
31595b9c547cSRui Paulo 	return (pos - start) / RSN_SELECTOR_LEN;
31605b9c547cSRui Paulo }
31615b9c547cSRui Paulo 
31625b9c547cSRui Paulo 
wpa_pick_pairwise_cipher(int ciphers,int none_allowed)31635b9c547cSRui Paulo int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
31645b9c547cSRui Paulo {
31655b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP_256)
31665b9c547cSRui Paulo 		return WPA_CIPHER_CCMP_256;
31675b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP_256)
31685b9c547cSRui Paulo 		return WPA_CIPHER_GCMP_256;
31695b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP)
31705b9c547cSRui Paulo 		return WPA_CIPHER_CCMP;
31715b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP)
31725b9c547cSRui Paulo 		return WPA_CIPHER_GCMP;
31735b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_TKIP)
31745b9c547cSRui Paulo 		return WPA_CIPHER_TKIP;
31755b9c547cSRui Paulo 	if (none_allowed && (ciphers & WPA_CIPHER_NONE))
31765b9c547cSRui Paulo 		return WPA_CIPHER_NONE;
31775b9c547cSRui Paulo 	return -1;
31785b9c547cSRui Paulo }
31795b9c547cSRui Paulo 
31805b9c547cSRui Paulo 
wpa_pick_group_cipher(int ciphers)31815b9c547cSRui Paulo int wpa_pick_group_cipher(int ciphers)
31825b9c547cSRui Paulo {
31835b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP_256)
31845b9c547cSRui Paulo 		return WPA_CIPHER_CCMP_256;
31855b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP_256)
31865b9c547cSRui Paulo 		return WPA_CIPHER_GCMP_256;
31875b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP)
31885b9c547cSRui Paulo 		return WPA_CIPHER_CCMP;
31895b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP)
31905b9c547cSRui Paulo 		return WPA_CIPHER_GCMP;
31915b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GTK_NOT_USED)
31925b9c547cSRui Paulo 		return WPA_CIPHER_GTK_NOT_USED;
31935b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_TKIP)
31945b9c547cSRui Paulo 		return WPA_CIPHER_TKIP;
31955b9c547cSRui Paulo 	return -1;
31965b9c547cSRui Paulo }
31975b9c547cSRui Paulo 
31985b9c547cSRui Paulo 
wpa_parse_cipher(const char * value)31995b9c547cSRui Paulo int wpa_parse_cipher(const char *value)
32005b9c547cSRui Paulo {
32015b9c547cSRui Paulo 	int val = 0, last;
32025b9c547cSRui Paulo 	char *start, *end, *buf;
32035b9c547cSRui Paulo 
32045b9c547cSRui Paulo 	buf = os_strdup(value);
32055b9c547cSRui Paulo 	if (buf == NULL)
32065b9c547cSRui Paulo 		return -1;
32075b9c547cSRui Paulo 	start = buf;
32085b9c547cSRui Paulo 
32095b9c547cSRui Paulo 	while (*start != '\0') {
32105b9c547cSRui Paulo 		while (*start == ' ' || *start == '\t')
32115b9c547cSRui Paulo 			start++;
32125b9c547cSRui Paulo 		if (*start == '\0')
32135b9c547cSRui Paulo 			break;
32145b9c547cSRui Paulo 		end = start;
32155b9c547cSRui Paulo 		while (*end != ' ' && *end != '\t' && *end != '\0')
32165b9c547cSRui Paulo 			end++;
32175b9c547cSRui Paulo 		last = *end == '\0';
32185b9c547cSRui Paulo 		*end = '\0';
32195b9c547cSRui Paulo 		if (os_strcmp(start, "CCMP-256") == 0)
32205b9c547cSRui Paulo 			val |= WPA_CIPHER_CCMP_256;
32215b9c547cSRui Paulo 		else if (os_strcmp(start, "GCMP-256") == 0)
32225b9c547cSRui Paulo 			val |= WPA_CIPHER_GCMP_256;
32235b9c547cSRui Paulo 		else if (os_strcmp(start, "CCMP") == 0)
32245b9c547cSRui Paulo 			val |= WPA_CIPHER_CCMP;
32255b9c547cSRui Paulo 		else if (os_strcmp(start, "GCMP") == 0)
32265b9c547cSRui Paulo 			val |= WPA_CIPHER_GCMP;
3227c1d255d3SCy Schubert #ifndef CONFIG_NO_TKIP
32285b9c547cSRui Paulo 		else if (os_strcmp(start, "TKIP") == 0)
32295b9c547cSRui Paulo 			val |= WPA_CIPHER_TKIP;
3230c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
3231c1d255d3SCy Schubert #ifdef CONFIG_WEP
32325b9c547cSRui Paulo 		else if (os_strcmp(start, "WEP104") == 0)
32335b9c547cSRui Paulo 			val |= WPA_CIPHER_WEP104;
32345b9c547cSRui Paulo 		else if (os_strcmp(start, "WEP40") == 0)
32355b9c547cSRui Paulo 			val |= WPA_CIPHER_WEP40;
3236c1d255d3SCy Schubert #endif /* CONFIG_WEP */
32375b9c547cSRui Paulo 		else if (os_strcmp(start, "NONE") == 0)
32385b9c547cSRui Paulo 			val |= WPA_CIPHER_NONE;
32395b9c547cSRui Paulo 		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
32405b9c547cSRui Paulo 			val |= WPA_CIPHER_GTK_NOT_USED;
324185732ac8SCy Schubert 		else if (os_strcmp(start, "AES-128-CMAC") == 0)
324285732ac8SCy Schubert 			val |= WPA_CIPHER_AES_128_CMAC;
324385732ac8SCy Schubert 		else if (os_strcmp(start, "BIP-GMAC-128") == 0)
324485732ac8SCy Schubert 			val |= WPA_CIPHER_BIP_GMAC_128;
324585732ac8SCy Schubert 		else if (os_strcmp(start, "BIP-GMAC-256") == 0)
324685732ac8SCy Schubert 			val |= WPA_CIPHER_BIP_GMAC_256;
324785732ac8SCy Schubert 		else if (os_strcmp(start, "BIP-CMAC-256") == 0)
324885732ac8SCy Schubert 			val |= WPA_CIPHER_BIP_CMAC_256;
32495b9c547cSRui Paulo 		else {
32505b9c547cSRui Paulo 			os_free(buf);
32515b9c547cSRui Paulo 			return -1;
32525b9c547cSRui Paulo 		}
32535b9c547cSRui Paulo 
32545b9c547cSRui Paulo 		if (last)
32555b9c547cSRui Paulo 			break;
32565b9c547cSRui Paulo 		start = end + 1;
32575b9c547cSRui Paulo 	}
32585b9c547cSRui Paulo 	os_free(buf);
32595b9c547cSRui Paulo 
32605b9c547cSRui Paulo 	return val;
32615b9c547cSRui Paulo }
32625b9c547cSRui Paulo 
32635b9c547cSRui Paulo 
wpa_write_ciphers(char * start,char * end,int ciphers,const char * delim)32645b9c547cSRui Paulo int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
32655b9c547cSRui Paulo {
32665b9c547cSRui Paulo 	char *pos = start;
32675b9c547cSRui Paulo 	int ret;
32685b9c547cSRui Paulo 
32695b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP_256) {
32705b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
32715b9c547cSRui Paulo 				  pos == start ? "" : delim);
32725b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
32735b9c547cSRui Paulo 			return -1;
32745b9c547cSRui Paulo 		pos += ret;
32755b9c547cSRui Paulo 	}
32765b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP_256) {
32775b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
32785b9c547cSRui Paulo 				  pos == start ? "" : delim);
32795b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
32805b9c547cSRui Paulo 			return -1;
32815b9c547cSRui Paulo 		pos += ret;
32825b9c547cSRui Paulo 	}
32835b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_CCMP) {
32845b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sCCMP",
32855b9c547cSRui Paulo 				  pos == start ? "" : delim);
32865b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
32875b9c547cSRui Paulo 			return -1;
32885b9c547cSRui Paulo 		pos += ret;
32895b9c547cSRui Paulo 	}
32905b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_GCMP) {
32915b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sGCMP",
32925b9c547cSRui Paulo 				  pos == start ? "" : delim);
32935b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
32945b9c547cSRui Paulo 			return -1;
32955b9c547cSRui Paulo 		pos += ret;
32965b9c547cSRui Paulo 	}
32975b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_TKIP) {
32985b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sTKIP",
32995b9c547cSRui Paulo 				  pos == start ? "" : delim);
33005b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
33015b9c547cSRui Paulo 			return -1;
33025b9c547cSRui Paulo 		pos += ret;
33035b9c547cSRui Paulo 	}
330485732ac8SCy Schubert 	if (ciphers & WPA_CIPHER_AES_128_CMAC) {
330585732ac8SCy Schubert 		ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC",
330685732ac8SCy Schubert 				  pos == start ? "" : delim);
330785732ac8SCy Schubert 		if (os_snprintf_error(end - pos, ret))
330885732ac8SCy Schubert 			return -1;
330985732ac8SCy Schubert 		pos += ret;
331085732ac8SCy Schubert 	}
331185732ac8SCy Schubert 	if (ciphers & WPA_CIPHER_BIP_GMAC_128) {
331285732ac8SCy Schubert 		ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
331385732ac8SCy Schubert 				  pos == start ? "" : delim);
331485732ac8SCy Schubert 		if (os_snprintf_error(end - pos, ret))
331585732ac8SCy Schubert 			return -1;
331685732ac8SCy Schubert 		pos += ret;
331785732ac8SCy Schubert 	}
331885732ac8SCy Schubert 	if (ciphers & WPA_CIPHER_BIP_GMAC_256) {
331985732ac8SCy Schubert 		ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
332085732ac8SCy Schubert 				  pos == start ? "" : delim);
332185732ac8SCy Schubert 		if (os_snprintf_error(end - pos, ret))
332285732ac8SCy Schubert 			return -1;
332385732ac8SCy Schubert 		pos += ret;
332485732ac8SCy Schubert 	}
332585732ac8SCy Schubert 	if (ciphers & WPA_CIPHER_BIP_CMAC_256) {
332685732ac8SCy Schubert 		ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
332785732ac8SCy Schubert 				  pos == start ? "" : delim);
332885732ac8SCy Schubert 		if (os_snprintf_error(end - pos, ret))
332985732ac8SCy Schubert 			return -1;
333085732ac8SCy Schubert 		pos += ret;
333185732ac8SCy Schubert 	}
33325b9c547cSRui Paulo 	if (ciphers & WPA_CIPHER_NONE) {
33335b9c547cSRui Paulo 		ret = os_snprintf(pos, end - pos, "%sNONE",
33345b9c547cSRui Paulo 				  pos == start ? "" : delim);
33355b9c547cSRui Paulo 		if (os_snprintf_error(end - pos, ret))
33365b9c547cSRui Paulo 			return -1;
33375b9c547cSRui Paulo 		pos += ret;
33385b9c547cSRui Paulo 	}
33395b9c547cSRui Paulo 
33405b9c547cSRui Paulo 	return pos - start;
33415b9c547cSRui Paulo }
33425b9c547cSRui Paulo 
33435b9c547cSRui Paulo 
wpa_select_ap_group_cipher(int wpa,int wpa_pairwise,int rsn_pairwise)33445b9c547cSRui Paulo int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
33455b9c547cSRui Paulo {
33465b9c547cSRui Paulo 	int pairwise = 0;
33475b9c547cSRui Paulo 
33485b9c547cSRui Paulo 	/* Select group cipher based on the enabled pairwise cipher suites */
33495b9c547cSRui Paulo 	if (wpa & 1)
33505b9c547cSRui Paulo 		pairwise |= wpa_pairwise;
33515b9c547cSRui Paulo 	if (wpa & 2)
33525b9c547cSRui Paulo 		pairwise |= rsn_pairwise;
33535b9c547cSRui Paulo 
33545b9c547cSRui Paulo 	if (pairwise & WPA_CIPHER_TKIP)
33555b9c547cSRui Paulo 		return WPA_CIPHER_TKIP;
33565b9c547cSRui Paulo 	if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
33575b9c547cSRui Paulo 		return WPA_CIPHER_GCMP;
33585b9c547cSRui Paulo 	if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
33595b9c547cSRui Paulo 			 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
33605b9c547cSRui Paulo 		return WPA_CIPHER_GCMP_256;
33615b9c547cSRui Paulo 	if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
33625b9c547cSRui Paulo 			 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
33635b9c547cSRui Paulo 		return WPA_CIPHER_CCMP_256;
33645b9c547cSRui Paulo 	return WPA_CIPHER_CCMP;
3365f05cddf9SRui Paulo }
336685732ac8SCy Schubert 
336785732ac8SCy Schubert 
336885732ac8SCy Schubert #ifdef CONFIG_FILS
fils_domain_name_hash(const char * domain,u8 * hash)336985732ac8SCy Schubert int fils_domain_name_hash(const char *domain, u8 *hash)
337085732ac8SCy Schubert {
337185732ac8SCy Schubert 	char buf[255], *wpos = buf;
337285732ac8SCy Schubert 	const char *pos = domain;
337385732ac8SCy Schubert 	size_t len;
337485732ac8SCy Schubert 	const u8 *addr[1];
337585732ac8SCy Schubert 	u8 mac[SHA256_MAC_LEN];
337685732ac8SCy Schubert 
337785732ac8SCy Schubert 	for (len = 0; len < sizeof(buf) && *pos; len++) {
337885732ac8SCy Schubert 		if (isalpha(*pos) && isupper(*pos))
337985732ac8SCy Schubert 			*wpos++ = tolower(*pos);
338085732ac8SCy Schubert 		else
338185732ac8SCy Schubert 			*wpos++ = *pos;
338285732ac8SCy Schubert 		pos++;
338385732ac8SCy Schubert 	}
338485732ac8SCy Schubert 
338585732ac8SCy Schubert 	addr[0] = (const u8 *) buf;
338685732ac8SCy Schubert 	if (sha256_vector(1, addr, &len, mac) < 0)
338785732ac8SCy Schubert 		return -1;
338885732ac8SCy Schubert 	os_memcpy(hash, mac, 2);
338985732ac8SCy Schubert 	return 0;
339085732ac8SCy Schubert }
339185732ac8SCy Schubert #endif /* CONFIG_FILS */
3392c1d255d3SCy Schubert 
3393c1d255d3SCy Schubert 
3394c1d255d3SCy Schubert /**
3395c1d255d3SCy Schubert  * wpa_parse_vendor_specific - Parse Vendor Specific IEs
3396c1d255d3SCy Schubert  * @pos: Pointer to the IE header
3397c1d255d3SCy Schubert  * @end: Pointer to the end of the Key Data buffer
3398c1d255d3SCy Schubert  * @ie: Pointer to parsed IE data
3399c1d255d3SCy Schubert  */
wpa_parse_vendor_specific(const u8 * pos,const u8 * end,struct wpa_eapol_ie_parse * ie)3400c1d255d3SCy Schubert static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
3401c1d255d3SCy Schubert 				      struct wpa_eapol_ie_parse *ie)
3402c1d255d3SCy Schubert {
3403c1d255d3SCy Schubert 	unsigned int oui;
3404c1d255d3SCy Schubert 
3405c1d255d3SCy Schubert 	if (pos[1] < 4) {
3406c1d255d3SCy Schubert 		wpa_printf(MSG_MSGDUMP,
3407c1d255d3SCy Schubert 			   "Too short vendor specific IE ignored (len=%u)",
3408c1d255d3SCy Schubert 			   pos[1]);
3409c1d255d3SCy Schubert 		return;
3410c1d255d3SCy Schubert 	}
3411c1d255d3SCy Schubert 
3412c1d255d3SCy Schubert 	oui = WPA_GET_BE24(&pos[2]);
3413c1d255d3SCy Schubert 	if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
3414c1d255d3SCy Schubert 		if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
3415c1d255d3SCy Schubert 			ie->wmm = &pos[2];
3416c1d255d3SCy Schubert 			ie->wmm_len = pos[1];
3417c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
3418c1d255d3SCy Schubert 				    ie->wmm, ie->wmm_len);
3419c1d255d3SCy Schubert 		} else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
3420c1d255d3SCy Schubert 			ie->wmm = &pos[2];
3421c1d255d3SCy Schubert 			ie->wmm_len = pos[1];
3422c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
3423c1d255d3SCy Schubert 				    ie->wmm, ie->wmm_len);
3424c1d255d3SCy Schubert 		}
3425c1d255d3SCy Schubert 	}
3426c1d255d3SCy Schubert }
3427c1d255d3SCy Schubert 
3428c1d255d3SCy Schubert 
3429c1d255d3SCy Schubert /**
3430c1d255d3SCy Schubert  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
3431c1d255d3SCy Schubert  * @pos: Pointer to the IE header
3432c1d255d3SCy Schubert  * @ie: Pointer to parsed IE data
3433c1d255d3SCy Schubert  * Returns: 0 on success, 1 if end mark is found, 2 if KDE is not recognized
3434c1d255d3SCy Schubert  */
wpa_parse_generic(const u8 * pos,struct wpa_eapol_ie_parse * ie)3435c1d255d3SCy Schubert static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
3436c1d255d3SCy Schubert {
3437*a90b9d01SCy Schubert 	u8 len = pos[1];
3438*a90b9d01SCy Schubert 	size_t dlen = 2 + len;
3439*a90b9d01SCy Schubert 	u32 selector;
3440*a90b9d01SCy Schubert 	const u8 *p;
3441*a90b9d01SCy Schubert 	size_t left;
3442*a90b9d01SCy Schubert 	u8 link_id;
3443*a90b9d01SCy Schubert 	char title[50];
3444*a90b9d01SCy Schubert 	int ret;
3445*a90b9d01SCy Schubert 
3446*a90b9d01SCy Schubert 	if (len == 0)
3447c1d255d3SCy Schubert 		return 1;
3448c1d255d3SCy Schubert 
3449*a90b9d01SCy Schubert 	if (len < RSN_SELECTOR_LEN)
3450*a90b9d01SCy Schubert 		return 2;
3451*a90b9d01SCy Schubert 
3452*a90b9d01SCy Schubert 	p = pos + 2;
3453*a90b9d01SCy Schubert 	selector = RSN_SELECTOR_GET(p);
3454*a90b9d01SCy Schubert 	p += RSN_SELECTOR_LEN;
3455*a90b9d01SCy Schubert 	left = len - RSN_SELECTOR_LEN;
3456*a90b9d01SCy Schubert 
3457*a90b9d01SCy Schubert 	if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) {
3458c1d255d3SCy Schubert 		ie->wpa_ie = pos;
3459*a90b9d01SCy Schubert 		ie->wpa_ie_len = dlen;
3460c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
3461c1d255d3SCy Schubert 			    ie->wpa_ie, ie->wpa_ie_len);
3462c1d255d3SCy Schubert 		return 0;
3463c1d255d3SCy Schubert 	}
3464c1d255d3SCy Schubert 
3465*a90b9d01SCy Schubert 	if (selector == OSEN_IE_VENDOR_TYPE) {
3466c1d255d3SCy Schubert 		ie->osen = pos;
3467*a90b9d01SCy Schubert 		ie->osen_len = dlen;
3468c1d255d3SCy Schubert 		return 0;
3469c1d255d3SCy Schubert 	}
3470c1d255d3SCy Schubert 
3471*a90b9d01SCy Schubert 	if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) {
3472*a90b9d01SCy Schubert 		ie->pmkid = p;
3473*a90b9d01SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen);
3474c1d255d3SCy Schubert 		return 0;
3475c1d255d3SCy Schubert 	}
3476c1d255d3SCy Schubert 
3477*a90b9d01SCy Schubert 	if (left >= 2 && selector == RSN_KEY_DATA_KEYID) {
3478*a90b9d01SCy Schubert 		ie->key_id = p;
3479*a90b9d01SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", pos, dlen);
3480c1d255d3SCy Schubert 		return 0;
3481c1d255d3SCy Schubert 	}
3482c1d255d3SCy Schubert 
3483*a90b9d01SCy Schubert 	if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) {
3484*a90b9d01SCy Schubert 		ie->gtk = p;
3485*a90b9d01SCy Schubert 		ie->gtk_len = left;
3486*a90b9d01SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen);
3487c1d255d3SCy Schubert 		return 0;
3488c1d255d3SCy Schubert 	}
3489c1d255d3SCy Schubert 
3490*a90b9d01SCy Schubert 	if (left >= ETH_ALEN && selector == RSN_KEY_DATA_MAC_ADDR) {
3491*a90b9d01SCy Schubert 		ie->mac_addr = p;
3492*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key: " MACSTR,
3493*a90b9d01SCy Schubert 			   MAC2STR(ie->mac_addr));
3494c1d255d3SCy Schubert 		return 0;
3495c1d255d3SCy Schubert 	}
3496c1d255d3SCy Schubert 
3497*a90b9d01SCy Schubert 	if (left > 2 && selector == RSN_KEY_DATA_IGTK) {
3498*a90b9d01SCy Schubert 		ie->igtk = p;
3499*a90b9d01SCy Schubert 		ie->igtk_len = left;
3500c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
3501*a90b9d01SCy Schubert 				pos, dlen);
3502c1d255d3SCy Schubert 		return 0;
3503c1d255d3SCy Schubert 	}
3504c1d255d3SCy Schubert 
3505*a90b9d01SCy Schubert 	if (left > 2 && selector == RSN_KEY_DATA_BIGTK) {
3506*a90b9d01SCy Schubert 		ie->bigtk = p;
3507*a90b9d01SCy Schubert 		ie->bigtk_len = left;
3508c1d255d3SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
3509*a90b9d01SCy Schubert 				pos, dlen);
3510c1d255d3SCy Schubert 		return 0;
3511c1d255d3SCy Schubert 	}
3512c1d255d3SCy Schubert 
3513*a90b9d01SCy Schubert 	if (left >= 1 && selector == WFA_KEY_DATA_IP_ADDR_REQ) {
3514*a90b9d01SCy Schubert 		ie->ip_addr_req = p;
3515c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
3516*a90b9d01SCy Schubert 			    ie->ip_addr_req, left);
3517c1d255d3SCy Schubert 		return 0;
3518c1d255d3SCy Schubert 	}
3519c1d255d3SCy Schubert 
3520*a90b9d01SCy Schubert 	if (left >= 3 * 4 && selector == WFA_KEY_DATA_IP_ADDR_ALLOC) {
3521*a90b9d01SCy Schubert 		ie->ip_addr_alloc = p;
3522c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG,
3523c1d255d3SCy Schubert 			    "WPA: IP Address Allocation in EAPOL-Key",
3524*a90b9d01SCy Schubert 			    ie->ip_addr_alloc, left);
3525c1d255d3SCy Schubert 		return 0;
3526c1d255d3SCy Schubert 	}
3527c1d255d3SCy Schubert 
3528*a90b9d01SCy Schubert 	if (left > 2 && selector == RSN_KEY_DATA_OCI) {
3529*a90b9d01SCy Schubert 		ie->oci = p;
3530*a90b9d01SCy Schubert 		ie->oci_len = left;
3531c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
3532*a90b9d01SCy Schubert 			    pos, dlen);
3533c1d255d3SCy Schubert 		return 0;
3534c1d255d3SCy Schubert 	}
3535c1d255d3SCy Schubert 
3536*a90b9d01SCy Schubert 	if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) {
3537*a90b9d01SCy Schubert 		ie->transition_disable = p;
3538*a90b9d01SCy Schubert 		ie->transition_disable_len = left;
3539c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG,
3540c1d255d3SCy Schubert 			    "WPA: Transition Disable KDE in EAPOL-Key",
3541*a90b9d01SCy Schubert 			    pos, dlen);
3542c1d255d3SCy Schubert 		return 0;
3543c1d255d3SCy Schubert 	}
3544c1d255d3SCy Schubert 
3545*a90b9d01SCy Schubert 	if (left >= 2 && selector == WFA_KEY_DATA_DPP) {
3546*a90b9d01SCy Schubert 		ie->dpp_kde = p;
3547*a90b9d01SCy Schubert 		ie->dpp_kde_len = left;
3548*a90b9d01SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen);
3549*a90b9d01SCy Schubert 		return 0;
3550*a90b9d01SCy Schubert 	}
3551*a90b9d01SCy Schubert 
3552*a90b9d01SCy Schubert 	if (left >= RSN_MLO_GTK_KDE_PREFIX_LENGTH &&
3553*a90b9d01SCy Schubert 	    selector == RSN_KEY_DATA_MLO_GTK) {
3554*a90b9d01SCy Schubert 		link_id = (p[0] & RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK) >>
3555*a90b9d01SCy Schubert 			RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT;
3556*a90b9d01SCy Schubert 		if (link_id >= MAX_NUM_MLD_LINKS)
3557*a90b9d01SCy Schubert 			return 2;
3558*a90b9d01SCy Schubert 
3559*a90b9d01SCy Schubert 		ie->valid_mlo_gtks |= BIT(link_id);
3560*a90b9d01SCy Schubert 		ie->mlo_gtk[link_id] = p;
3561*a90b9d01SCy Schubert 		ie->mlo_gtk_len[link_id] = left;
3562*a90b9d01SCy Schubert 		ret = os_snprintf(title, sizeof(title),
3563*a90b9d01SCy Schubert 				  "RSN: Link ID %u - MLO GTK KDE in EAPOL-Key",
3564*a90b9d01SCy Schubert 				  link_id);
3565*a90b9d01SCy Schubert 		if (!os_snprintf_error(sizeof(title), ret))
3566*a90b9d01SCy Schubert 			wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
3567*a90b9d01SCy Schubert 		return 0;
3568*a90b9d01SCy Schubert 	}
3569*a90b9d01SCy Schubert 
3570*a90b9d01SCy Schubert 	if (left >= RSN_MLO_IGTK_KDE_PREFIX_LENGTH &&
3571*a90b9d01SCy Schubert 	    selector == RSN_KEY_DATA_MLO_IGTK) {
3572*a90b9d01SCy Schubert 		link_id = (p[8] & RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK) >>
3573*a90b9d01SCy Schubert 			  RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT;
3574*a90b9d01SCy Schubert 		if (link_id >= MAX_NUM_MLD_LINKS)
3575*a90b9d01SCy Schubert 			return 2;
3576*a90b9d01SCy Schubert 
3577*a90b9d01SCy Schubert 		ie->valid_mlo_igtks |= BIT(link_id);
3578*a90b9d01SCy Schubert 		ie->mlo_igtk[link_id] = p;
3579*a90b9d01SCy Schubert 		ie->mlo_igtk_len[link_id] = left;
3580*a90b9d01SCy Schubert 		ret = os_snprintf(title, sizeof(title),
3581*a90b9d01SCy Schubert 				  "RSN: Link ID %u - MLO IGTK KDE in EAPOL-Key",
3582*a90b9d01SCy Schubert 				  link_id);
3583*a90b9d01SCy Schubert 		if (!os_snprintf_error(sizeof(title), ret))
3584*a90b9d01SCy Schubert 			wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
3585*a90b9d01SCy Schubert 		return 0;
3586*a90b9d01SCy Schubert 	}
3587*a90b9d01SCy Schubert 
3588*a90b9d01SCy Schubert 	if (left >= RSN_MLO_BIGTK_KDE_PREFIX_LENGTH &&
3589*a90b9d01SCy Schubert 	    selector == RSN_KEY_DATA_MLO_BIGTK) {
3590*a90b9d01SCy Schubert 		link_id = (p[8] & RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK) >>
3591*a90b9d01SCy Schubert 			  RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT;
3592*a90b9d01SCy Schubert 		if (link_id >= MAX_NUM_MLD_LINKS)
3593*a90b9d01SCy Schubert 			return 2;
3594*a90b9d01SCy Schubert 
3595*a90b9d01SCy Schubert 		ie->valid_mlo_bigtks |= BIT(link_id);
3596*a90b9d01SCy Schubert 		ie->mlo_bigtk[link_id] = p;
3597*a90b9d01SCy Schubert 		ie->mlo_bigtk_len[link_id] = left;
3598*a90b9d01SCy Schubert 		ret = os_snprintf(title, sizeof(title),
3599*a90b9d01SCy Schubert 				  "RSN: Link ID %u - MLO BIGTK KDE in EAPOL-Key",
3600*a90b9d01SCy Schubert 				  link_id);
3601*a90b9d01SCy Schubert 		if (!os_snprintf_error(sizeof(title), ret))
3602*a90b9d01SCy Schubert 			wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
3603*a90b9d01SCy Schubert 		return 0;
3604*a90b9d01SCy Schubert 	}
3605*a90b9d01SCy Schubert 
3606*a90b9d01SCy Schubert 	if (left >= RSN_MLO_LINK_KDE_FIXED_LENGTH &&
3607*a90b9d01SCy Schubert 	    selector == RSN_KEY_DATA_MLO_LINK) {
3608*a90b9d01SCy Schubert 		link_id = (p[0] & RSN_MLO_LINK_KDE_LI_LINK_ID_MASK) >>
3609*a90b9d01SCy Schubert 			  RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT;
3610*a90b9d01SCy Schubert 		if (link_id >= MAX_NUM_MLD_LINKS)
3611*a90b9d01SCy Schubert 			return 2;
3612*a90b9d01SCy Schubert 
3613*a90b9d01SCy Schubert 		ie->valid_mlo_links |= BIT(link_id);
3614*a90b9d01SCy Schubert 		ie->mlo_link[link_id] = p;
3615*a90b9d01SCy Schubert 		ie->mlo_link_len[link_id] = left;
3616*a90b9d01SCy Schubert 		ret = os_snprintf(title, sizeof(title),
3617*a90b9d01SCy Schubert 				  "RSN: Link ID %u - MLO Link KDE in EAPOL-Key",
3618*a90b9d01SCy Schubert 				  link_id);
3619*a90b9d01SCy Schubert 		if (!os_snprintf_error(sizeof(title), ret))
3620*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, title, pos, dlen);
3621c1d255d3SCy Schubert 		return 0;
3622c1d255d3SCy Schubert 	}
3623c1d255d3SCy Schubert 
3624c1d255d3SCy Schubert 	return 2;
3625c1d255d3SCy Schubert }
3626c1d255d3SCy Schubert 
3627c1d255d3SCy Schubert 
3628c1d255d3SCy Schubert /**
3629c1d255d3SCy Schubert  * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
3630c1d255d3SCy Schubert  * @buf: Pointer to the Key Data buffer
3631c1d255d3SCy Schubert  * @len: Key Data Length
3632c1d255d3SCy Schubert  * @ie: Pointer to parsed IE data
3633c1d255d3SCy Schubert  * Returns: 0 on success, -1 on failure
3634c1d255d3SCy Schubert  */
wpa_parse_kde_ies(const u8 * buf,size_t len,struct wpa_eapol_ie_parse * ie)3635c1d255d3SCy Schubert int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
3636c1d255d3SCy Schubert {
3637c1d255d3SCy Schubert 	const u8 *pos, *end;
3638c1d255d3SCy Schubert 	int ret = 0;
3639*a90b9d01SCy Schubert 	size_t dlen = 0;
3640c1d255d3SCy Schubert 
3641c1d255d3SCy Schubert 	os_memset(ie, 0, sizeof(*ie));
3642*a90b9d01SCy Schubert 	for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) {
3643c1d255d3SCy Schubert 		if (pos[0] == 0xdd &&
3644c1d255d3SCy Schubert 		    ((pos == buf + len - 1) || pos[1] == 0)) {
3645c1d255d3SCy Schubert 			/* Ignore padding */
3646c1d255d3SCy Schubert 			break;
3647c1d255d3SCy Schubert 		}
3648*a90b9d01SCy Schubert 		dlen = 2 + pos[1];
3649*a90b9d01SCy Schubert 		if ((int) dlen > end - pos) {
3650c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
3651c1d255d3SCy Schubert 				   "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
3652c1d255d3SCy Schubert 				   pos[0], pos[1], (int) (pos - buf));
3653c1d255d3SCy Schubert 			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
3654c1d255d3SCy Schubert 			ret = -1;
3655c1d255d3SCy Schubert 			break;
3656c1d255d3SCy Schubert 		}
3657c1d255d3SCy Schubert 		if (*pos == WLAN_EID_RSN) {
3658c1d255d3SCy Schubert 			ie->rsn_ie = pos;
3659*a90b9d01SCy Schubert 			ie->rsn_ie_len = dlen;
3660c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
3661c1d255d3SCy Schubert 				    ie->rsn_ie, ie->rsn_ie_len);
3662c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_RSNX) {
3663c1d255d3SCy Schubert 			ie->rsnxe = pos;
3664*a90b9d01SCy Schubert 			ie->rsnxe_len = dlen;
3665c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
3666c1d255d3SCy Schubert 				    ie->rsnxe, ie->rsnxe_len);
3667c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
3668c1d255d3SCy Schubert 			ie->mdie = pos;
3669*a90b9d01SCy Schubert 			ie->mdie_len = dlen;
3670c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
3671c1d255d3SCy Schubert 				    ie->mdie, ie->mdie_len);
3672c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
3673c1d255d3SCy Schubert 			ie->ftie = pos;
3674*a90b9d01SCy Schubert 			ie->ftie_len = dlen;
3675c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
3676c1d255d3SCy Schubert 				    ie->ftie, ie->ftie_len);
3677c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
3678c1d255d3SCy Schubert 			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
3679c1d255d3SCy Schubert 				ie->reassoc_deadline = pos;
3680c1d255d3SCy Schubert 				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
3681c1d255d3SCy Schubert 					    "in EAPOL-Key",
3682*a90b9d01SCy Schubert 					    ie->reassoc_deadline, dlen);
3683c1d255d3SCy Schubert 			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
3684c1d255d3SCy Schubert 				ie->key_lifetime = pos;
3685c1d255d3SCy Schubert 				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
3686c1d255d3SCy Schubert 					    "in EAPOL-Key",
3687*a90b9d01SCy Schubert 					    ie->key_lifetime, dlen);
3688c1d255d3SCy Schubert 			} else {
3689c1d255d3SCy Schubert 				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
3690c1d255d3SCy Schubert 					    "EAPOL-Key Key Data IE",
3691*a90b9d01SCy Schubert 					    pos, dlen);
3692c1d255d3SCy Schubert 			}
3693c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_LINK_ID) {
3694c1d255d3SCy Schubert 			if (pos[1] >= 18) {
3695c1d255d3SCy Schubert 				ie->lnkid = pos;
3696*a90b9d01SCy Schubert 				ie->lnkid_len = dlen;
3697c1d255d3SCy Schubert 			}
3698c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_EXT_CAPAB) {
3699c1d255d3SCy Schubert 			ie->ext_capab = pos;
3700*a90b9d01SCy Schubert 			ie->ext_capab_len = dlen;
3701c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_SUPP_RATES) {
3702c1d255d3SCy Schubert 			ie->supp_rates = pos;
3703*a90b9d01SCy Schubert 			ie->supp_rates_len = dlen;
3704c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
3705c1d255d3SCy Schubert 			ie->ext_supp_rates = pos;
3706*a90b9d01SCy Schubert 			ie->ext_supp_rates_len = dlen;
3707c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_HT_CAP &&
3708c1d255d3SCy Schubert 			   pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
3709c1d255d3SCy Schubert 			ie->ht_capabilities = pos + 2;
3710*a90b9d01SCy Schubert 		} else if (*pos == WLAN_EID_AID) {
3711c1d255d3SCy Schubert 			if (pos[1] >= 2)
3712c1d255d3SCy Schubert 				ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
3713c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_VHT_CAP &&
3714c1d255d3SCy Schubert 			   pos[1] >= sizeof(struct ieee80211_vht_capabilities))
3715c1d255d3SCy Schubert 		{
3716c1d255d3SCy Schubert 			ie->vht_capabilities = pos + 2;
3717c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_EXTENSION &&
3718c1d255d3SCy Schubert 			   pos[1] >= 1 + IEEE80211_HE_CAPAB_MIN_LEN &&
3719c1d255d3SCy Schubert 			   pos[2] == WLAN_EID_EXT_HE_CAPABILITIES) {
3720c1d255d3SCy Schubert 			ie->he_capabilities = pos + 3;
3721c1d255d3SCy Schubert 			ie->he_capab_len = pos[1] - 1;
37224b72b91aSCy Schubert 		} else if (*pos == WLAN_EID_EXTENSION &&
37234b72b91aSCy Schubert 			   pos[1] >= 1 +
37244b72b91aSCy Schubert 			   sizeof(struct ieee80211_he_6ghz_band_cap) &&
37254b72b91aSCy Schubert 			   pos[2] == WLAN_EID_EXT_HE_6GHZ_BAND_CAP) {
37264b72b91aSCy Schubert 			ie->he_6ghz_capabilities = pos + 3;
3727*a90b9d01SCy Schubert 		} else if (*pos == WLAN_EID_EXTENSION &&
3728*a90b9d01SCy Schubert 			   pos[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN &&
3729*a90b9d01SCy Schubert 			   pos[2] == WLAN_EID_EXT_EHT_CAPABILITIES) {
3730*a90b9d01SCy Schubert 			ie->eht_capabilities = pos + 3;
3731*a90b9d01SCy Schubert 			ie->eht_capab_len = pos[1] - 1;
3732c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
3733c1d255d3SCy Schubert 			ie->qosinfo = pos[2];
3734c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
3735c1d255d3SCy Schubert 			ie->supp_channels = pos + 2;
3736c1d255d3SCy Schubert 			ie->supp_channels_len = pos[1];
3737c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
3738c1d255d3SCy Schubert 			/*
3739c1d255d3SCy Schubert 			 * The value of the Length field of the Supported
3740c1d255d3SCy Schubert 			 * Operating Classes element is between 2 and 253.
3741c1d255d3SCy Schubert 			 * Silently skip invalid elements to avoid interop
3742c1d255d3SCy Schubert 			 * issues when trying to use the value.
3743c1d255d3SCy Schubert 			 */
3744c1d255d3SCy Schubert 			if (pos[1] >= 2 && pos[1] <= 253) {
3745c1d255d3SCy Schubert 				ie->supp_oper_classes = pos + 2;
3746c1d255d3SCy Schubert 				ie->supp_oper_classes_len = pos[1];
3747c1d255d3SCy Schubert 			}
3748*a90b9d01SCy Schubert 		} else if (*pos == WLAN_EID_SSID) {
3749*a90b9d01SCy Schubert 			ie->ssid = pos + 2;
3750*a90b9d01SCy Schubert 			ie->ssid_len = pos[1];
3751*a90b9d01SCy Schubert 			wpa_hexdump_ascii(MSG_DEBUG, "RSN: SSID in EAPOL-Key",
3752*a90b9d01SCy Schubert 					  ie->ssid, ie->ssid_len);
3753c1d255d3SCy Schubert 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
3754c1d255d3SCy Schubert 			ret = wpa_parse_generic(pos, ie);
3755c1d255d3SCy Schubert 			if (ret == 1) {
3756c1d255d3SCy Schubert 				/* end mark found */
3757c1d255d3SCy Schubert 				ret = 0;
3758c1d255d3SCy Schubert 				break;
3759c1d255d3SCy Schubert 			}
3760c1d255d3SCy Schubert 
3761c1d255d3SCy Schubert 			if (ret == 2) {
3762c1d255d3SCy Schubert 				/* not a known KDE */
3763c1d255d3SCy Schubert 				wpa_parse_vendor_specific(pos, end, ie);
3764c1d255d3SCy Schubert 			}
3765c1d255d3SCy Schubert 
3766c1d255d3SCy Schubert 			ret = 0;
3767c1d255d3SCy Schubert 		} else {
3768c1d255d3SCy Schubert 			wpa_hexdump(MSG_DEBUG,
3769c1d255d3SCy Schubert 				    "WPA: Unrecognized EAPOL-Key Key Data IE",
3770*a90b9d01SCy Schubert 				    pos, dlen);
3771c1d255d3SCy Schubert 		}
3772c1d255d3SCy Schubert 	}
3773c1d255d3SCy Schubert 
3774c1d255d3SCy Schubert 	return ret;
3775c1d255d3SCy Schubert }
3776c1d255d3SCy Schubert 
3777c1d255d3SCy Schubert 
3778c1d255d3SCy Schubert #ifdef CONFIG_PASN
3779c1d255d3SCy Schubert 
3780c1d255d3SCy Schubert /*
3781c1d255d3SCy Schubert  * wpa_pasn_build_auth_header - Add the MAC header and initialize Authentication
3782c1d255d3SCy Schubert  * frame for PASN
3783c1d255d3SCy Schubert  *
3784c1d255d3SCy Schubert  * @buf: Buffer in which the header will be added
3785c1d255d3SCy Schubert  * @bssid: The BSSID of the AP
3786c1d255d3SCy Schubert  * @src: Source address
3787c1d255d3SCy Schubert  * @dst: Destination address
3788c1d255d3SCy Schubert  * @trans_seq: Authentication transaction sequence number
3789c1d255d3SCy Schubert  * @status: Authentication status
3790c1d255d3SCy Schubert  */
wpa_pasn_build_auth_header(struct wpabuf * buf,const u8 * bssid,const u8 * src,const u8 * dst,u8 trans_seq,u16 status)3791c1d255d3SCy Schubert void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
3792c1d255d3SCy Schubert 				const u8 *src, const u8 *dst,
3793c1d255d3SCy Schubert 				u8 trans_seq, u16 status)
3794c1d255d3SCy Schubert {
3795c1d255d3SCy Schubert 	struct ieee80211_mgmt *auth;
3796c1d255d3SCy Schubert 
3797c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Add authentication header. trans_seq=%u",
3798c1d255d3SCy Schubert 		   trans_seq);
3799c1d255d3SCy Schubert 
3800c1d255d3SCy Schubert 	auth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
3801c1d255d3SCy Schubert 					u.auth.variable));
3802c1d255d3SCy Schubert 
3803c1d255d3SCy Schubert 	auth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
3804c1d255d3SCy Schubert 					   (WLAN_FC_STYPE_AUTH << 4));
3805c1d255d3SCy Schubert 
3806c1d255d3SCy Schubert 	os_memcpy(auth->da, dst, ETH_ALEN);
3807c1d255d3SCy Schubert 	os_memcpy(auth->sa, src, ETH_ALEN);
3808c1d255d3SCy Schubert 	os_memcpy(auth->bssid, bssid, ETH_ALEN);
3809c1d255d3SCy Schubert 	auth->seq_ctrl = 0;
3810c1d255d3SCy Schubert 
3811c1d255d3SCy Schubert 	auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_PASN);
3812c1d255d3SCy Schubert 	auth->u.auth.auth_transaction = host_to_le16(trans_seq);
3813c1d255d3SCy Schubert 	auth->u.auth.status_code = host_to_le16(status);
3814c1d255d3SCy Schubert }
3815c1d255d3SCy Schubert 
3816c1d255d3SCy Schubert 
3817c1d255d3SCy Schubert /*
3818c1d255d3SCy Schubert  * wpa_pasn_add_rsne - Add an RSNE for PASN authentication
3819c1d255d3SCy Schubert  * @buf: Buffer in which the IE will be added
3820c1d255d3SCy Schubert  * @pmkid: Optional PMKID. Can be NULL.
3821c1d255d3SCy Schubert  * @akmp: Authentication and key management protocol
3822c1d255d3SCy Schubert  * @cipher: The cipher suite
3823c1d255d3SCy Schubert  */
wpa_pasn_add_rsne(struct wpabuf * buf,const u8 * pmkid,int akmp,int cipher)3824c1d255d3SCy Schubert int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
3825c1d255d3SCy Schubert {
3826c1d255d3SCy Schubert 	struct rsn_ie_hdr *hdr;
3827c1d255d3SCy Schubert 	u32 suite;
3828c1d255d3SCy Schubert 	u16 capab;
3829c1d255d3SCy Schubert 	u8 *pos;
3830c1d255d3SCy Schubert 	u8 rsne_len;
3831c1d255d3SCy Schubert 
3832c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Add RSNE");
3833c1d255d3SCy Schubert 
3834c1d255d3SCy Schubert 	rsne_len = sizeof(*hdr) + RSN_SELECTOR_LEN +
3835c1d255d3SCy Schubert 		2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN +
3836c1d255d3SCy Schubert 		2 + RSN_SELECTOR_LEN + 2 + (pmkid ? PMKID_LEN : 0);
3837c1d255d3SCy Schubert 
3838c1d255d3SCy Schubert 	if (wpabuf_tailroom(buf) < rsne_len)
3839c1d255d3SCy Schubert 		return -1;
3840c1d255d3SCy Schubert 	hdr = wpabuf_put(buf, rsne_len);
3841c1d255d3SCy Schubert 	hdr->elem_id = WLAN_EID_RSN;
3842c1d255d3SCy Schubert 	hdr->len = rsne_len - 2;
3843c1d255d3SCy Schubert 	WPA_PUT_LE16(hdr->version, RSN_VERSION);
3844c1d255d3SCy Schubert 	pos = (u8 *) (hdr + 1);
3845c1d255d3SCy Schubert 
3846c1d255d3SCy Schubert 	/* Group addressed data is not allowed */
3847c1d255d3SCy Schubert 	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
3848c1d255d3SCy Schubert 	pos += RSN_SELECTOR_LEN;
3849c1d255d3SCy Schubert 
3850c1d255d3SCy Schubert 	/* Add the pairwise cipher */
3851c1d255d3SCy Schubert 	WPA_PUT_LE16(pos, 1);
3852c1d255d3SCy Schubert 	pos += 2;
3853c1d255d3SCy Schubert 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, cipher);
3854c1d255d3SCy Schubert 	RSN_SELECTOR_PUT(pos, suite);
3855c1d255d3SCy Schubert 	pos += RSN_SELECTOR_LEN;
3856c1d255d3SCy Schubert 
3857c1d255d3SCy Schubert 	/* Add the AKM suite */
3858c1d255d3SCy Schubert 	WPA_PUT_LE16(pos, 1);
3859c1d255d3SCy Schubert 	pos += 2;
3860c1d255d3SCy Schubert 
3861c1d255d3SCy Schubert 	switch (akmp) {
3862c1d255d3SCy Schubert 	case WPA_KEY_MGMT_PASN:
3863c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
3864c1d255d3SCy Schubert 		break;
3865c1d255d3SCy Schubert #ifdef CONFIG_SAE
3866c1d255d3SCy Schubert 	case WPA_KEY_MGMT_SAE:
3867c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
3868c1d255d3SCy Schubert 		break;
3869*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
3870*a90b9d01SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
3871*a90b9d01SCy Schubert 		break;
3872c1d255d3SCy Schubert #endif /* CONFIG_SAE */
3873c1d255d3SCy Schubert #ifdef CONFIG_FILS
3874c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
3875c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
3876c1d255d3SCy Schubert 		break;
3877c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
3878c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
3879c1d255d3SCy Schubert 		break;
3880c1d255d3SCy Schubert #endif /* CONFIG_FILS */
3881c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211R
3882c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_PSK:
3883c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
3884c1d255d3SCy Schubert 		break;
3885c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X:
3886c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
3887c1d255d3SCy Schubert 		break;
3888c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
3889c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
3890c1d255d3SCy Schubert 		break;
3891c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211R */
3892c1d255d3SCy Schubert 	default:
3893c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: Invalid AKMP=0x%x", akmp);
3894c1d255d3SCy Schubert 		return -1;
3895c1d255d3SCy Schubert 	}
3896c1d255d3SCy Schubert 	pos += RSN_SELECTOR_LEN;
3897c1d255d3SCy Schubert 
3898c1d255d3SCy Schubert 	/* RSN Capabilities: PASN mandates both MFP capable and required */
3899c1d255d3SCy Schubert 	capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
3900c1d255d3SCy Schubert 	WPA_PUT_LE16(pos, capab);
3901c1d255d3SCy Schubert 	pos += 2;
3902c1d255d3SCy Schubert 
3903c1d255d3SCy Schubert 	if (pmkid) {
3904c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Adding PMKID");
3905c1d255d3SCy Schubert 
3906c1d255d3SCy Schubert 		WPA_PUT_LE16(pos, 1);
3907c1d255d3SCy Schubert 		pos += 2;
3908c1d255d3SCy Schubert 		os_memcpy(pos, pmkid, PMKID_LEN);
3909c1d255d3SCy Schubert 		pos += PMKID_LEN;
3910c1d255d3SCy Schubert 	} else {
3911c1d255d3SCy Schubert 		WPA_PUT_LE16(pos, 0);
3912c1d255d3SCy Schubert 		pos += 2;
3913c1d255d3SCy Schubert 	}
3914c1d255d3SCy Schubert 
3915c1d255d3SCy Schubert 	/* Group addressed management is not allowed */
3916c1d255d3SCy Schubert 	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
3917c1d255d3SCy Schubert 
3918c1d255d3SCy Schubert 	return 0;
3919c1d255d3SCy Schubert }
3920c1d255d3SCy Schubert 
3921c1d255d3SCy Schubert 
3922c1d255d3SCy Schubert /*
3923c1d255d3SCy Schubert  * wpa_pasn_add_parameter_ie - Add PASN Parameters IE for PASN authentication
3924c1d255d3SCy Schubert  * @buf: Buffer in which the IE will be added
3925c1d255d3SCy Schubert  * @pasn_group: Finite Cyclic Group ID for PASN authentication
3926c1d255d3SCy Schubert  * @wrapped_data_format: Format of the data in the Wrapped Data IE
3927c1d255d3SCy Schubert  * @pubkey: A buffer holding the local public key. Can be NULL
3928c1d255d3SCy Schubert  * @compressed: In case pubkey is included, indicates if the public key is
3929c1d255d3SCy Schubert  *     compressed (only x coordinate is included) or not (both x and y
3930c1d255d3SCy Schubert  *     coordinates are included)
3931c1d255d3SCy Schubert  * @comeback: A buffer holding the comeback token. Can be NULL
3932c1d255d3SCy Schubert  * @after: If comeback is set, defined the comeback time in seconds. -1 to not
3933c1d255d3SCy Schubert  *	include the Comeback After field (frames from non-AP STA).
3934c1d255d3SCy Schubert  */
wpa_pasn_add_parameter_ie(struct wpabuf * buf,u16 pasn_group,u8 wrapped_data_format,const struct wpabuf * pubkey,bool compressed,const struct wpabuf * comeback,int after)3935c1d255d3SCy Schubert void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
3936c1d255d3SCy Schubert 			       u8 wrapped_data_format,
3937c1d255d3SCy Schubert 			       const struct wpabuf *pubkey, bool compressed,
3938c1d255d3SCy Schubert 			       const struct wpabuf *comeback, int after)
3939c1d255d3SCy Schubert {
3940c1d255d3SCy Schubert 	struct pasn_parameter_ie *params;
3941c1d255d3SCy Schubert 
3942c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Add PASN Parameters element");
3943c1d255d3SCy Schubert 
3944c1d255d3SCy Schubert 	params = wpabuf_put(buf, sizeof(*params));
3945c1d255d3SCy Schubert 
3946c1d255d3SCy Schubert 	params->id = WLAN_EID_EXTENSION;
3947c1d255d3SCy Schubert 	params->len = sizeof(*params) - 2;
3948c1d255d3SCy Schubert 	params->id_ext = WLAN_EID_EXT_PASN_PARAMS;
3949c1d255d3SCy Schubert 	params->control = 0;
3950c1d255d3SCy Schubert 	params->wrapped_data_format = wrapped_data_format;
3951c1d255d3SCy Schubert 
3952c1d255d3SCy Schubert 	if (comeback) {
3953c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Adding comeback data");
3954c1d255d3SCy Schubert 
3955c1d255d3SCy Schubert 		/*
3956c1d255d3SCy Schubert 		 * 2 octets for the 'after' field + 1 octet for the length +
3957c1d255d3SCy Schubert 		 * actual cookie data
3958c1d255d3SCy Schubert 		 */
3959c1d255d3SCy Schubert 		if (after >= 0)
3960c1d255d3SCy Schubert 			params->len += 2;
3961c1d255d3SCy Schubert 		params->len += 1 + wpabuf_len(comeback);
3962c1d255d3SCy Schubert 		params->control |= WPA_PASN_CTRL_COMEBACK_INFO_PRESENT;
3963c1d255d3SCy Schubert 
3964c1d255d3SCy Schubert 		if (after >= 0)
3965c1d255d3SCy Schubert 			wpabuf_put_le16(buf, after);
3966c1d255d3SCy Schubert 		wpabuf_put_u8(buf, wpabuf_len(comeback));
3967c1d255d3SCy Schubert 		wpabuf_put_buf(buf, comeback);
3968c1d255d3SCy Schubert 	}
3969c1d255d3SCy Schubert 
3970c1d255d3SCy Schubert 	if (pubkey) {
3971c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3972c1d255d3SCy Schubert 			   "PASN: Adding public key and group ID %u",
3973c1d255d3SCy Schubert 			   pasn_group);
3974c1d255d3SCy Schubert 
3975c1d255d3SCy Schubert 		/*
3976c1d255d3SCy Schubert 		 * 2 octets for the finite cyclic group + 2 octets public key
3977c1d255d3SCy Schubert 		 * length + 1 octet for the compressed/uncompressed indication +
3978c1d255d3SCy Schubert 		 * the actual key.
3979c1d255d3SCy Schubert 		 */
3980c1d255d3SCy Schubert 		params->len += 2 + 1 + 1 + wpabuf_len(pubkey);
3981c1d255d3SCy Schubert 		params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
3982c1d255d3SCy Schubert 
3983c1d255d3SCy Schubert 		wpabuf_put_le16(buf, pasn_group);
3984c1d255d3SCy Schubert 
3985c1d255d3SCy Schubert 		/*
3986c1d255d3SCy Schubert 		 * The first octet indicates whether the public key is
3987c1d255d3SCy Schubert 		 * compressed, as defined in RFC 5480 section 2.2.
3988c1d255d3SCy Schubert 		 */
3989c1d255d3SCy Schubert 		wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1);
3990c1d255d3SCy Schubert 		wpabuf_put_u8(buf, compressed ? WPA_PASN_PUBKEY_COMPRESSED_0 :
3991c1d255d3SCy Schubert 			      WPA_PASN_PUBKEY_UNCOMPRESSED);
3992c1d255d3SCy Schubert 
3993c1d255d3SCy Schubert 		wpabuf_put_buf(buf, pubkey);
3994c1d255d3SCy Schubert 	}
3995c1d255d3SCy Schubert }
3996c1d255d3SCy Schubert 
3997c1d255d3SCy Schubert /*
3998c1d255d3SCy Schubert  * wpa_pasn_add_wrapped_data - Add a Wrapped Data IE to PASN Authentication
3999c1d255d3SCy Schubert  * frame. If needed, the Wrapped Data IE would be fragmented.
4000c1d255d3SCy Schubert  *
4001c1d255d3SCy Schubert  * @buf: Buffer in which the IE will be added
4002c1d255d3SCy Schubert  * @wrapped_data_buf: Buffer holding the wrapped data
4003c1d255d3SCy Schubert  */
wpa_pasn_add_wrapped_data(struct wpabuf * buf,struct wpabuf * wrapped_data_buf)4004c1d255d3SCy Schubert int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
4005c1d255d3SCy Schubert 			      struct wpabuf *wrapped_data_buf)
4006c1d255d3SCy Schubert {
4007c1d255d3SCy Schubert 	const u8 *data;
4008c1d255d3SCy Schubert 	size_t data_len;
4009c1d255d3SCy Schubert 	u8 len;
4010c1d255d3SCy Schubert 
4011c1d255d3SCy Schubert 	if (!wrapped_data_buf)
4012c1d255d3SCy Schubert 		return 0;
4013c1d255d3SCy Schubert 
4014c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Add wrapped data");
4015c1d255d3SCy Schubert 
4016c1d255d3SCy Schubert 	data = wpabuf_head_u8(wrapped_data_buf);
4017c1d255d3SCy Schubert 	data_len = wpabuf_len(wrapped_data_buf);
4018c1d255d3SCy Schubert 
4019c1d255d3SCy Schubert 	/* nothing to add */
4020c1d255d3SCy Schubert 	if (!data_len)
4021c1d255d3SCy Schubert 		return 0;
4022c1d255d3SCy Schubert 
4023c1d255d3SCy Schubert 	if (data_len <= 254)
4024c1d255d3SCy Schubert 		len = 1 + data_len;
4025c1d255d3SCy Schubert 	else
4026c1d255d3SCy Schubert 		len = 255;
4027c1d255d3SCy Schubert 
4028c1d255d3SCy Schubert 	if (wpabuf_tailroom(buf) < 3 + data_len)
4029c1d255d3SCy Schubert 		return -1;
4030c1d255d3SCy Schubert 
4031c1d255d3SCy Schubert 	wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
4032c1d255d3SCy Schubert 	wpabuf_put_u8(buf, len);
4033c1d255d3SCy Schubert 	wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
4034c1d255d3SCy Schubert 	wpabuf_put_data(buf, data, len - 1);
4035c1d255d3SCy Schubert 
4036c1d255d3SCy Schubert 	data += len - 1;
4037c1d255d3SCy Schubert 	data_len -= len - 1;
4038c1d255d3SCy Schubert 
4039c1d255d3SCy Schubert 	while (data_len) {
4040c1d255d3SCy Schubert 		if (wpabuf_tailroom(buf) < 1 + data_len)
4041c1d255d3SCy Schubert 			return -1;
4042c1d255d3SCy Schubert 		wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
4043c1d255d3SCy Schubert 		len = data_len > 255 ? 255 : data_len;
4044c1d255d3SCy Schubert 		wpabuf_put_u8(buf, len);
4045c1d255d3SCy Schubert 		wpabuf_put_data(buf, data, len);
4046c1d255d3SCy Schubert 		data += len;
4047c1d255d3SCy Schubert 		data_len -= len;
4048c1d255d3SCy Schubert 	}
4049c1d255d3SCy Schubert 
4050c1d255d3SCy Schubert 	return 0;
4051c1d255d3SCy Schubert }
4052c1d255d3SCy Schubert 
4053c1d255d3SCy Schubert 
4054c1d255d3SCy Schubert /*
4055c1d255d3SCy Schubert  * wpa_pasn_validate_rsne - Validate PSAN specific data of RSNE
4056c1d255d3SCy Schubert  * @data: Parsed representation of an RSNE
4057c1d255d3SCy Schubert  * Returns -1 for invalid data; otherwise 0
4058c1d255d3SCy Schubert  */
wpa_pasn_validate_rsne(const struct wpa_ie_data * data)4059c1d255d3SCy Schubert int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
4060c1d255d3SCy Schubert {
4061c1d255d3SCy Schubert 	u16 capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
4062c1d255d3SCy Schubert 
4063c1d255d3SCy Schubert 	if (data->proto != WPA_PROTO_RSN)
4064c1d255d3SCy Schubert 		return -1;
4065c1d255d3SCy Schubert 
4066c1d255d3SCy Schubert 	if ((data->capabilities & capab) != capab) {
4067c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid RSNE capabilities");
4068c1d255d3SCy Schubert 		return -1;
4069c1d255d3SCy Schubert 	}
4070c1d255d3SCy Schubert 
4071c1d255d3SCy Schubert 	if (!data->has_group || data->group_cipher != WPA_CIPHER_GTK_NOT_USED) {
4072c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher");
4073c1d255d3SCy Schubert 		return -1;
4074c1d255d3SCy Schubert 	}
4075c1d255d3SCy Schubert 
4076c1d255d3SCy Schubert 	if (!data->has_pairwise || !data->pairwise_cipher ||
4077c1d255d3SCy Schubert 	    (data->pairwise_cipher & (data->pairwise_cipher - 1))) {
4078c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: No valid pairwise suite");
4079c1d255d3SCy Schubert 		return -1;
4080c1d255d3SCy Schubert 	}
4081c1d255d3SCy Schubert 
4082c1d255d3SCy Schubert 	switch (data->key_mgmt) {
4083c1d255d3SCy Schubert #ifdef CONFIG_SAE
4084c1d255d3SCy Schubert 	case WPA_KEY_MGMT_SAE:
4085*a90b9d01SCy Schubert 	case WPA_KEY_MGMT_SAE_EXT_KEY:
4086c1d255d3SCy Schubert 	/* fall through */
4087c1d255d3SCy Schubert #endif /* CONFIG_SAE */
4088c1d255d3SCy Schubert #ifdef CONFIG_FILS
4089c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA256:
4090c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FILS_SHA384:
4091c1d255d3SCy Schubert 	/* fall through */
4092c1d255d3SCy Schubert #endif /* CONFIG_FILS */
4093c1d255d3SCy Schubert #ifdef CONFIG_IEEE80211R
4094c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_PSK:
4095c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X:
4096c1d255d3SCy Schubert 	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
4097c1d255d3SCy Schubert 	/* fall through */
4098c1d255d3SCy Schubert #endif /* CONFIG_IEEE80211R */
4099c1d255d3SCy Schubert 	case WPA_KEY_MGMT_PASN:
4100c1d255d3SCy Schubert 		break;
4101c1d255d3SCy Schubert 	default:
4102c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "PASN: invalid key_mgmt: 0x%0x",
4103c1d255d3SCy Schubert 			   data->key_mgmt);
4104c1d255d3SCy Schubert 		return -1;
4105c1d255d3SCy Schubert 	}
4106c1d255d3SCy Schubert 
4107c1d255d3SCy Schubert 	if (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED) {
4108c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher");
4109c1d255d3SCy Schubert 		return -1;
4110c1d255d3SCy Schubert 	}
4111c1d255d3SCy Schubert 
4112c1d255d3SCy Schubert 	if (data->num_pmkid > 1) {
4113c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid number of PMKIDs");
4114c1d255d3SCy Schubert 		return -1;
4115c1d255d3SCy Schubert 	}
4116c1d255d3SCy Schubert 
4117c1d255d3SCy Schubert 	return 0;
4118c1d255d3SCy Schubert }
4119c1d255d3SCy Schubert 
4120c1d255d3SCy Schubert 
4121c1d255d3SCy Schubert /*
4122c1d255d3SCy Schubert  * wpa_pasn_parse_parameter_ie - Validates PASN Parameters IE
4123c1d255d3SCy Schubert  * @data: Pointer to the PASN Parameters IE (starting with the EID).
4124c1d255d3SCy Schubert  * @len: Length of the data in the PASN Parameters IE
4125c1d255d3SCy Schubert  * @from_ap: Whether this was received from an AP
4126c1d255d3SCy Schubert  * @pasn_params: On successful return would hold the parsed PASN parameters.
4127c1d255d3SCy Schubert  * Returns: -1 for invalid data; otherwise 0
4128c1d255d3SCy Schubert  *
4129c1d255d3SCy Schubert  * Note: On successful return, the pointers in &pasn_params point to the data in
4130c1d255d3SCy Schubert  * the IE and are not locally allocated (so they should not be freed etc.).
4131c1d255d3SCy Schubert  */
wpa_pasn_parse_parameter_ie(const u8 * data,u8 len,bool from_ap,struct wpa_pasn_params_data * pasn_params)4132c1d255d3SCy Schubert int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
4133c1d255d3SCy Schubert 				struct wpa_pasn_params_data *pasn_params)
4134c1d255d3SCy Schubert {
4135c1d255d3SCy Schubert 	struct pasn_parameter_ie *params = (struct pasn_parameter_ie *) data;
4136c1d255d3SCy Schubert 	const u8 *pos = (const u8 *) (params + 1);
4137c1d255d3SCy Schubert 
4138c1d255d3SCy Schubert 	if (!pasn_params) {
4139c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid params");
4140c1d255d3SCy Schubert 		return -1;
4141c1d255d3SCy Schubert 	}
4142c1d255d3SCy Schubert 
4143c1d255d3SCy Schubert 	if (!params || ((size_t) (params->len + 2) < sizeof(*params)) ||
4144c1d255d3SCy Schubert 	    len < sizeof(*params) || params->len + 2 != len) {
4145c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
4146c1d255d3SCy Schubert 			   "PASN: Invalid parameters IE. len=(%u, %u)",
4147c1d255d3SCy Schubert 			   params ? params->len : 0, len);
4148c1d255d3SCy Schubert 		return -1;
4149c1d255d3SCy Schubert 	}
4150c1d255d3SCy Schubert 
4151c1d255d3SCy Schubert 	os_memset(pasn_params, 0, sizeof(*pasn_params));
4152c1d255d3SCy Schubert 
4153c1d255d3SCy Schubert 	switch (params->wrapped_data_format) {
4154c1d255d3SCy Schubert 	case WPA_PASN_WRAPPED_DATA_NO:
4155c1d255d3SCy Schubert 	case WPA_PASN_WRAPPED_DATA_SAE:
4156c1d255d3SCy Schubert 	case WPA_PASN_WRAPPED_DATA_FILS_SK:
4157c1d255d3SCy Schubert 	case WPA_PASN_WRAPPED_DATA_FT:
4158c1d255d3SCy Schubert 		break;
4159c1d255d3SCy Schubert 	default:
4160c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Invalid wrapped data format");
4161c1d255d3SCy Schubert 		return -1;
4162c1d255d3SCy Schubert 	}
4163c1d255d3SCy Schubert 
4164c1d255d3SCy Schubert 	pasn_params->wrapped_data_format = params->wrapped_data_format;
4165c1d255d3SCy Schubert 
4166c1d255d3SCy Schubert 	len -= sizeof(*params);
4167c1d255d3SCy Schubert 
4168c1d255d3SCy Schubert 	if (params->control & WPA_PASN_CTRL_COMEBACK_INFO_PRESENT) {
4169c1d255d3SCy Schubert 		if (from_ap) {
4170c1d255d3SCy Schubert 			if (len < 2) {
4171c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
4172c1d255d3SCy Schubert 					   "PASN: Invalid Parameters IE: Truncated Comeback After");
4173c1d255d3SCy Schubert 				return -1;
4174c1d255d3SCy Schubert 			}
4175c1d255d3SCy Schubert 			pasn_params->after = WPA_GET_LE16(pos);
4176c1d255d3SCy Schubert 			pos += 2;
4177c1d255d3SCy Schubert 			len -= 2;
4178c1d255d3SCy Schubert 		}
4179c1d255d3SCy Schubert 
4180c1d255d3SCy Schubert 		if (len < 1 || len < 1 + *pos) {
4181c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
4182c1d255d3SCy Schubert 				   "PASN: Invalid Parameters IE: comeback len");
4183c1d255d3SCy Schubert 			return -1;
4184c1d255d3SCy Schubert 		}
4185c1d255d3SCy Schubert 
4186c1d255d3SCy Schubert 		pasn_params->comeback_len = *pos++;
4187c1d255d3SCy Schubert 		len--;
4188c1d255d3SCy Schubert 		pasn_params->comeback = pos;
4189c1d255d3SCy Schubert 		len -=  pasn_params->comeback_len;
4190c1d255d3SCy Schubert 		pos += pasn_params->comeback_len;
4191c1d255d3SCy Schubert 	}
4192c1d255d3SCy Schubert 
4193c1d255d3SCy Schubert 	if (params->control & WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT) {
4194c1d255d3SCy Schubert 		if (len < 3 || len < 3 + pos[2]) {
4195c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
4196c1d255d3SCy Schubert 				   "PASN: Invalid Parameters IE: group and key");
4197c1d255d3SCy Schubert 			return -1;
4198c1d255d3SCy Schubert 		}
4199c1d255d3SCy Schubert 
4200c1d255d3SCy Schubert 		pasn_params->group = WPA_GET_LE16(pos);
4201c1d255d3SCy Schubert 		pos += 2;
4202c1d255d3SCy Schubert 		len -= 2;
4203c1d255d3SCy Schubert 		pasn_params->pubkey_len = *pos++;
4204c1d255d3SCy Schubert 		len--;
4205c1d255d3SCy Schubert 		pasn_params->pubkey = pos;
4206c1d255d3SCy Schubert 		len -= pasn_params->pubkey_len;
4207c1d255d3SCy Schubert 		pos += pasn_params->pubkey_len;
4208c1d255d3SCy Schubert 	}
4209c1d255d3SCy Schubert 
4210c1d255d3SCy Schubert 	if (len) {
4211c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
4212c1d255d3SCy Schubert 			   "PASN: Invalid Parameters IE. Bytes left=%u", len);
4213c1d255d3SCy Schubert 		return -1;
4214c1d255d3SCy Schubert 	}
4215c1d255d3SCy Schubert 
4216c1d255d3SCy Schubert 	return 0;
4217c1d255d3SCy Schubert }
4218c1d255d3SCy Schubert 
4219c1d255d3SCy Schubert 
wpa_pasn_add_rsnxe(struct wpabuf * buf,u16 capab)4220c1d255d3SCy Schubert void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab)
4221c1d255d3SCy Schubert {
4222c1d255d3SCy Schubert 	size_t flen;
4223c1d255d3SCy Schubert 
4224c1d255d3SCy Schubert 	flen = (capab & 0xff00) ? 2 : 1;
4225c1d255d3SCy Schubert 	if (!capab)
4226c1d255d3SCy Schubert 		return; /* no supported extended RSN capabilities */
4227c1d255d3SCy Schubert 	if (wpabuf_tailroom(buf) < 2 + flen)
4228c1d255d3SCy Schubert 		return;
4229c1d255d3SCy Schubert 	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
4230c1d255d3SCy Schubert 
4231c1d255d3SCy Schubert 	wpabuf_put_u8(buf, WLAN_EID_RSNX);
4232c1d255d3SCy Schubert 	wpabuf_put_u8(buf, flen);
4233c1d255d3SCy Schubert 	wpabuf_put_u8(buf, capab & 0x00ff);
4234c1d255d3SCy Schubert 	capab >>= 8;
4235c1d255d3SCy Schubert 	if (capab)
4236c1d255d3SCy Schubert 		wpabuf_put_u8(buf, capab);
4237c1d255d3SCy Schubert }
4238c1d255d3SCy Schubert 
4239*a90b9d01SCy Schubert 
4240*a90b9d01SCy Schubert /*
4241*a90b9d01SCy Schubert  * wpa_pasn_add_extra_ies - Add protocol specific IEs in Authentication
4242*a90b9d01SCy Schubert  * frame for PASN.
4243*a90b9d01SCy Schubert  *
4244*a90b9d01SCy Schubert  * @buf: Buffer in which the elements will be added
4245*a90b9d01SCy Schubert  * @extra_ies: Protocol specific elements to add
4246*a90b9d01SCy Schubert  * @len: Length of the elements
4247*a90b9d01SCy Schubert  * Returns: 0 on success, -1 on failure
4248*a90b9d01SCy Schubert  */
4249*a90b9d01SCy Schubert 
wpa_pasn_add_extra_ies(struct wpabuf * buf,const u8 * extra_ies,size_t len)4250*a90b9d01SCy Schubert int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len)
4251*a90b9d01SCy Schubert {
4252*a90b9d01SCy Schubert 	if (!len || !extra_ies || !buf)
4253*a90b9d01SCy Schubert 		return 0;
4254*a90b9d01SCy Schubert 
4255*a90b9d01SCy Schubert 	if (wpabuf_tailroom(buf) < sizeof(len))
4256*a90b9d01SCy Schubert 		return -1;
4257*a90b9d01SCy Schubert 
4258*a90b9d01SCy Schubert 	wpabuf_put_data(buf, extra_ies, len);
4259*a90b9d01SCy Schubert 	return 0;
4260*a90b9d01SCy Schubert }
4261*a90b9d01SCy Schubert 
4262c1d255d3SCy Schubert #endif /* CONFIG_PASN */
4263