1189251Ssam/*
2189251Ssam * WPA/RSN - Shared functions for supplicant and authenticator
3346981Scy * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/md5.h"
13214734Srpaulo#include "crypto/sha1.h"
14214734Srpaulo#include "crypto/sha256.h"
15281806Srpaulo#include "crypto/sha384.h"
16346981Scy#include "crypto/sha512.h"
17214734Srpaulo#include "crypto/aes_wrap.h"
18214734Srpaulo#include "crypto/crypto.h"
19189251Ssam#include "ieee802_11_defs.h"
20189251Ssam#include "defs.h"
21189251Ssam#include "wpa_common.h"
22189251Ssam
23189251Ssam
24346981Scystatic unsigned int wpa_kck_len(int akmp, size_t pmk_len)
25281806Srpaulo{
26346981Scy	switch (akmp) {
27346981Scy	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
28346981Scy	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
29281806Srpaulo		return 24;
30346981Scy	case WPA_KEY_MGMT_FILS_SHA256:
31346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
32346981Scy	case WPA_KEY_MGMT_FILS_SHA384:
33346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
34346981Scy		return 0;
35346981Scy	case WPA_KEY_MGMT_DPP:
36346981Scy		return pmk_len / 2;
37346981Scy	case WPA_KEY_MGMT_OWE:
38346981Scy		return pmk_len / 2;
39346981Scy	default:
40346981Scy		return 16;
41346981Scy	}
42281806Srpaulo}
43281806Srpaulo
44281806Srpaulo
45346981Scy#ifdef CONFIG_IEEE80211R
46346981Scystatic unsigned int wpa_kck2_len(int akmp)
47281806Srpaulo{
48346981Scy	switch (akmp) {
49346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
50346981Scy		return 16;
51346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
52346981Scy		return 24;
53346981Scy	default:
54346981Scy		return 0;
55346981Scy	}
56346981Scy}
57346981Scy#endif /* CONFIG_IEEE80211R */
58346981Scy
59346981Scy
60346981Scystatic unsigned int wpa_kek_len(int akmp, size_t pmk_len)
61346981Scy{
62346981Scy	switch (akmp) {
63346981Scy	case WPA_KEY_MGMT_FILS_SHA384:
64346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
65346981Scy		return 64;
66346981Scy	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
67346981Scy	case WPA_KEY_MGMT_FILS_SHA256:
68346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
69346981Scy	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
70281806Srpaulo		return 32;
71346981Scy	case WPA_KEY_MGMT_DPP:
72346981Scy		return pmk_len <= 32 ? 16 : 32;
73346981Scy	case WPA_KEY_MGMT_OWE:
74346981Scy		return pmk_len <= 32 ? 16 : 32;
75346981Scy	default:
76346981Scy		return 16;
77346981Scy	}
78281806Srpaulo}
79281806Srpaulo
80281806Srpaulo
81346981Scy#ifdef CONFIG_IEEE80211R
82346981Scystatic unsigned int wpa_kek2_len(int akmp)
83281806Srpaulo{
84346981Scy	switch (akmp) {
85346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
86346981Scy		return 16;
87346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
88346981Scy		return 32;
89346981Scy	default:
90346981Scy		return 0;
91346981Scy	}
92346981Scy}
93346981Scy#endif /* CONFIG_IEEE80211R */
94346981Scy
95346981Scy
96346981Scyunsigned int wpa_mic_len(int akmp, size_t pmk_len)
97346981Scy{
98346981Scy	switch (akmp) {
99346981Scy	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
100346981Scy	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
101281806Srpaulo		return 24;
102346981Scy	case WPA_KEY_MGMT_FILS_SHA256:
103346981Scy	case WPA_KEY_MGMT_FILS_SHA384:
104346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
105346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
106346981Scy		return 0;
107346981Scy	case WPA_KEY_MGMT_DPP:
108346981Scy		return pmk_len / 2;
109346981Scy	case WPA_KEY_MGMT_OWE:
110346981Scy		return pmk_len / 2;
111346981Scy	default:
112346981Scy		return 16;
113346981Scy	}
114281806Srpaulo}
115281806Srpaulo
116281806Srpaulo
117189251Ssam/**
118346981Scy * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
119346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation
120346981Scy * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
121346981Scy */
122346981Scyint wpa_use_akm_defined(int akmp)
123346981Scy{
124346981Scy	return akmp == WPA_KEY_MGMT_OSEN ||
125346981Scy		akmp == WPA_KEY_MGMT_OWE ||
126346981Scy		akmp == WPA_KEY_MGMT_DPP ||
127346981Scy		akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
128346981Scy		wpa_key_mgmt_sae(akmp) ||
129346981Scy		wpa_key_mgmt_suite_b(akmp) ||
130346981Scy		wpa_key_mgmt_fils(akmp);
131346981Scy}
132346981Scy
133346981Scy
134346981Scy/**
135346981Scy * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
136346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation
137346981Scy * Returns: 1 if CMAC is used; 0 otherwise
138346981Scy */
139346981Scyint wpa_use_cmac(int akmp)
140346981Scy{
141346981Scy	return akmp == WPA_KEY_MGMT_OSEN ||
142346981Scy		akmp == WPA_KEY_MGMT_OWE ||
143346981Scy		akmp == WPA_KEY_MGMT_DPP ||
144346981Scy		wpa_key_mgmt_ft(akmp) ||
145346981Scy		wpa_key_mgmt_sha256(akmp) ||
146346981Scy		wpa_key_mgmt_sae(akmp) ||
147346981Scy		wpa_key_mgmt_suite_b(akmp);
148346981Scy}
149346981Scy
150346981Scy
151346981Scy/**
152346981Scy * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
153346981Scy * @akmp: WPA_KEY_MGMT_* used in key derivation
154346981Scy * Returns: 1 if AES Keywrap is used; 0 otherwise
155346981Scy *
156346981Scy * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
157346981Scy * to use AES Keywrap based on the negotiated pairwise cipher. This function
158346981Scy * does not cover those special cases.
159346981Scy */
160346981Scyint wpa_use_aes_key_wrap(int akmp)
161346981Scy{
162346981Scy	return akmp == WPA_KEY_MGMT_OSEN ||
163346981Scy		akmp == WPA_KEY_MGMT_OWE ||
164346981Scy		akmp == WPA_KEY_MGMT_DPP ||
165346981Scy		wpa_key_mgmt_ft(akmp) ||
166346981Scy		wpa_key_mgmt_sha256(akmp) ||
167346981Scy		wpa_key_mgmt_sae(akmp) ||
168346981Scy		wpa_key_mgmt_suite_b(akmp);
169346981Scy}
170346981Scy
171346981Scy
172346981Scy/**
173189251Ssam * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
174189251Ssam * @key: EAPOL-Key Key Confirmation Key (KCK)
175281806Srpaulo * @key_len: KCK length in octets
176281806Srpaulo * @akmp: WPA_KEY_MGMT_* used in key derivation
177189251Ssam * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
178189251Ssam * @buf: Pointer to the beginning of the EAPOL header (version field)
179189251Ssam * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
180189251Ssam * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
181189251Ssam * Returns: 0 on success, -1 on failure
182189251Ssam *
183189251Ssam * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
184189251Ssam * to be cleared (all zeroes) when calling this function.
185189251Ssam *
186189251Ssam * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
187189251Ssam * description of the Key MIC calculation. It includes packet data from the
188189251Ssam * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
189189251Ssam * happened during final editing of the standard and the correct behavior is
190189251Ssam * defined in the last draft (IEEE 802.11i/D10).
191189251Ssam */
192281806Srpauloint wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
193281806Srpaulo		      const u8 *buf, size_t len, u8 *mic)
194189251Ssam{
195346981Scy	u8 hash[SHA512_MAC_LEN];
196189251Ssam
197346981Scy	if (key_len == 0) {
198346981Scy		wpa_printf(MSG_DEBUG,
199346981Scy			   "WPA: KCK not set - cannot calculate MIC");
200346981Scy		return -1;
201346981Scy	}
202346981Scy
203189251Ssam	switch (ver) {
204252726Srpaulo#ifndef CONFIG_FIPS
205189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
206346981Scy		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5");
207281806Srpaulo		return hmac_md5(key, key_len, buf, len, mic);
208252726Srpaulo#endif /* CONFIG_FIPS */
209189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
210346981Scy		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1");
211281806Srpaulo		if (hmac_sha1(key, key_len, buf, len, hash))
212214734Srpaulo			return -1;
213189251Ssam		os_memcpy(mic, hash, MD5_MAC_LEN);
214189251Ssam		break;
215209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
216189251Ssam	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
217346981Scy		wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
218189251Ssam		return omac1_aes_128(key, buf, len, mic);
219209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
220281806Srpaulo	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
221281806Srpaulo		switch (akmp) {
222346981Scy#ifdef CONFIG_SAE
223346981Scy		case WPA_KEY_MGMT_SAE:
224346981Scy		case WPA_KEY_MGMT_FT_SAE:
225346981Scy			wpa_printf(MSG_DEBUG,
226346981Scy				   "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
227346981Scy			return omac1_aes_128(key, buf, len, mic);
228346981Scy#endif /* CONFIG_SAE */
229281806Srpaulo#ifdef CONFIG_HS20
230281806Srpaulo		case WPA_KEY_MGMT_OSEN:
231346981Scy			wpa_printf(MSG_DEBUG,
232346981Scy				   "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)");
233281806Srpaulo			return omac1_aes_128(key, buf, len, mic);
234281806Srpaulo#endif /* CONFIG_HS20 */
235281806Srpaulo#ifdef CONFIG_SUITEB
236281806Srpaulo		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
237346981Scy			wpa_printf(MSG_DEBUG,
238346981Scy				   "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)");
239281806Srpaulo			if (hmac_sha256(key, key_len, buf, len, hash))
240281806Srpaulo				return -1;
241281806Srpaulo			os_memcpy(mic, hash, MD5_MAC_LEN);
242281806Srpaulo			break;
243281806Srpaulo#endif /* CONFIG_SUITEB */
244281806Srpaulo#ifdef CONFIG_SUITEB192
245281806Srpaulo		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
246346981Scy			wpa_printf(MSG_DEBUG,
247346981Scy				   "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)");
248281806Srpaulo			if (hmac_sha384(key, key_len, buf, len, hash))
249281806Srpaulo				return -1;
250281806Srpaulo			os_memcpy(mic, hash, 24);
251281806Srpaulo			break;
252281806Srpaulo#endif /* CONFIG_SUITEB192 */
253346981Scy#ifdef CONFIG_OWE
254346981Scy		case WPA_KEY_MGMT_OWE:
255346981Scy			wpa_printf(MSG_DEBUG,
256346981Scy				   "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)",
257346981Scy				   (unsigned int) key_len * 8 * 2);
258346981Scy			if (key_len == 128 / 8) {
259346981Scy				if (hmac_sha256(key, key_len, buf, len, hash))
260346981Scy					return -1;
261346981Scy			} else if (key_len == 192 / 8) {
262346981Scy				if (hmac_sha384(key, key_len, buf, len, hash))
263346981Scy					return -1;
264346981Scy			} else if (key_len == 256 / 8) {
265346981Scy				if (hmac_sha512(key, key_len, buf, len, hash))
266346981Scy					return -1;
267346981Scy			} else {
268346981Scy				wpa_printf(MSG_INFO,
269346981Scy					   "OWE: Unsupported KCK length: %u",
270346981Scy					   (unsigned int) key_len);
271346981Scy				return -1;
272346981Scy			}
273346981Scy			os_memcpy(mic, hash, key_len);
274346981Scy			break;
275346981Scy#endif /* CONFIG_OWE */
276346981Scy#ifdef CONFIG_DPP
277346981Scy		case WPA_KEY_MGMT_DPP:
278346981Scy			wpa_printf(MSG_DEBUG,
279346981Scy				   "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - DPP)",
280346981Scy				   (unsigned int) key_len * 8 * 2);
281346981Scy			if (key_len == 128 / 8) {
282346981Scy				if (hmac_sha256(key, key_len, buf, len, hash))
283346981Scy					return -1;
284346981Scy			} else if (key_len == 192 / 8) {
285346981Scy				if (hmac_sha384(key, key_len, buf, len, hash))
286346981Scy					return -1;
287346981Scy			} else if (key_len == 256 / 8) {
288346981Scy				if (hmac_sha512(key, key_len, buf, len, hash))
289346981Scy					return -1;
290346981Scy			} else {
291346981Scy				wpa_printf(MSG_INFO,
292346981Scy					   "DPP: Unsupported KCK length: %u",
293346981Scy					   (unsigned int) key_len);
294346981Scy				return -1;
295346981Scy			}
296346981Scy			os_memcpy(mic, hash, key_len);
297346981Scy			break;
298346981Scy#endif /* CONFIG_DPP */
299346981Scy#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384)
300346981Scy		case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
301346981Scy			wpa_printf(MSG_DEBUG,
302346981Scy				   "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)");
303346981Scy			if (hmac_sha384(key, key_len, buf, len, hash))
304346981Scy				return -1;
305346981Scy			os_memcpy(mic, hash, 24);
306346981Scy			break;
307346981Scy#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */
308281806Srpaulo		default:
309346981Scy			wpa_printf(MSG_DEBUG,
310346981Scy				   "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
311346981Scy				   akmp);
312281806Srpaulo			return -1;
313281806Srpaulo		}
314281806Srpaulo		break;
315189251Ssam	default:
316346981Scy		wpa_printf(MSG_DEBUG,
317346981Scy			   "WPA: EAPOL-Key MIC algorithm not known (ver=%d)",
318346981Scy			   ver);
319189251Ssam		return -1;
320189251Ssam	}
321189251Ssam
322189251Ssam	return 0;
323189251Ssam}
324189251Ssam
325189251Ssam
326189251Ssam/**
327189251Ssam * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
328189251Ssam * @pmk: Pairwise master key
329189251Ssam * @pmk_len: Length of PMK
330189251Ssam * @label: Label to use in derivation
331189251Ssam * @addr1: AA or SA
332189251Ssam * @addr2: SA or AA
333189251Ssam * @nonce1: ANonce or SNonce
334189251Ssam * @nonce2: SNonce or ANonce
335189251Ssam * @ptk: Buffer for pairwise transient key
336281806Srpaulo * @akmp: Negotiated AKM
337281806Srpaulo * @cipher: Negotiated pairwise cipher
338281806Srpaulo * Returns: 0 on success, -1 on failure
339189251Ssam *
340189251Ssam * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
341189251Ssam * PTK = PRF-X(PMK, "Pairwise key expansion",
342189251Ssam *             Min(AA, SA) || Max(AA, SA) ||
343346981Scy *             Min(ANonce, SNonce) || Max(ANonce, SNonce)
344346981Scy *             [ || Z.x ])
345189251Ssam *
346346981Scy * The optional Z.x component is used only with DPP and that part is not defined
347346981Scy * in IEEE 802.11.
348189251Ssam */
349281806Srpauloint wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
350281806Srpaulo		   const u8 *addr1, const u8 *addr2,
351281806Srpaulo		   const u8 *nonce1, const u8 *nonce2,
352346981Scy		   struct wpa_ptk *ptk, int akmp, int cipher,
353346981Scy		   const u8 *z, size_t z_len)
354189251Ssam{
355346981Scy#define MAX_Z_LEN 66 /* with NIST P-521 */
356346981Scy	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
357346981Scy	size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
358281806Srpaulo	u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
359281806Srpaulo	size_t ptk_len;
360189251Ssam
361346981Scy	if (pmk_len == 0) {
362346981Scy		wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
363346981Scy		return -1;
364346981Scy	}
365346981Scy
366346981Scy	if (z_len > MAX_Z_LEN)
367346981Scy		return -1;
368346981Scy
369189251Ssam	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
370189251Ssam		os_memcpy(data, addr1, ETH_ALEN);
371189251Ssam		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
372189251Ssam	} else {
373189251Ssam		os_memcpy(data, addr2, ETH_ALEN);
374189251Ssam		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
375189251Ssam	}
376189251Ssam
377189251Ssam	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
378189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
379189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
380189251Ssam			  WPA_NONCE_LEN);
381189251Ssam	} else {
382189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
383189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
384189251Ssam			  WPA_NONCE_LEN);
385189251Ssam	}
386189251Ssam
387346981Scy	if (z && z_len) {
388346981Scy		os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
389346981Scy		data_len += z_len;
390346981Scy	}
391346981Scy
392346981Scy	ptk->kck_len = wpa_kck_len(akmp, pmk_len);
393346981Scy	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
394281806Srpaulo	ptk->tk_len = wpa_cipher_key_len(cipher);
395346981Scy	if (ptk->tk_len == 0) {
396346981Scy		wpa_printf(MSG_ERROR,
397346981Scy			   "WPA: Unsupported cipher (0x%x) used in PTK derivation",
398346981Scy			   cipher);
399346981Scy		return -1;
400346981Scy	}
401281806Srpaulo	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
402281806Srpaulo
403346981Scy	if (wpa_key_mgmt_sha384(akmp)) {
404346981Scy#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
405346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
406346981Scy		if (sha384_prf(pmk, pmk_len, label, data, data_len,
407346981Scy			       tmp, ptk_len) < 0)
408346981Scy			return -1;
409346981Scy#else /* CONFIG_SUITEB192 || CONFIG_FILS */
410346981Scy		return -1;
411346981Scy#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
412346981Scy	} else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
413346981Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_SAE) || defined(CONFIG_FILS)
414346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
415346981Scy		if (sha256_prf(pmk, pmk_len, label, data, data_len,
416346981Scy			       tmp, ptk_len) < 0)
417346981Scy			return -1;
418346981Scy#else /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
419346981Scy		return -1;
420346981Scy#endif /* CONFIG_IEEE80211W or CONFIG_SAE or CONFIG_FILS */
421346981Scy#ifdef CONFIG_DPP
422346981Scy	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
423346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
424346981Scy		if (sha256_prf(pmk, pmk_len, label, data, data_len,
425346981Scy			       tmp, ptk_len) < 0)
426346981Scy			return -1;
427346981Scy	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
428346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
429346981Scy		if (sha384_prf(pmk, pmk_len, label, data, data_len,
430346981Scy			       tmp, ptk_len) < 0)
431346981Scy			return -1;
432346981Scy	} else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
433346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
434346981Scy		if (sha512_prf(pmk, pmk_len, label, data, data_len,
435346981Scy			       tmp, ptk_len) < 0)
436346981Scy			return -1;
437346981Scy	} else if (akmp == WPA_KEY_MGMT_DPP) {
438346981Scy		wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u",
439346981Scy			   (unsigned int) pmk_len);
440346981Scy		return -1;
441346981Scy#endif /* CONFIG_DPP */
442346981Scy	} else {
443346981Scy		wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
444346981Scy		if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
445346981Scy			     ptk_len) < 0)
446346981Scy			return -1;
447346981Scy	}
448189251Ssam
449189251Ssam	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
450189251Ssam		   MAC2STR(addr1), MAC2STR(addr2));
451252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
452252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
453346981Scy	if (z && z_len)
454346981Scy		wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
455189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
456281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
457281806Srpaulo
458281806Srpaulo	os_memcpy(ptk->kck, tmp, ptk->kck_len);
459281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
460281806Srpaulo
461281806Srpaulo	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
462281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
463281806Srpaulo
464281806Srpaulo	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
465281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
466281806Srpaulo
467346981Scy	ptk->kek2_len = 0;
468346981Scy	ptk->kck2_len = 0;
469346981Scy
470281806Srpaulo	os_memset(tmp, 0, sizeof(tmp));
471346981Scy	os_memset(data, 0, data_len);
472281806Srpaulo	return 0;
473189251Ssam}
474189251Ssam
475346981Scy#ifdef CONFIG_FILS
476189251Ssam
477346981Scyint fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
478346981Scy		     const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
479346981Scy		     size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
480346981Scy{
481346981Scy	u8 nonces[2 * FILS_NONCE_LEN];
482346981Scy	const u8 *addr[2];
483346981Scy	size_t len[2];
484346981Scy	size_t num_elem;
485346981Scy	int res;
486346981Scy
487346981Scy	/* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
488346981Scy	wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
489346981Scy
490346981Scy	if (wpa_key_mgmt_sha384(akmp))
491346981Scy		*pmk_len = SHA384_MAC_LEN;
492346981Scy	else if (wpa_key_mgmt_sha256(akmp))
493346981Scy		*pmk_len = SHA256_MAC_LEN;
494346981Scy	else
495346981Scy		return -1;
496346981Scy
497346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
498346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
499346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
500346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
501346981Scy
502346981Scy	os_memcpy(nonces, snonce, FILS_NONCE_LEN);
503346981Scy	os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
504346981Scy	addr[0] = rmsk;
505346981Scy	len[0] = rmsk_len;
506346981Scy	num_elem = 1;
507346981Scy	if (dh_ss) {
508346981Scy		addr[1] = dh_ss;
509346981Scy		len[1] = dh_ss_len;
510346981Scy		num_elem++;
511346981Scy	}
512346981Scy	if (wpa_key_mgmt_sha384(akmp))
513346981Scy		res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
514346981Scy					 addr, len, pmk);
515346981Scy	else
516346981Scy		res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
517346981Scy					 addr, len, pmk);
518346981Scy	if (res == 0)
519346981Scy		wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
520346981Scy	else
521346981Scy		*pmk_len = 0;
522346981Scy	return res;
523346981Scy}
524346981Scy
525346981Scy
526346981Scyint fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
527346981Scy		   u8 *pmkid)
528346981Scy{
529346981Scy	const u8 *addr[1];
530346981Scy	size_t len[1];
531346981Scy	u8 hash[SHA384_MAC_LEN];
532346981Scy	int res;
533346981Scy
534346981Scy	/* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
535346981Scy	addr[0] = reauth;
536346981Scy	len[0] = reauth_len;
537346981Scy	if (wpa_key_mgmt_sha384(akmp))
538346981Scy		res = sha384_vector(1, addr, len, hash);
539346981Scy	else if (wpa_key_mgmt_sha256(akmp))
540346981Scy		res = sha256_vector(1, addr, len, hash);
541346981Scy	else
542346981Scy		return -1;
543346981Scy	if (res)
544346981Scy		return res;
545346981Scy	os_memcpy(pmkid, hash, PMKID_LEN);
546346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
547346981Scy	return 0;
548346981Scy}
549346981Scy
550346981Scy
551346981Scyint fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
552346981Scy		    const u8 *snonce, const u8 *anonce, const u8 *dhss,
553346981Scy		    size_t dhss_len, struct wpa_ptk *ptk,
554346981Scy		    u8 *ick, size_t *ick_len, int akmp, int cipher,
555346981Scy		    u8 *fils_ft, size_t *fils_ft_len)
556346981Scy{
557346981Scy	u8 *data, *pos;
558346981Scy	size_t data_len;
559346981Scy	u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
560346981Scy	       FILS_FT_MAX_LEN];
561346981Scy	size_t key_data_len;
562346981Scy	const char *label = "FILS PTK Derivation";
563346981Scy	int ret = -1;
564346981Scy
565346981Scy	/*
566346981Scy	 * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
567346981Scy	 *                       SPA || AA || SNonce || ANonce [ || DHss ])
568346981Scy	 * ICK = L(FILS-Key-Data, 0, ICK_bits)
569346981Scy	 * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits)
570346981Scy	 * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits)
571346981Scy	 * If doing FT initial mobility domain association:
572346981Scy	 * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
573346981Scy	 *             FILS-FT_bits)
574346981Scy	 */
575346981Scy	data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
576346981Scy	data = os_malloc(data_len);
577346981Scy	if (!data)
578346981Scy		goto err;
579346981Scy	pos = data;
580346981Scy	os_memcpy(pos, spa, ETH_ALEN);
581346981Scy	pos += ETH_ALEN;
582346981Scy	os_memcpy(pos, aa, ETH_ALEN);
583346981Scy	pos += ETH_ALEN;
584346981Scy	os_memcpy(pos, snonce, FILS_NONCE_LEN);
585346981Scy	pos += FILS_NONCE_LEN;
586346981Scy	os_memcpy(pos, anonce, FILS_NONCE_LEN);
587346981Scy	pos += FILS_NONCE_LEN;
588346981Scy	if (dhss)
589346981Scy		os_memcpy(pos, dhss, dhss_len);
590346981Scy
591346981Scy	ptk->kck_len = 0;
592346981Scy	ptk->kek_len = wpa_kek_len(akmp, pmk_len);
593346981Scy	ptk->tk_len = wpa_cipher_key_len(cipher);
594346981Scy	if (wpa_key_mgmt_sha384(akmp))
595346981Scy		*ick_len = 48;
596346981Scy	else if (wpa_key_mgmt_sha256(akmp))
597346981Scy		*ick_len = 32;
598346981Scy	else
599346981Scy		goto err;
600346981Scy	key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
601346981Scy
602346981Scy	if (fils_ft && fils_ft_len) {
603346981Scy		if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
604346981Scy			*fils_ft_len = 32;
605346981Scy		} else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) {
606346981Scy			*fils_ft_len = 48;
607346981Scy		} else {
608346981Scy			*fils_ft_len = 0;
609346981Scy			fils_ft = NULL;
610346981Scy		}
611346981Scy		key_data_len += *fils_ft_len;
612346981Scy	}
613346981Scy
614346981Scy	if (wpa_key_mgmt_sha384(akmp)) {
615346981Scy		wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)");
616346981Scy		if (sha384_prf(pmk, pmk_len, label, data, data_len,
617346981Scy			       tmp, key_data_len) < 0)
618346981Scy			goto err;
619346981Scy	} else {
620346981Scy		wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)");
621346981Scy		if (sha256_prf(pmk, pmk_len, label, data, data_len,
622346981Scy			       tmp, key_data_len) < 0)
623346981Scy			goto err;
624346981Scy	}
625346981Scy
626346981Scy	wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR
627346981Scy		   " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa));
628346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
629346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
630346981Scy	if (dhss)
631346981Scy		wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len);
632346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len);
633346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
634346981Scy
635346981Scy	os_memcpy(ick, tmp, *ick_len);
636346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
637346981Scy
638346981Scy	os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
639346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
640346981Scy
641346981Scy	os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
642346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
643346981Scy
644346981Scy	if (fils_ft && fils_ft_len) {
645346981Scy		os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
646346981Scy			  *fils_ft_len);
647346981Scy		wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
648346981Scy				fils_ft, *fils_ft_len);
649346981Scy	}
650346981Scy
651346981Scy	ptk->kek2_len = 0;
652346981Scy	ptk->kck2_len = 0;
653346981Scy
654346981Scy	os_memset(tmp, 0, sizeof(tmp));
655346981Scy	ret = 0;
656346981Scyerr:
657346981Scy	bin_clear_free(data, data_len);
658346981Scy	return ret;
659346981Scy}
660346981Scy
661346981Scy
662346981Scyint fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
663346981Scy		     const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
664346981Scy		     const u8 *g_sta, size_t g_sta_len,
665346981Scy		     const u8 *g_ap, size_t g_ap_len,
666346981Scy		     int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
667346981Scy		     size_t *key_auth_len)
668346981Scy{
669346981Scy	const u8 *addr[6];
670346981Scy	size_t len[6];
671346981Scy	size_t num_elem = 4;
672346981Scy	int res;
673346981Scy
674346981Scy	wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR
675346981Scy		   " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid));
676346981Scy	wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len);
677346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
678346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
679346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len);
680346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len);
681346981Scy
682346981Scy	/*
683346981Scy	 * For (Re)Association Request frame (STA->AP):
684346981Scy	 * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID
685346981Scy	 *                      [ || gSTA || gAP ])
686346981Scy	 */
687346981Scy	addr[0] = snonce;
688346981Scy	len[0] = FILS_NONCE_LEN;
689346981Scy	addr[1] = anonce;
690346981Scy	len[1] = FILS_NONCE_LEN;
691346981Scy	addr[2] = sta_addr;
692346981Scy	len[2] = ETH_ALEN;
693346981Scy	addr[3] = bssid;
694346981Scy	len[3] = ETH_ALEN;
695346981Scy	if (g_sta && g_ap_len && g_ap && g_ap_len) {
696346981Scy		addr[4] = g_sta;
697346981Scy		len[4] = g_sta_len;
698346981Scy		addr[5] = g_ap;
699346981Scy		len[5] = g_ap_len;
700346981Scy		num_elem = 6;
701346981Scy	}
702346981Scy
703346981Scy	if (wpa_key_mgmt_sha384(akmp)) {
704346981Scy		*key_auth_len = 48;
705346981Scy		res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
706346981Scy					 key_auth_sta);
707346981Scy	} else if (wpa_key_mgmt_sha256(akmp)) {
708346981Scy		*key_auth_len = 32;
709346981Scy		res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
710346981Scy					 key_auth_sta);
711346981Scy	} else {
712346981Scy		return -1;
713346981Scy	}
714346981Scy	if (res < 0)
715346981Scy		return res;
716346981Scy
717346981Scy	/*
718346981Scy	 * For (Re)Association Response frame (AP->STA):
719346981Scy	 * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC
720346981Scy	 *                      [ || gAP || gSTA ])
721346981Scy	 */
722346981Scy	addr[0] = anonce;
723346981Scy	addr[1] = snonce;
724346981Scy	addr[2] = bssid;
725346981Scy	addr[3] = sta_addr;
726346981Scy	if (g_sta && g_ap_len && g_ap && g_ap_len) {
727346981Scy		addr[4] = g_ap;
728346981Scy		len[4] = g_ap_len;
729346981Scy		addr[5] = g_sta;
730346981Scy		len[5] = g_sta_len;
731346981Scy	}
732346981Scy
733346981Scy	if (wpa_key_mgmt_sha384(akmp))
734346981Scy		res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
735346981Scy					 key_auth_ap);
736346981Scy	else if (wpa_key_mgmt_sha256(akmp))
737346981Scy		res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
738346981Scy					 key_auth_ap);
739346981Scy	if (res < 0)
740346981Scy		return res;
741346981Scy
742346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)",
743346981Scy		    key_auth_sta, *key_auth_len);
744346981Scy	wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)",
745346981Scy		    key_auth_ap, *key_auth_len);
746346981Scy
747346981Scy	return 0;
748346981Scy}
749346981Scy
750346981Scy#endif /* CONFIG_FILS */
751346981Scy
752346981Scy
753189251Ssam#ifdef CONFIG_IEEE80211R
754281806Srpauloint wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
755281806Srpaulo	       const u8 *ap_addr, u8 transaction_seqnum,
756281806Srpaulo	       const u8 *mdie, size_t mdie_len,
757189251Ssam	       const u8 *ftie, size_t ftie_len,
758189251Ssam	       const u8 *rsnie, size_t rsnie_len,
759189251Ssam	       const u8 *ric, size_t ric_len, u8 *mic)
760189251Ssam{
761289549Srpaulo	const u8 *addr[9];
762289549Srpaulo	size_t len[9];
763289549Srpaulo	size_t i, num_elem = 0;
764346981Scy	u8 zero_mic[24];
765346981Scy	size_t mic_len, fte_fixed_len;
766189251Ssam
767346981Scy	if (kck_len == 16) {
768346981Scy		mic_len = 16;
769346981Scy#ifdef CONFIG_SHA384
770346981Scy	} else if (kck_len == 24) {
771346981Scy		mic_len = 24;
772346981Scy#endif /* CONFIG_SHA384 */
773346981Scy	} else {
774281806Srpaulo		wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
775281806Srpaulo			   (unsigned int) kck_len);
776281806Srpaulo		return -1;
777281806Srpaulo	}
778281806Srpaulo
779346981Scy	fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
780346981Scy
781289549Srpaulo	addr[num_elem] = sta_addr;
782289549Srpaulo	len[num_elem] = ETH_ALEN;
783289549Srpaulo	num_elem++;
784189251Ssam
785289549Srpaulo	addr[num_elem] = ap_addr;
786289549Srpaulo	len[num_elem] = ETH_ALEN;
787289549Srpaulo	num_elem++;
788289549Srpaulo
789289549Srpaulo	addr[num_elem] = &transaction_seqnum;
790289549Srpaulo	len[num_elem] = 1;
791289549Srpaulo	num_elem++;
792289549Srpaulo
793189251Ssam	if (rsnie) {
794289549Srpaulo		addr[num_elem] = rsnie;
795289549Srpaulo		len[num_elem] = rsnie_len;
796289549Srpaulo		num_elem++;
797189251Ssam	}
798189251Ssam	if (mdie) {
799289549Srpaulo		addr[num_elem] = mdie;
800289549Srpaulo		len[num_elem] = mdie_len;
801289549Srpaulo		num_elem++;
802189251Ssam	}
803189251Ssam	if (ftie) {
804346981Scy		if (ftie_len < 2 + fte_fixed_len)
805189251Ssam			return -1;
806289549Srpaulo
807289549Srpaulo		/* IE hdr and mic_control */
808289549Srpaulo		addr[num_elem] = ftie;
809289549Srpaulo		len[num_elem] = 2 + 2;
810289549Srpaulo		num_elem++;
811289549Srpaulo
812289549Srpaulo		/* MIC field with all zeros */
813346981Scy		os_memset(zero_mic, 0, mic_len);
814289549Srpaulo		addr[num_elem] = zero_mic;
815346981Scy		len[num_elem] = mic_len;
816289549Srpaulo		num_elem++;
817289549Srpaulo
818289549Srpaulo		/* Rest of FTIE */
819346981Scy		addr[num_elem] = ftie + 2 + 2 + mic_len;
820346981Scy		len[num_elem] = ftie_len - (2 + 2 + mic_len);
821289549Srpaulo		num_elem++;
822189251Ssam	}
823189251Ssam	if (ric) {
824289549Srpaulo		addr[num_elem] = ric;
825289549Srpaulo		len[num_elem] = ric_len;
826289549Srpaulo		num_elem++;
827189251Ssam	}
828189251Ssam
829289549Srpaulo	for (i = 0; i < num_elem; i++)
830289549Srpaulo		wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
831346981Scy#ifdef CONFIG_SHA384
832346981Scy	if (kck_len == 24) {
833346981Scy		u8 hash[SHA384_MAC_LEN];
834346981Scy
835346981Scy		if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
836346981Scy			return -1;
837346981Scy		os_memcpy(mic, hash, 24);
838346981Scy	}
839346981Scy#endif /* CONFIG_SHA384 */
840346981Scy	if (kck_len == 16 &&
841346981Scy	    omac1_aes_128_vector(kck, num_elem, addr, len, mic))
842189251Ssam		return -1;
843189251Ssam
844189251Ssam	return 0;
845189251Ssam}
846252726Srpaulo
847252726Srpaulo
848252726Srpaulostatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
849346981Scy			     struct wpa_ft_ies *parse, int use_sha384)
850252726Srpaulo{
851252726Srpaulo	const u8 *end, *pos;
852252726Srpaulo
853252726Srpaulo	parse->ftie = ie;
854252726Srpaulo	parse->ftie_len = ie_len;
855252726Srpaulo
856346981Scy	pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
857346981Scy		    sizeof(struct rsn_ftie));
858252726Srpaulo	end = ie + ie_len;
859346981Scy	wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
860252726Srpaulo
861337817Scy	while (end - pos >= 2) {
862337817Scy		u8 id, len;
863337817Scy
864337817Scy		id = *pos++;
865337817Scy		len = *pos++;
866346981Scy		if (len > end - pos) {
867346981Scy			wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
868337817Scy			break;
869346981Scy		}
870337817Scy
871337817Scy		switch (id) {
872252726Srpaulo		case FTIE_SUBELEM_R1KH_ID:
873337817Scy			if (len != FT_R1KH_ID_LEN) {
874337817Scy				wpa_printf(MSG_DEBUG,
875337817Scy					   "FT: Invalid R1KH-ID length in FTIE: %d",
876337817Scy					   len);
877252726Srpaulo				return -1;
878252726Srpaulo			}
879337817Scy			parse->r1kh_id = pos;
880252726Srpaulo			break;
881252726Srpaulo		case FTIE_SUBELEM_GTK:
882337817Scy			parse->gtk = pos;
883337817Scy			parse->gtk_len = len;
884252726Srpaulo			break;
885252726Srpaulo		case FTIE_SUBELEM_R0KH_ID:
886337817Scy			if (len < 1 || len > FT_R0KH_ID_MAX_LEN) {
887337817Scy				wpa_printf(MSG_DEBUG,
888337817Scy					   "FT: Invalid R0KH-ID length in FTIE: %d",
889337817Scy					   len);
890252726Srpaulo				return -1;
891252726Srpaulo			}
892337817Scy			parse->r0kh_id = pos;
893337817Scy			parse->r0kh_id_len = len;
894252726Srpaulo			break;
895252726Srpaulo#ifdef CONFIG_IEEE80211W
896252726Srpaulo		case FTIE_SUBELEM_IGTK:
897337817Scy			parse->igtk = pos;
898337817Scy			parse->igtk_len = len;
899252726Srpaulo			break;
900252726Srpaulo#endif /* CONFIG_IEEE80211W */
901346981Scy#ifdef CONFIG_OCV
902346981Scy		case FTIE_SUBELEM_OCI:
903346981Scy			parse->oci = pos;
904346981Scy			parse->oci_len = len;
905346981Scy			break;
906346981Scy#endif /* CONFIG_OCV */
907346981Scy		default:
908346981Scy			wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
909346981Scy			break;
910252726Srpaulo		}
911252726Srpaulo
912337817Scy		pos += len;
913252726Srpaulo	}
914252726Srpaulo
915252726Srpaulo	return 0;
916252726Srpaulo}
917252726Srpaulo
918252726Srpaulo
919252726Srpauloint wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
920346981Scy		     struct wpa_ft_ies *parse, int use_sha384)
921252726Srpaulo{
922252726Srpaulo	const u8 *end, *pos;
923252726Srpaulo	struct wpa_ie_data data;
924252726Srpaulo	int ret;
925252726Srpaulo	const struct rsn_ftie *ftie;
926252726Srpaulo	int prot_ie_count = 0;
927346981Scy	int update_use_sha384 = 0;
928252726Srpaulo
929346981Scy	if (use_sha384 < 0) {
930346981Scy		use_sha384 = 0;
931346981Scy		update_use_sha384 = 1;
932346981Scy	}
933346981Scy
934252726Srpaulo	os_memset(parse, 0, sizeof(*parse));
935252726Srpaulo	if (ies == NULL)
936252726Srpaulo		return 0;
937252726Srpaulo
938252726Srpaulo	pos = ies;
939252726Srpaulo	end = ies + ies_len;
940337817Scy	while (end - pos >= 2) {
941337817Scy		u8 id, len;
942337817Scy
943337817Scy		id = *pos++;
944337817Scy		len = *pos++;
945337817Scy		if (len > end - pos)
946337817Scy			break;
947337817Scy
948337817Scy		switch (id) {
949252726Srpaulo		case WLAN_EID_RSN:
950346981Scy			wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
951337817Scy			parse->rsn = pos;
952337817Scy			parse->rsn_len = len;
953252726Srpaulo			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
954252726Srpaulo						   parse->rsn_len + 2,
955252726Srpaulo						   &data);
956252726Srpaulo			if (ret < 0) {
957252726Srpaulo				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
958252726Srpaulo					   "RSN IE: %d", ret);
959252726Srpaulo				return -1;
960252726Srpaulo			}
961252726Srpaulo			if (data.num_pmkid == 1 && data.pmkid)
962252726Srpaulo				parse->rsn_pmkid = data.pmkid;
963346981Scy			parse->key_mgmt = data.key_mgmt;
964346981Scy			parse->pairwise_cipher = data.pairwise_cipher;
965346981Scy			if (update_use_sha384) {
966346981Scy				use_sha384 =
967346981Scy					wpa_key_mgmt_sha384(parse->key_mgmt);
968346981Scy				update_use_sha384 = 0;
969346981Scy			}
970252726Srpaulo			break;
971252726Srpaulo		case WLAN_EID_MOBILITY_DOMAIN:
972346981Scy			wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
973337817Scy			if (len < sizeof(struct rsn_mdie))
974289549Srpaulo				return -1;
975337817Scy			parse->mdie = pos;
976337817Scy			parse->mdie_len = len;
977252726Srpaulo			break;
978252726Srpaulo		case WLAN_EID_FAST_BSS_TRANSITION:
979346981Scy			wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
980346981Scy			if (use_sha384) {
981346981Scy				const struct rsn_ftie_sha384 *ftie_sha384;
982346981Scy
983346981Scy				if (len < sizeof(*ftie_sha384))
984346981Scy					return -1;
985346981Scy				ftie_sha384 =
986346981Scy					(const struct rsn_ftie_sha384 *) pos;
987346981Scy				wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
988346981Scy					    ftie_sha384->mic_control, 2);
989346981Scy				wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
990346981Scy					    ftie_sha384->mic,
991346981Scy					    sizeof(ftie_sha384->mic));
992346981Scy				wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
993346981Scy					    ftie_sha384->anonce,
994346981Scy					    WPA_NONCE_LEN);
995346981Scy				wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
996346981Scy					    ftie_sha384->snonce,
997346981Scy					    WPA_NONCE_LEN);
998346981Scy				prot_ie_count = ftie_sha384->mic_control[1];
999346981Scy				if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
1000346981Scy					return -1;
1001346981Scy				break;
1002346981Scy			}
1003346981Scy
1004337817Scy			if (len < sizeof(*ftie))
1005252726Srpaulo				return -1;
1006337817Scy			ftie = (const struct rsn_ftie *) pos;
1007346981Scy			wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
1008346981Scy				    ftie->mic_control, 2);
1009346981Scy			wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
1010346981Scy				    ftie->mic, sizeof(ftie->mic));
1011346981Scy			wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
1012346981Scy				    ftie->anonce, WPA_NONCE_LEN);
1013346981Scy			wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
1014346981Scy				    ftie->snonce, WPA_NONCE_LEN);
1015252726Srpaulo			prot_ie_count = ftie->mic_control[1];
1016346981Scy			if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
1017252726Srpaulo				return -1;
1018252726Srpaulo			break;
1019252726Srpaulo		case WLAN_EID_TIMEOUT_INTERVAL:
1020346981Scy			wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
1021346981Scy				    pos, len);
1022337817Scy			if (len != 5)
1023289549Srpaulo				break;
1024337817Scy			parse->tie = pos;
1025337817Scy			parse->tie_len = len;
1026252726Srpaulo			break;
1027252726Srpaulo		case WLAN_EID_RIC_DATA:
1028252726Srpaulo			if (parse->ric == NULL)
1029337817Scy				parse->ric = pos - 2;
1030252726Srpaulo			break;
1031252726Srpaulo		}
1032252726Srpaulo
1033337817Scy		pos += len;
1034252726Srpaulo	}
1035252726Srpaulo
1036252726Srpaulo	if (prot_ie_count == 0)
1037252726Srpaulo		return 0; /* no MIC */
1038252726Srpaulo
1039252726Srpaulo	/*
1040252726Srpaulo	 * Check that the protected IE count matches with IEs included in the
1041252726Srpaulo	 * frame.
1042252726Srpaulo	 */
1043252726Srpaulo	if (parse->rsn)
1044252726Srpaulo		prot_ie_count--;
1045252726Srpaulo	if (parse->mdie)
1046252726Srpaulo		prot_ie_count--;
1047252726Srpaulo	if (parse->ftie)
1048252726Srpaulo		prot_ie_count--;
1049252726Srpaulo	if (prot_ie_count < 0) {
1050252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
1051252726Srpaulo			   "the protected IE count");
1052252726Srpaulo		return -1;
1053252726Srpaulo	}
1054252726Srpaulo
1055252726Srpaulo	if (prot_ie_count == 0 && parse->ric) {
1056252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
1057252726Srpaulo			   "included in protected IE count");
1058252726Srpaulo		return -1;
1059252726Srpaulo	}
1060252726Srpaulo
1061252726Srpaulo	/* Determine the end of the RIC IE(s) */
1062337817Scy	if (parse->ric) {
1063337817Scy		pos = parse->ric;
1064337817Scy		while (end - pos >= 2 && 2 + pos[1] <= end - pos &&
1065337817Scy		       prot_ie_count) {
1066337817Scy			prot_ie_count--;
1067337817Scy			pos += 2 + pos[1];
1068337817Scy		}
1069337817Scy		parse->ric_len = pos - parse->ric;
1070252726Srpaulo	}
1071252726Srpaulo	if (prot_ie_count) {
1072252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
1073252726Srpaulo			   "frame", (int) prot_ie_count);
1074252726Srpaulo		return -1;
1075252726Srpaulo	}
1076252726Srpaulo
1077252726Srpaulo	return 0;
1078252726Srpaulo}
1079189251Ssam#endif /* CONFIG_IEEE80211R */
1080189251Ssam
1081189251Ssam
1082189251Ssamstatic int rsn_selector_to_bitfield(const u8 *s)
1083189251Ssam{
1084189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
1085189251Ssam		return WPA_CIPHER_NONE;
1086189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
1087189251Ssam		return WPA_CIPHER_TKIP;
1088189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
1089189251Ssam		return WPA_CIPHER_CCMP;
1090189251Ssam#ifdef CONFIG_IEEE80211W
1091189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
1092189251Ssam		return WPA_CIPHER_AES_128_CMAC;
1093189251Ssam#endif /* CONFIG_IEEE80211W */
1094252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
1095252726Srpaulo		return WPA_CIPHER_GCMP;
1096281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
1097281806Srpaulo		return WPA_CIPHER_CCMP_256;
1098281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
1099281806Srpaulo		return WPA_CIPHER_GCMP_256;
1100281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
1101281806Srpaulo		return WPA_CIPHER_BIP_GMAC_128;
1102281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
1103281806Srpaulo		return WPA_CIPHER_BIP_GMAC_256;
1104281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
1105281806Srpaulo		return WPA_CIPHER_BIP_CMAC_256;
1106281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
1107281806Srpaulo		return WPA_CIPHER_GTK_NOT_USED;
1108189251Ssam	return 0;
1109189251Ssam}
1110189251Ssam
1111189251Ssam
1112189251Ssamstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
1113189251Ssam{
1114189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
1115189251Ssam		return WPA_KEY_MGMT_IEEE8021X;
1116189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
1117189251Ssam		return WPA_KEY_MGMT_PSK;
1118189251Ssam#ifdef CONFIG_IEEE80211R
1119189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
1120189251Ssam		return WPA_KEY_MGMT_FT_IEEE8021X;
1121189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
1122189251Ssam		return WPA_KEY_MGMT_FT_PSK;
1123346981Scy#ifdef CONFIG_SHA384
1124346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
1125346981Scy		return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
1126346981Scy#endif /* CONFIG_SHA384 */
1127189251Ssam#endif /* CONFIG_IEEE80211R */
1128189251Ssam#ifdef CONFIG_IEEE80211W
1129189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
1130189251Ssam		return WPA_KEY_MGMT_IEEE8021X_SHA256;
1131189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
1132189251Ssam		return WPA_KEY_MGMT_PSK_SHA256;
1133189251Ssam#endif /* CONFIG_IEEE80211W */
1134252726Srpaulo#ifdef CONFIG_SAE
1135252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
1136252726Srpaulo		return WPA_KEY_MGMT_SAE;
1137252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
1138252726Srpaulo		return WPA_KEY_MGMT_FT_SAE;
1139252726Srpaulo#endif /* CONFIG_SAE */
1140281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
1141281806Srpaulo		return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
1142281806Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
1143281806Srpaulo		return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
1144346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256)
1145346981Scy		return WPA_KEY_MGMT_FILS_SHA256;
1146346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384)
1147346981Scy		return WPA_KEY_MGMT_FILS_SHA384;
1148346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256)
1149346981Scy		return WPA_KEY_MGMT_FT_FILS_SHA256;
1150346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384)
1151346981Scy		return WPA_KEY_MGMT_FT_FILS_SHA384;
1152346981Scy#ifdef CONFIG_OWE
1153346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE)
1154346981Scy		return WPA_KEY_MGMT_OWE;
1155346981Scy#endif /* CONFIG_OWE */
1156346981Scy#ifdef CONFIG_DPP
1157346981Scy	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP)
1158346981Scy		return WPA_KEY_MGMT_DPP;
1159346981Scy#endif /* CONFIG_DPP */
1160289549Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
1161289549Srpaulo		return WPA_KEY_MGMT_OSEN;
1162189251Ssam	return 0;
1163189251Ssam}
1164189251Ssam
1165189251Ssam
1166289549Srpauloint wpa_cipher_valid_group(int cipher)
1167281806Srpaulo{
1168281806Srpaulo	return wpa_cipher_valid_pairwise(cipher) ||
1169281806Srpaulo		cipher == WPA_CIPHER_GTK_NOT_USED;
1170281806Srpaulo}
1171281806Srpaulo
1172281806Srpaulo
1173281806Srpaulo#ifdef CONFIG_IEEE80211W
1174281806Srpauloint wpa_cipher_valid_mgmt_group(int cipher)
1175281806Srpaulo{
1176281806Srpaulo	return cipher == WPA_CIPHER_AES_128_CMAC ||
1177281806Srpaulo		cipher == WPA_CIPHER_BIP_GMAC_128 ||
1178281806Srpaulo		cipher == WPA_CIPHER_BIP_GMAC_256 ||
1179281806Srpaulo		cipher == WPA_CIPHER_BIP_CMAC_256;
1180281806Srpaulo}
1181281806Srpaulo#endif /* CONFIG_IEEE80211W */
1182281806Srpaulo
1183281806Srpaulo
1184189251Ssam/**
1185189251Ssam * wpa_parse_wpa_ie_rsn - Parse RSN IE
1186189251Ssam * @rsn_ie: Buffer containing RSN IE
1187189251Ssam * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
1188189251Ssam * @data: Pointer to structure that will be filled in with parsed data
1189189251Ssam * Returns: 0 on success, <0 on failure
1190189251Ssam */
1191189251Ssamint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
1192189251Ssam			 struct wpa_ie_data *data)
1193189251Ssam{
1194189251Ssam	const u8 *pos;
1195189251Ssam	int left;
1196189251Ssam	int i, count;
1197189251Ssam
1198189251Ssam	os_memset(data, 0, sizeof(*data));
1199189251Ssam	data->proto = WPA_PROTO_RSN;
1200189251Ssam	data->pairwise_cipher = WPA_CIPHER_CCMP;
1201189251Ssam	data->group_cipher = WPA_CIPHER_CCMP;
1202189251Ssam	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
1203189251Ssam	data->capabilities = 0;
1204189251Ssam	data->pmkid = NULL;
1205189251Ssam	data->num_pmkid = 0;
1206189251Ssam#ifdef CONFIG_IEEE80211W
1207189251Ssam	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
1208189251Ssam#else /* CONFIG_IEEE80211W */
1209189251Ssam	data->mgmt_group_cipher = 0;
1210189251Ssam#endif /* CONFIG_IEEE80211W */
1211189251Ssam
1212189251Ssam	if (rsn_ie_len == 0) {
1213189251Ssam		/* No RSN IE - fail silently */
1214189251Ssam		return -1;
1215189251Ssam	}
1216189251Ssam
1217189251Ssam	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
1218189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
1219189251Ssam			   __func__, (unsigned long) rsn_ie_len);
1220189251Ssam		return -1;
1221189251Ssam	}
1222189251Ssam
1223289549Srpaulo	if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
1224289549Srpaulo	    rsn_ie[1] == rsn_ie_len - 2 &&
1225289549Srpaulo	    WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
1226289549Srpaulo		pos = rsn_ie + 6;
1227289549Srpaulo		left = rsn_ie_len - 6;
1228189251Ssam
1229346981Scy		data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
1230346981Scy		data->has_group = 1;
1231346981Scy		data->key_mgmt = WPA_KEY_MGMT_OSEN;
1232289549Srpaulo		data->proto = WPA_PROTO_OSEN;
1233289549Srpaulo	} else {
1234289549Srpaulo		const struct rsn_ie_hdr *hdr;
1235289549Srpaulo
1236289549Srpaulo		hdr = (const struct rsn_ie_hdr *) rsn_ie;
1237289549Srpaulo
1238289549Srpaulo		if (hdr->elem_id != WLAN_EID_RSN ||
1239289549Srpaulo		    hdr->len != rsn_ie_len - 2 ||
1240289549Srpaulo		    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
1241289549Srpaulo			wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
1242289549Srpaulo				   __func__);
1243289549Srpaulo			return -2;
1244289549Srpaulo		}
1245289549Srpaulo
1246289549Srpaulo		pos = (const u8 *) (hdr + 1);
1247289549Srpaulo		left = rsn_ie_len - sizeof(*hdr);
1248189251Ssam	}
1249189251Ssam
1250189251Ssam	if (left >= RSN_SELECTOR_LEN) {
1251189251Ssam		data->group_cipher = rsn_selector_to_bitfield(pos);
1252346981Scy		data->has_group = 1;
1253281806Srpaulo		if (!wpa_cipher_valid_group(data->group_cipher)) {
1254337817Scy			wpa_printf(MSG_DEBUG,
1255337817Scy				   "%s: invalid group cipher 0x%x (%08x)",
1256337817Scy				   __func__, data->group_cipher,
1257337817Scy				   WPA_GET_BE32(pos));
1258189251Ssam			return -1;
1259189251Ssam		}
1260189251Ssam		pos += RSN_SELECTOR_LEN;
1261189251Ssam		left -= RSN_SELECTOR_LEN;
1262189251Ssam	} else if (left > 0) {
1263189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
1264189251Ssam			   __func__, left);
1265189251Ssam		return -3;
1266189251Ssam	}
1267189251Ssam
1268189251Ssam	if (left >= 2) {
1269189251Ssam		data->pairwise_cipher = 0;
1270189251Ssam		count = WPA_GET_LE16(pos);
1271189251Ssam		pos += 2;
1272189251Ssam		left -= 2;
1273281806Srpaulo		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
1274189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
1275189251Ssam				   "count %u left %u", __func__, count, left);
1276189251Ssam			return -4;
1277189251Ssam		}
1278346981Scy		if (count)
1279346981Scy			data->has_pairwise = 1;
1280189251Ssam		for (i = 0; i < count; i++) {
1281189251Ssam			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
1282189251Ssam			pos += RSN_SELECTOR_LEN;
1283189251Ssam			left -= RSN_SELECTOR_LEN;
1284189251Ssam		}
1285189251Ssam#ifdef CONFIG_IEEE80211W
1286189251Ssam		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
1287189251Ssam			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
1288189251Ssam				   "pairwise cipher", __func__);
1289189251Ssam			return -1;
1290189251Ssam		}
1291189251Ssam#endif /* CONFIG_IEEE80211W */
1292189251Ssam	} else if (left == 1) {
1293189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
1294189251Ssam			   __func__);
1295189251Ssam		return -5;
1296189251Ssam	}
1297189251Ssam
1298189251Ssam	if (left >= 2) {
1299189251Ssam		data->key_mgmt = 0;
1300189251Ssam		count = WPA_GET_LE16(pos);
1301189251Ssam		pos += 2;
1302189251Ssam		left -= 2;
1303281806Srpaulo		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
1304189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
1305189251Ssam				   "count %u left %u", __func__, count, left);
1306189251Ssam			return -6;
1307189251Ssam		}
1308189251Ssam		for (i = 0; i < count; i++) {
1309189251Ssam			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
1310189251Ssam			pos += RSN_SELECTOR_LEN;
1311189251Ssam			left -= RSN_SELECTOR_LEN;
1312189251Ssam		}
1313189251Ssam	} else if (left == 1) {
1314189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
1315189251Ssam			   __func__);
1316189251Ssam		return -7;
1317189251Ssam	}
1318189251Ssam
1319189251Ssam	if (left >= 2) {
1320189251Ssam		data->capabilities = WPA_GET_LE16(pos);
1321189251Ssam		pos += 2;
1322189251Ssam		left -= 2;
1323189251Ssam	}
1324189251Ssam
1325189251Ssam	if (left >= 2) {
1326281806Srpaulo		u16 num_pmkid = WPA_GET_LE16(pos);
1327189251Ssam		pos += 2;
1328189251Ssam		left -= 2;
1329281806Srpaulo		if (num_pmkid > (unsigned int) left / PMKID_LEN) {
1330189251Ssam			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
1331281806Srpaulo				   "(num_pmkid=%u left=%d)",
1332281806Srpaulo				   __func__, num_pmkid, left);
1333189251Ssam			data->num_pmkid = 0;
1334189251Ssam			return -9;
1335189251Ssam		} else {
1336281806Srpaulo			data->num_pmkid = num_pmkid;
1337189251Ssam			data->pmkid = pos;
1338189251Ssam			pos += data->num_pmkid * PMKID_LEN;
1339189251Ssam			left -= data->num_pmkid * PMKID_LEN;
1340189251Ssam		}
1341189251Ssam	}
1342189251Ssam
1343189251Ssam#ifdef CONFIG_IEEE80211W
1344189251Ssam	if (left >= 4) {
1345189251Ssam		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
1346281806Srpaulo		if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
1347337817Scy			wpa_printf(MSG_DEBUG,
1348337817Scy				   "%s: Unsupported management group cipher 0x%x (%08x)",
1349337817Scy				   __func__, data->mgmt_group_cipher,
1350337817Scy				   WPA_GET_BE32(pos));
1351189251Ssam			return -10;
1352189251Ssam		}
1353189251Ssam		pos += RSN_SELECTOR_LEN;
1354189251Ssam		left -= RSN_SELECTOR_LEN;
1355189251Ssam	}
1356189251Ssam#endif /* CONFIG_IEEE80211W */
1357189251Ssam
1358189251Ssam	if (left > 0) {
1359281806Srpaulo		wpa_hexdump(MSG_DEBUG,
1360281806Srpaulo			    "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
1361281806Srpaulo			    pos, left);
1362189251Ssam	}
1363189251Ssam
1364189251Ssam	return 0;
1365189251Ssam}
1366189251Ssam
1367189251Ssam
1368252726Srpaulostatic int wpa_selector_to_bitfield(const u8 *s)
1369252726Srpaulo{
1370252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
1371252726Srpaulo		return WPA_CIPHER_NONE;
1372252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
1373252726Srpaulo		return WPA_CIPHER_TKIP;
1374252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
1375252726Srpaulo		return WPA_CIPHER_CCMP;
1376252726Srpaulo	return 0;
1377252726Srpaulo}
1378252726Srpaulo
1379252726Srpaulo
1380252726Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s)
1381252726Srpaulo{
1382252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
1383252726Srpaulo		return WPA_KEY_MGMT_IEEE8021X;
1384252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
1385252726Srpaulo		return WPA_KEY_MGMT_PSK;
1386252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
1387252726Srpaulo		return WPA_KEY_MGMT_WPA_NONE;
1388252726Srpaulo	return 0;
1389252726Srpaulo}
1390252726Srpaulo
1391252726Srpaulo
1392252726Srpauloint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
1393252726Srpaulo			 struct wpa_ie_data *data)
1394252726Srpaulo{
1395252726Srpaulo	const struct wpa_ie_hdr *hdr;
1396252726Srpaulo	const u8 *pos;
1397252726Srpaulo	int left;
1398252726Srpaulo	int i, count;
1399252726Srpaulo
1400252726Srpaulo	os_memset(data, 0, sizeof(*data));
1401252726Srpaulo	data->proto = WPA_PROTO_WPA;
1402252726Srpaulo	data->pairwise_cipher = WPA_CIPHER_TKIP;
1403252726Srpaulo	data->group_cipher = WPA_CIPHER_TKIP;
1404252726Srpaulo	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
1405252726Srpaulo	data->capabilities = 0;
1406252726Srpaulo	data->pmkid = NULL;
1407252726Srpaulo	data->num_pmkid = 0;
1408252726Srpaulo	data->mgmt_group_cipher = 0;
1409252726Srpaulo
1410252726Srpaulo	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
1411252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
1412252726Srpaulo			   __func__, (unsigned long) wpa_ie_len);
1413252726Srpaulo		return -1;
1414252726Srpaulo	}
1415252726Srpaulo
1416252726Srpaulo	hdr = (const struct wpa_ie_hdr *) wpa_ie;
1417252726Srpaulo
1418252726Srpaulo	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
1419252726Srpaulo	    hdr->len != wpa_ie_len - 2 ||
1420252726Srpaulo	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
1421252726Srpaulo	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
1422252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
1423252726Srpaulo			   __func__);
1424252726Srpaulo		return -2;
1425252726Srpaulo	}
1426252726Srpaulo
1427252726Srpaulo	pos = (const u8 *) (hdr + 1);
1428252726Srpaulo	left = wpa_ie_len - sizeof(*hdr);
1429252726Srpaulo
1430252726Srpaulo	if (left >= WPA_SELECTOR_LEN) {
1431252726Srpaulo		data->group_cipher = wpa_selector_to_bitfield(pos);
1432252726Srpaulo		pos += WPA_SELECTOR_LEN;
1433252726Srpaulo		left -= WPA_SELECTOR_LEN;
1434252726Srpaulo	} else if (left > 0) {
1435252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
1436252726Srpaulo			   __func__, left);
1437252726Srpaulo		return -3;
1438252726Srpaulo	}
1439252726Srpaulo
1440252726Srpaulo	if (left >= 2) {
1441252726Srpaulo		data->pairwise_cipher = 0;
1442252726Srpaulo		count = WPA_GET_LE16(pos);
1443252726Srpaulo		pos += 2;
1444252726Srpaulo		left -= 2;
1445281806Srpaulo		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
1446252726Srpaulo			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
1447252726Srpaulo				   "count %u left %u", __func__, count, left);
1448252726Srpaulo			return -4;
1449252726Srpaulo		}
1450252726Srpaulo		for (i = 0; i < count; i++) {
1451252726Srpaulo			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
1452252726Srpaulo			pos += WPA_SELECTOR_LEN;
1453252726Srpaulo			left -= WPA_SELECTOR_LEN;
1454252726Srpaulo		}
1455252726Srpaulo	} else if (left == 1) {
1456252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
1457252726Srpaulo			   __func__);
1458252726Srpaulo		return -5;
1459252726Srpaulo	}
1460252726Srpaulo
1461252726Srpaulo	if (left >= 2) {
1462252726Srpaulo		data->key_mgmt = 0;
1463252726Srpaulo		count = WPA_GET_LE16(pos);
1464252726Srpaulo		pos += 2;
1465252726Srpaulo		left -= 2;
1466281806Srpaulo		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
1467252726Srpaulo			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
1468252726Srpaulo				   "count %u left %u", __func__, count, left);
1469252726Srpaulo			return -6;
1470252726Srpaulo		}
1471252726Srpaulo		for (i = 0; i < count; i++) {
1472252726Srpaulo			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
1473252726Srpaulo			pos += WPA_SELECTOR_LEN;
1474252726Srpaulo			left -= WPA_SELECTOR_LEN;
1475252726Srpaulo		}
1476252726Srpaulo	} else if (left == 1) {
1477252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
1478252726Srpaulo			   __func__);
1479252726Srpaulo		return -7;
1480252726Srpaulo	}
1481252726Srpaulo
1482252726Srpaulo	if (left >= 2) {
1483252726Srpaulo		data->capabilities = WPA_GET_LE16(pos);
1484252726Srpaulo		pos += 2;
1485252726Srpaulo		left -= 2;
1486252726Srpaulo	}
1487252726Srpaulo
1488252726Srpaulo	if (left > 0) {
1489281806Srpaulo		wpa_hexdump(MSG_DEBUG,
1490281806Srpaulo			    "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
1491281806Srpaulo			    pos, left);
1492252726Srpaulo	}
1493252726Srpaulo
1494252726Srpaulo	return 0;
1495252726Srpaulo}
1496252726Srpaulo
1497252726Srpaulo
1498346981Scyint wpa_default_rsn_cipher(int freq)
1499346981Scy{
1500346981Scy	if (freq > 56160)
1501346981Scy		return WPA_CIPHER_GCMP; /* DMG */
1502346981Scy
1503346981Scy	return WPA_CIPHER_CCMP;
1504346981Scy}
1505346981Scy
1506346981Scy
1507189251Ssam#ifdef CONFIG_IEEE80211R
1508189251Ssam
1509189251Ssam/**
1510189251Ssam * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
1511189251Ssam *
1512189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.3
1513189251Ssam */
1514346981Scyint wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
1515346981Scy		      const u8 *ssid, size_t ssid_len,
1516346981Scy		      const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
1517346981Scy		      const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
1518346981Scy		      int use_sha384)
1519189251Ssam{
1520289549Srpaulo	u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
1521189251Ssam	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
1522346981Scy	u8 *pos, r0_key_data[64], hash[48];
1523189251Ssam	const u8 *addr[2];
1524189251Ssam	size_t len[2];
1525346981Scy	size_t q = use_sha384 ? 48 : 32;
1526346981Scy	size_t r0_key_data_len = q + 16;
1527189251Ssam
1528189251Ssam	/*
1529189251Ssam	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
1530189251Ssam	 *                       SSIDlength || SSID || MDID || R0KHlength ||
1531189251Ssam	 *                       R0KH-ID || S0KH-ID)
1532346981Scy	 * XXKey is either the second 256 bits of MSK or PSK; or the first
1533346981Scy	 * 384 bits of MSK for FT-EAP-SHA384.
1534346981Scy	 * PMK-R0 = L(R0-Key-Data, 0, Q)
1535346981Scy	 * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
1536346981Scy	 * Q = 384 for FT-EAP-SHA384; otherwise, 256
1537189251Ssam	 */
1538289549Srpaulo	if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
1539346981Scy		return -1;
1540346981Scy	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
1541346981Scy		   use_sha384 ? "SHA384" : "SHA256");
1542346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
1543346981Scy	wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
1544346981Scy	wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
1545346981Scy	wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
1546346981Scy	wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
1547189251Ssam	pos = buf;
1548189251Ssam	*pos++ = ssid_len;
1549189251Ssam	os_memcpy(pos, ssid, ssid_len);
1550189251Ssam	pos += ssid_len;
1551189251Ssam	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
1552189251Ssam	pos += MOBILITY_DOMAIN_ID_LEN;
1553189251Ssam	*pos++ = r0kh_id_len;
1554189251Ssam	os_memcpy(pos, r0kh_id, r0kh_id_len);
1555189251Ssam	pos += r0kh_id_len;
1556189251Ssam	os_memcpy(pos, s0kh_id, ETH_ALEN);
1557189251Ssam	pos += ETH_ALEN;
1558189251Ssam
1559346981Scy#ifdef CONFIG_SHA384
1560346981Scy	if (use_sha384) {
1561346981Scy		if (xxkey_len != SHA384_MAC_LEN) {
1562346981Scy			wpa_printf(MSG_ERROR,
1563346981Scy				   "FT: Unexpected XXKey length %d (expected %d)",
1564346981Scy				   (int) xxkey_len, SHA384_MAC_LEN);
1565346981Scy			return -1;
1566346981Scy		}
1567346981Scy		if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
1568346981Scy			       r0_key_data, r0_key_data_len) < 0)
1569346981Scy			return -1;
1570346981Scy	}
1571346981Scy#endif /* CONFIG_SHA384 */
1572346981Scy	if (!use_sha384) {
1573346981Scy		if (xxkey_len != PMK_LEN) {
1574346981Scy			wpa_printf(MSG_ERROR,
1575346981Scy				   "FT: Unexpected XXKey length %d (expected %d)",
1576346981Scy				   (int) xxkey_len, PMK_LEN);
1577346981Scy			return -1;
1578346981Scy		}
1579346981Scy		if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
1580346981Scy			       r0_key_data, r0_key_data_len) < 0)
1581346981Scy			return -1;
1582346981Scy	}
1583346981Scy	os_memcpy(pmk_r0, r0_key_data, q);
1584346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
1585346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
1586189251Ssam
1587189251Ssam	/*
1588346981Scy	 * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
1589189251Ssam	 */
1590189251Ssam	addr[0] = (const u8 *) "FT-R0N";
1591189251Ssam	len[0] = 6;
1592346981Scy	addr[1] = &r0_key_data[q];
1593189251Ssam	len[1] = 16;
1594189251Ssam
1595346981Scy#ifdef CONFIG_SHA384
1596346981Scy	if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
1597346981Scy		return -1;
1598346981Scy#endif /* CONFIG_SHA384 */
1599346981Scy	if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
1600346981Scy		return -1;
1601189251Ssam	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
1602346981Scy	os_memset(r0_key_data, 0, sizeof(r0_key_data));
1603346981Scy	return 0;
1604189251Ssam}
1605189251Ssam
1606189251Ssam
1607189251Ssam/**
1608189251Ssam * wpa_derive_pmk_r1_name - Derive PMKR1Name
1609189251Ssam *
1610189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
1611189251Ssam */
1612346981Scyint wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
1613346981Scy			   const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
1614189251Ssam{
1615346981Scy	u8 hash[48];
1616189251Ssam	const u8 *addr[4];
1617189251Ssam	size_t len[4];
1618189251Ssam
1619189251Ssam	/*
1620346981Scy	 * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
1621346981Scy	 *                               R1KH-ID || S1KH-ID))
1622189251Ssam	 */
1623189251Ssam	addr[0] = (const u8 *) "FT-R1N";
1624189251Ssam	len[0] = 6;
1625189251Ssam	addr[1] = pmk_r0_name;
1626189251Ssam	len[1] = WPA_PMK_NAME_LEN;
1627189251Ssam	addr[2] = r1kh_id;
1628189251Ssam	len[2] = FT_R1KH_ID_LEN;
1629189251Ssam	addr[3] = s1kh_id;
1630189251Ssam	len[3] = ETH_ALEN;
1631189251Ssam
1632346981Scy#ifdef CONFIG_SHA384
1633346981Scy	if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
1634346981Scy		return -1;
1635346981Scy#endif /* CONFIG_SHA384 */
1636346981Scy	if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
1637346981Scy		return -1;
1638189251Ssam	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
1639346981Scy	return 0;
1640189251Ssam}
1641189251Ssam
1642189251Ssam
1643189251Ssam/**
1644189251Ssam * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
1645189251Ssam *
1646189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
1647189251Ssam */
1648346981Scyint wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
1649346981Scy		      const u8 *pmk_r0_name,
1650346981Scy		      const u8 *r1kh_id, const u8 *s1kh_id,
1651346981Scy		      u8 *pmk_r1, u8 *pmk_r1_name)
1652189251Ssam{
1653189251Ssam	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
1654189251Ssam	u8 *pos;
1655189251Ssam
1656189251Ssam	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
1657346981Scy	wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
1658346981Scy		   pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
1659346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
1660346981Scy	wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
1661346981Scy	wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
1662189251Ssam	pos = buf;
1663189251Ssam	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
1664189251Ssam	pos += FT_R1KH_ID_LEN;
1665189251Ssam	os_memcpy(pos, s1kh_id, ETH_ALEN);
1666189251Ssam	pos += ETH_ALEN;
1667189251Ssam
1668346981Scy#ifdef CONFIG_SHA384
1669346981Scy	if (pmk_r0_len == SHA384_MAC_LEN &&
1670346981Scy	    sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
1671346981Scy		       buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
1672346981Scy		return -1;
1673346981Scy#endif /* CONFIG_SHA384 */
1674346981Scy	if (pmk_r0_len == PMK_LEN &&
1675346981Scy	    sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
1676346981Scy		       buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
1677346981Scy		return -1;
1678346981Scy	if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
1679346981Scy		wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
1680346981Scy			   (int) pmk_r0_len);
1681346981Scy		return -1;
1682346981Scy	}
1683346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
1684189251Ssam
1685346981Scy	return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
1686346981Scy				      pmk_r1_name,
1687346981Scy				      pmk_r0_len == SHA384_MAC_LEN);
1688189251Ssam}
1689189251Ssam
1690189251Ssam
1691189251Ssam/**
1692189251Ssam * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
1693189251Ssam *
1694189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.5
1695189251Ssam */
1696346981Scyint wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
1697346981Scy		      const u8 *snonce, const u8 *anonce,
1698281806Srpaulo		      const u8 *sta_addr, const u8 *bssid,
1699281806Srpaulo		      const u8 *pmk_r1_name,
1700281806Srpaulo		      struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
1701189251Ssam{
1702189251Ssam	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
1703189251Ssam	u8 *pos, hash[32];
1704189251Ssam	const u8 *addr[6];
1705189251Ssam	size_t len[6];
1706346981Scy	u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
1707346981Scy	size_t ptk_len, offset;
1708346981Scy	int use_sha384 = wpa_key_mgmt_sha384(akmp);
1709189251Ssam
1710189251Ssam	/*
1711189251Ssam	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
1712189251Ssam	 *                  BSSID || STA-ADDR)
1713189251Ssam	 */
1714346981Scy	wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
1715346981Scy		   use_sha384 ? "SHA384" : "SHA256");
1716346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
1717346981Scy	wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
1718346981Scy	wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
1719346981Scy	wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
1720346981Scy		   MAC2STR(bssid), MAC2STR(sta_addr));
1721189251Ssam	pos = buf;
1722189251Ssam	os_memcpy(pos, snonce, WPA_NONCE_LEN);
1723189251Ssam	pos += WPA_NONCE_LEN;
1724189251Ssam	os_memcpy(pos, anonce, WPA_NONCE_LEN);
1725189251Ssam	pos += WPA_NONCE_LEN;
1726189251Ssam	os_memcpy(pos, bssid, ETH_ALEN);
1727189251Ssam	pos += ETH_ALEN;
1728189251Ssam	os_memcpy(pos, sta_addr, ETH_ALEN);
1729189251Ssam	pos += ETH_ALEN;
1730189251Ssam
1731346981Scy	ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
1732346981Scy	ptk->kck2_len = wpa_kck2_len(akmp);
1733346981Scy	ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
1734346981Scy	ptk->kek2_len = wpa_kek2_len(akmp);
1735281806Srpaulo	ptk->tk_len = wpa_cipher_key_len(cipher);
1736346981Scy	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
1737346981Scy		ptk->kck2_len + ptk->kek2_len;
1738189251Ssam
1739346981Scy#ifdef CONFIG_SHA384
1740346981Scy	if (use_sha384) {
1741346981Scy		if (pmk_r1_len != SHA384_MAC_LEN) {
1742346981Scy			wpa_printf(MSG_ERROR,
1743346981Scy				   "FT: Unexpected PMK-R1 length %d (expected %d)",
1744346981Scy				   (int) pmk_r1_len, SHA384_MAC_LEN);
1745346981Scy			return -1;
1746346981Scy		}
1747346981Scy		if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
1748346981Scy			       buf, pos - buf, tmp, ptk_len) < 0)
1749346981Scy			return -1;
1750346981Scy	}
1751346981Scy#endif /* CONFIG_SHA384 */
1752346981Scy	if (!use_sha384) {
1753346981Scy		if (pmk_r1_len != PMK_LEN) {
1754346981Scy			wpa_printf(MSG_ERROR,
1755346981Scy				   "FT: Unexpected PMK-R1 length %d (expected %d)",
1756346981Scy				   (int) pmk_r1_len, PMK_LEN);
1757346981Scy			return -1;
1758346981Scy		}
1759346981Scy		if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
1760346981Scy			       buf, pos - buf, tmp, ptk_len) < 0)
1761346981Scy			return -1;
1762346981Scy	}
1763346981Scy	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
1764281806Srpaulo
1765189251Ssam	/*
1766189251Ssam	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
1767189251Ssam	 *                                ANonce || BSSID || STA-ADDR))
1768189251Ssam	 */
1769346981Scy	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
1770189251Ssam	addr[0] = pmk_r1_name;
1771189251Ssam	len[0] = WPA_PMK_NAME_LEN;
1772189251Ssam	addr[1] = (const u8 *) "FT-PTKN";
1773189251Ssam	len[1] = 7;
1774189251Ssam	addr[2] = snonce;
1775189251Ssam	len[2] = WPA_NONCE_LEN;
1776189251Ssam	addr[3] = anonce;
1777189251Ssam	len[3] = WPA_NONCE_LEN;
1778189251Ssam	addr[4] = bssid;
1779189251Ssam	len[4] = ETH_ALEN;
1780189251Ssam	addr[5] = sta_addr;
1781189251Ssam	len[5] = ETH_ALEN;
1782189251Ssam
1783346981Scy	if (sha256_vector(6, addr, len, hash) < 0)
1784346981Scy		return -1;
1785189251Ssam	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
1786281806Srpaulo
1787281806Srpaulo	os_memcpy(ptk->kck, tmp, ptk->kck_len);
1788346981Scy	offset = ptk->kck_len;
1789346981Scy	os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
1790346981Scy	offset += ptk->kek_len;
1791346981Scy	os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
1792346981Scy	offset += ptk->tk_len;
1793346981Scy	os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
1794346981Scy	offset += ptk->kck2_len;
1795346981Scy	os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
1796281806Srpaulo
1797281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
1798281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
1799346981Scy	if (ptk->kck2_len)
1800346981Scy		wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
1801346981Scy				ptk->kck2, ptk->kck2_len);
1802346981Scy	if (ptk->kek2_len)
1803346981Scy		wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
1804346981Scy				ptk->kek2, ptk->kek2_len);
1805281806Srpaulo	wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
1806281806Srpaulo	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
1807281806Srpaulo
1808281806Srpaulo	os_memset(tmp, 0, sizeof(tmp));
1809281806Srpaulo
1810281806Srpaulo	return 0;
1811189251Ssam}
1812189251Ssam
1813189251Ssam#endif /* CONFIG_IEEE80211R */
1814214734Srpaulo
1815214734Srpaulo
1816214734Srpaulo/**
1817214734Srpaulo * rsn_pmkid - Calculate PMK identifier
1818214734Srpaulo * @pmk: Pairwise master key
1819214734Srpaulo * @pmk_len: Length of pmk in bytes
1820214734Srpaulo * @aa: Authenticator address
1821214734Srpaulo * @spa: Supplicant address
1822214734Srpaulo * @pmkid: Buffer for PMKID
1823346981Scy * @akmp: Negotiated key management protocol
1824214734Srpaulo *
1825346981Scy * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy
1826346981Scy * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
1827346981Scy * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA))
1828346981Scy * AKM: 00-0F-AC:11
1829346981Scy * See rsn_pmkid_suite_b()
1830346981Scy * AKM: 00-0F-AC:12
1831346981Scy * See rsn_pmkid_suite_b_192()
1832346981Scy * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
1833346981Scy * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
1834346981Scy * Otherwise:
1835346981Scy * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
1836214734Srpaulo */
1837214734Srpaulovoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
1838346981Scy	       u8 *pmkid, int akmp)
1839214734Srpaulo{
1840214734Srpaulo	char *title = "PMK Name";
1841214734Srpaulo	const u8 *addr[3];
1842214734Srpaulo	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1843346981Scy	unsigned char hash[SHA384_MAC_LEN];
1844214734Srpaulo
1845214734Srpaulo	addr[0] = (u8 *) title;
1846214734Srpaulo	addr[1] = aa;
1847214734Srpaulo	addr[2] = spa;
1848214734Srpaulo
1849346981Scy	if (0) {
1850346981Scy#if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
1851346981Scy	} else if (wpa_key_mgmt_sha384(akmp)) {
1852346981Scy		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
1853346981Scy		hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
1854346981Scy#endif /* CONFIG_FILS || CONFIG_SHA384 */
1855346981Scy#if defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
1856346981Scy	} else if (wpa_key_mgmt_sha256(akmp)) {
1857346981Scy		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
1858214734Srpaulo		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
1859346981Scy#endif /* CONFIG_IEEE80211W || CONFIG_FILS */
1860346981Scy	} else {
1861346981Scy		wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
1862214734Srpaulo		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
1863346981Scy	}
1864346981Scy	wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN);
1865214734Srpaulo	os_memcpy(pmkid, hash, PMKID_LEN);
1866214734Srpaulo}
1867214734Srpaulo
1868214734Srpaulo
1869281806Srpaulo#ifdef CONFIG_SUITEB
1870214734Srpaulo/**
1871281806Srpaulo * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
1872281806Srpaulo * @kck: Key confirmation key
1873281806Srpaulo * @kck_len: Length of kck in bytes
1874281806Srpaulo * @aa: Authenticator address
1875281806Srpaulo * @spa: Supplicant address
1876281806Srpaulo * @pmkid: Buffer for PMKID
1877281806Srpaulo * Returns: 0 on success, -1 on failure
1878281806Srpaulo *
1879281806Srpaulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1880281806Srpaulo * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
1881281806Srpaulo */
1882281806Srpauloint rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
1883281806Srpaulo		      const u8 *spa, u8 *pmkid)
1884281806Srpaulo{
1885281806Srpaulo	char *title = "PMK Name";
1886281806Srpaulo	const u8 *addr[3];
1887281806Srpaulo	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1888281806Srpaulo	unsigned char hash[SHA256_MAC_LEN];
1889281806Srpaulo
1890281806Srpaulo	addr[0] = (u8 *) title;
1891281806Srpaulo	addr[1] = aa;
1892281806Srpaulo	addr[2] = spa;
1893281806Srpaulo
1894281806Srpaulo	if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
1895281806Srpaulo		return -1;
1896281806Srpaulo	os_memcpy(pmkid, hash, PMKID_LEN);
1897281806Srpaulo	return 0;
1898281806Srpaulo}
1899281806Srpaulo#endif /* CONFIG_SUITEB */
1900281806Srpaulo
1901281806Srpaulo
1902281806Srpaulo#ifdef CONFIG_SUITEB192
1903281806Srpaulo/**
1904281806Srpaulo * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
1905281806Srpaulo * @kck: Key confirmation key
1906281806Srpaulo * @kck_len: Length of kck in bytes
1907281806Srpaulo * @aa: Authenticator address
1908281806Srpaulo * @spa: Supplicant address
1909281806Srpaulo * @pmkid: Buffer for PMKID
1910281806Srpaulo * Returns: 0 on success, -1 on failure
1911281806Srpaulo *
1912281806Srpaulo * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1913281806Srpaulo * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
1914281806Srpaulo */
1915281806Srpauloint rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
1916281806Srpaulo			  const u8 *spa, u8 *pmkid)
1917281806Srpaulo{
1918281806Srpaulo	char *title = "PMK Name";
1919281806Srpaulo	const u8 *addr[3];
1920281806Srpaulo	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1921281806Srpaulo	unsigned char hash[SHA384_MAC_LEN];
1922281806Srpaulo
1923281806Srpaulo	addr[0] = (u8 *) title;
1924281806Srpaulo	addr[1] = aa;
1925281806Srpaulo	addr[2] = spa;
1926281806Srpaulo
1927281806Srpaulo	if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
1928281806Srpaulo		return -1;
1929281806Srpaulo	os_memcpy(pmkid, hash, PMKID_LEN);
1930281806Srpaulo	return 0;
1931281806Srpaulo}
1932281806Srpaulo#endif /* CONFIG_SUITEB192 */
1933281806Srpaulo
1934281806Srpaulo
1935281806Srpaulo/**
1936214734Srpaulo * wpa_cipher_txt - Convert cipher suite to a text string
1937214734Srpaulo * @cipher: Cipher suite (WPA_CIPHER_* enum)
1938214734Srpaulo * Returns: Pointer to a text string of the cipher suite name
1939214734Srpaulo */
1940214734Srpauloconst char * wpa_cipher_txt(int cipher)
1941214734Srpaulo{
1942214734Srpaulo	switch (cipher) {
1943214734Srpaulo	case WPA_CIPHER_NONE:
1944214734Srpaulo		return "NONE";
1945214734Srpaulo	case WPA_CIPHER_WEP40:
1946214734Srpaulo		return "WEP-40";
1947214734Srpaulo	case WPA_CIPHER_WEP104:
1948214734Srpaulo		return "WEP-104";
1949214734Srpaulo	case WPA_CIPHER_TKIP:
1950214734Srpaulo		return "TKIP";
1951214734Srpaulo	case WPA_CIPHER_CCMP:
1952214734Srpaulo		return "CCMP";
1953214734Srpaulo	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
1954214734Srpaulo		return "CCMP+TKIP";
1955252726Srpaulo	case WPA_CIPHER_GCMP:
1956252726Srpaulo		return "GCMP";
1957281806Srpaulo	case WPA_CIPHER_GCMP_256:
1958281806Srpaulo		return "GCMP-256";
1959281806Srpaulo	case WPA_CIPHER_CCMP_256:
1960281806Srpaulo		return "CCMP-256";
1961346981Scy	case WPA_CIPHER_AES_128_CMAC:
1962346981Scy		return "BIP";
1963346981Scy	case WPA_CIPHER_BIP_GMAC_128:
1964346981Scy		return "BIP-GMAC-128";
1965346981Scy	case WPA_CIPHER_BIP_GMAC_256:
1966346981Scy		return "BIP-GMAC-256";
1967346981Scy	case WPA_CIPHER_BIP_CMAC_256:
1968346981Scy		return "BIP-CMAC-256";
1969281806Srpaulo	case WPA_CIPHER_GTK_NOT_USED:
1970281806Srpaulo		return "GTK_NOT_USED";
1971214734Srpaulo	default:
1972214734Srpaulo		return "UNKNOWN";
1973214734Srpaulo	}
1974214734Srpaulo}
1975214734Srpaulo
1976214734Srpaulo
1977214734Srpaulo/**
1978214734Srpaulo * wpa_key_mgmt_txt - Convert key management suite to a text string
1979214734Srpaulo * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
1980214734Srpaulo * @proto: WPA/WPA2 version (WPA_PROTO_*)
1981214734Srpaulo * Returns: Pointer to a text string of the key management suite name
1982214734Srpaulo */
1983214734Srpauloconst char * wpa_key_mgmt_txt(int key_mgmt, int proto)
1984214734Srpaulo{
1985214734Srpaulo	switch (key_mgmt) {
1986214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X:
1987214734Srpaulo		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1988214734Srpaulo			return "WPA2+WPA/IEEE 802.1X/EAP";
1989214734Srpaulo		return proto == WPA_PROTO_RSN ?
1990214734Srpaulo			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
1991214734Srpaulo	case WPA_KEY_MGMT_PSK:
1992214734Srpaulo		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1993214734Srpaulo			return "WPA2-PSK+WPA-PSK";
1994214734Srpaulo		return proto == WPA_PROTO_RSN ?
1995214734Srpaulo			"WPA2-PSK" : "WPA-PSK";
1996214734Srpaulo	case WPA_KEY_MGMT_NONE:
1997214734Srpaulo		return "NONE";
1998337817Scy	case WPA_KEY_MGMT_WPA_NONE:
1999337817Scy		return "WPA-NONE";
2000214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
2001214734Srpaulo		return "IEEE 802.1X (no WPA)";
2002214734Srpaulo#ifdef CONFIG_IEEE80211R
2003214734Srpaulo	case WPA_KEY_MGMT_FT_IEEE8021X:
2004214734Srpaulo		return "FT-EAP";
2005346981Scy	case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
2006346981Scy		return "FT-EAP-SHA384";
2007214734Srpaulo	case WPA_KEY_MGMT_FT_PSK:
2008214734Srpaulo		return "FT-PSK";
2009214734Srpaulo#endif /* CONFIG_IEEE80211R */
2010214734Srpaulo#ifdef CONFIG_IEEE80211W
2011214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X_SHA256:
2012214734Srpaulo		return "WPA2-EAP-SHA256";
2013214734Srpaulo	case WPA_KEY_MGMT_PSK_SHA256:
2014214734Srpaulo		return "WPA2-PSK-SHA256";
2015214734Srpaulo#endif /* CONFIG_IEEE80211W */
2016281806Srpaulo	case WPA_KEY_MGMT_WPS:
2017281806Srpaulo		return "WPS";
2018281806Srpaulo	case WPA_KEY_MGMT_SAE:
2019281806Srpaulo		return "SAE";
2020281806Srpaulo	case WPA_KEY_MGMT_FT_SAE:
2021281806Srpaulo		return "FT-SAE";
2022281806Srpaulo	case WPA_KEY_MGMT_OSEN:
2023281806Srpaulo		return "OSEN";
2024281806Srpaulo	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
2025281806Srpaulo		return "WPA2-EAP-SUITE-B";
2026281806Srpaulo	case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
2027281806Srpaulo		return "WPA2-EAP-SUITE-B-192";
2028346981Scy	case WPA_KEY_MGMT_FILS_SHA256:
2029346981Scy		return "FILS-SHA256";
2030346981Scy	case WPA_KEY_MGMT_FILS_SHA384:
2031346981Scy		return "FILS-SHA384";
2032346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA256:
2033346981Scy		return "FT-FILS-SHA256";
2034346981Scy	case WPA_KEY_MGMT_FT_FILS_SHA384:
2035346981Scy		return "FT-FILS-SHA384";
2036346981Scy	case WPA_KEY_MGMT_OWE:
2037346981Scy		return "OWE";
2038346981Scy	case WPA_KEY_MGMT_DPP:
2039346981Scy		return "DPP";
2040214734Srpaulo	default:
2041214734Srpaulo		return "UNKNOWN";
2042214734Srpaulo	}
2043214734Srpaulo}
2044214734Srpaulo
2045214734Srpaulo
2046281806Srpaulou32 wpa_akm_to_suite(int akm)
2047281806Srpaulo{
2048346981Scy	if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
2049346981Scy		return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
2050281806Srpaulo	if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
2051346981Scy		return RSN_AUTH_KEY_MGMT_FT_802_1X;
2052281806Srpaulo	if (akm & WPA_KEY_MGMT_FT_PSK)
2053346981Scy		return RSN_AUTH_KEY_MGMT_FT_PSK;
2054281806Srpaulo	if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
2055346981Scy		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
2056281806Srpaulo	if (akm & WPA_KEY_MGMT_IEEE8021X)
2057346981Scy		return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
2058281806Srpaulo	if (akm & WPA_KEY_MGMT_PSK_SHA256)
2059346981Scy		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
2060281806Srpaulo	if (akm & WPA_KEY_MGMT_PSK)
2061346981Scy		return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
2062281806Srpaulo	if (akm & WPA_KEY_MGMT_CCKM)
2063346981Scy		return RSN_AUTH_KEY_MGMT_CCKM;
2064281806Srpaulo	if (akm & WPA_KEY_MGMT_OSEN)
2065346981Scy		return RSN_AUTH_KEY_MGMT_OSEN;
2066281806Srpaulo	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
2067346981Scy		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
2068281806Srpaulo	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
2069346981Scy		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
2070346981Scy	if (akm & WPA_KEY_MGMT_FILS_SHA256)
2071346981Scy		return RSN_AUTH_KEY_MGMT_FILS_SHA256;
2072346981Scy	if (akm & WPA_KEY_MGMT_FILS_SHA384)
2073346981Scy		return RSN_AUTH_KEY_MGMT_FILS_SHA384;
2074346981Scy	if (akm & WPA_KEY_MGMT_FT_FILS_SHA256)
2075346981Scy		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
2076346981Scy	if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
2077346981Scy		return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
2078351611Scy	if (akm & WPA_KEY_MGMT_SAE)
2079351611Scy		return RSN_AUTH_KEY_MGMT_SAE;
2080351611Scy	if (akm & WPA_KEY_MGMT_FT_SAE)
2081351611Scy		return RSN_AUTH_KEY_MGMT_FT_SAE;
2082351611Scy	if (akm & WPA_KEY_MGMT_OWE)
2083351611Scy		return RSN_AUTH_KEY_MGMT_OWE;
2084351611Scy	if (akm & WPA_KEY_MGMT_DPP)
2085351611Scy		return RSN_AUTH_KEY_MGMT_DPP;
2086351611Scy	if (akm & WPA_KEY_MGMT_OSEN)
2087351611Scy		return RSN_AUTH_KEY_MGMT_OSEN;
2088281806Srpaulo	return 0;
2089281806Srpaulo}
2090281806Srpaulo
2091281806Srpaulo
2092214734Srpauloint wpa_compare_rsn_ie(int ft_initial_assoc,
2093214734Srpaulo		       const u8 *ie1, size_t ie1len,
2094214734Srpaulo		       const u8 *ie2, size_t ie2len)
2095214734Srpaulo{
2096214734Srpaulo	if (ie1 == NULL || ie2 == NULL)
2097214734Srpaulo		return -1;
2098214734Srpaulo
2099214734Srpaulo	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
2100214734Srpaulo		return 0; /* identical IEs */
2101214734Srpaulo
2102214734Srpaulo#ifdef CONFIG_IEEE80211R
2103214734Srpaulo	if (ft_initial_assoc) {
2104214734Srpaulo		struct wpa_ie_data ie1d, ie2d;
2105214734Srpaulo		/*
2106214734Srpaulo		 * The PMKID-List in RSN IE is different between Beacon/Probe
2107214734Srpaulo		 * Response/(Re)Association Request frames and EAPOL-Key
2108214734Srpaulo		 * messages in FT initial mobility domain association. Allow
2109214734Srpaulo		 * for this, but verify that other parts of the RSN IEs are
2110214734Srpaulo		 * identical.
2111214734Srpaulo		 */
2112214734Srpaulo		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
2113214734Srpaulo		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
2114214734Srpaulo			return -1;
2115214734Srpaulo		if (ie1d.proto == ie2d.proto &&
2116214734Srpaulo		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
2117214734Srpaulo		    ie1d.group_cipher == ie2d.group_cipher &&
2118214734Srpaulo		    ie1d.key_mgmt == ie2d.key_mgmt &&
2119214734Srpaulo		    ie1d.capabilities == ie2d.capabilities &&
2120214734Srpaulo		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
2121214734Srpaulo			return 0;
2122214734Srpaulo	}
2123214734Srpaulo#endif /* CONFIG_IEEE80211R */
2124214734Srpaulo
2125214734Srpaulo	return -1;
2126214734Srpaulo}
2127214734Srpaulo
2128214734Srpaulo
2129346981Scy#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
2130337817Scyint wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
2131214734Srpaulo{
2132214734Srpaulo	u8 *start, *end, *rpos, *rend;
2133214734Srpaulo	int added = 0;
2134214734Srpaulo
2135214734Srpaulo	start = ies;
2136337817Scy	end = ies + *ies_len;
2137214734Srpaulo
2138214734Srpaulo	while (start < end) {
2139214734Srpaulo		if (*start == WLAN_EID_RSN)
2140214734Srpaulo			break;
2141214734Srpaulo		start += 2 + start[1];
2142214734Srpaulo	}
2143214734Srpaulo	if (start >= end) {
2144214734Srpaulo		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
2145214734Srpaulo			   "IEs data");
2146214734Srpaulo		return -1;
2147214734Srpaulo	}
2148214734Srpaulo	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
2149214734Srpaulo		    start, 2 + start[1]);
2150214734Srpaulo
2151214734Srpaulo	/* Find start of PMKID-Count */
2152214734Srpaulo	rpos = start + 2;
2153214734Srpaulo	rend = rpos + start[1];
2154214734Srpaulo
2155214734Srpaulo	/* Skip Version and Group Data Cipher Suite */
2156214734Srpaulo	rpos += 2 + 4;
2157214734Srpaulo	/* Skip Pairwise Cipher Suite Count and List */
2158214734Srpaulo	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2159214734Srpaulo	/* Skip AKM Suite Count and List */
2160214734Srpaulo	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2161214734Srpaulo
2162214734Srpaulo	if (rpos == rend) {
2163214734Srpaulo		/* Add RSN Capabilities */
2164214734Srpaulo		os_memmove(rpos + 2, rpos, end - rpos);
2165214734Srpaulo		*rpos++ = 0;
2166214734Srpaulo		*rpos++ = 0;
2167289549Srpaulo		added += 2;
2168289549Srpaulo		start[1] += 2;
2169289549Srpaulo		rend = rpos;
2170214734Srpaulo	} else {
2171214734Srpaulo		/* Skip RSN Capabilities */
2172214734Srpaulo		rpos += 2;
2173214734Srpaulo		if (rpos > rend) {
2174214734Srpaulo			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
2175214734Srpaulo				   "IEs data");
2176214734Srpaulo			return -1;
2177214734Srpaulo		}
2178214734Srpaulo	}
2179214734Srpaulo
2180214734Srpaulo	if (rpos == rend) {
2181214734Srpaulo		/* No PMKID-Count field included; add it */
2182289549Srpaulo		os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
2183214734Srpaulo		WPA_PUT_LE16(rpos, 1);
2184214734Srpaulo		rpos += 2;
2185214734Srpaulo		os_memcpy(rpos, pmkid, PMKID_LEN);
2186214734Srpaulo		added += 2 + PMKID_LEN;
2187214734Srpaulo		start[1] += 2 + PMKID_LEN;
2188214734Srpaulo	} else {
2189337817Scy		u16 num_pmkid;
2190337817Scy
2191337817Scy		if (rend - rpos < 2)
2192337817Scy			return -1;
2193337817Scy		num_pmkid = WPA_GET_LE16(rpos);
2194214734Srpaulo		/* PMKID-Count was included; use it */
2195337817Scy		if (num_pmkid != 0) {
2196337817Scy			u8 *after;
2197337817Scy
2198337817Scy			if (num_pmkid * PMKID_LEN > rend - rpos - 2)
2199337817Scy				return -1;
2200337817Scy			/*
2201337817Scy			 * PMKID may have been included in RSN IE in
2202337817Scy			 * (Re)Association Request frame, so remove the old
2203337817Scy			 * PMKID(s) first before adding the new one.
2204337817Scy			 */
2205337817Scy			wpa_printf(MSG_DEBUG,
2206337817Scy				   "FT: Remove %u old PMKID(s) from RSN IE",
2207337817Scy				   num_pmkid);
2208337817Scy			after = rpos + 2 + num_pmkid * PMKID_LEN;
2209337817Scy			os_memmove(rpos + 2, after, rend - after);
2210337817Scy			start[1] -= num_pmkid * PMKID_LEN;
2211337817Scy			added -= num_pmkid * PMKID_LEN;
2212214734Srpaulo		}
2213214734Srpaulo		WPA_PUT_LE16(rpos, 1);
2214214734Srpaulo		rpos += 2;
2215289549Srpaulo		os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
2216214734Srpaulo		os_memcpy(rpos, pmkid, PMKID_LEN);
2217214734Srpaulo		added += PMKID_LEN;
2218214734Srpaulo		start[1] += PMKID_LEN;
2219214734Srpaulo	}
2220214734Srpaulo
2221214734Srpaulo	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
2222214734Srpaulo		    "(PMKID inserted)", start, 2 + start[1]);
2223214734Srpaulo
2224337817Scy	*ies_len += added;
2225337817Scy
2226337817Scy	return 0;
2227214734Srpaulo}
2228346981Scy#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
2229252726Srpaulo
2230252726Srpaulo
2231252726Srpauloint wpa_cipher_key_len(int cipher)
2232252726Srpaulo{
2233252726Srpaulo	switch (cipher) {
2234281806Srpaulo	case WPA_CIPHER_CCMP_256:
2235281806Srpaulo	case WPA_CIPHER_GCMP_256:
2236281806Srpaulo	case WPA_CIPHER_BIP_GMAC_256:
2237281806Srpaulo	case WPA_CIPHER_BIP_CMAC_256:
2238281806Srpaulo		return 32;
2239252726Srpaulo	case WPA_CIPHER_CCMP:
2240252726Srpaulo	case WPA_CIPHER_GCMP:
2241281806Srpaulo	case WPA_CIPHER_AES_128_CMAC:
2242281806Srpaulo	case WPA_CIPHER_BIP_GMAC_128:
2243252726Srpaulo		return 16;
2244252726Srpaulo	case WPA_CIPHER_TKIP:
2245252726Srpaulo		return 32;
2246252726Srpaulo	}
2247252726Srpaulo
2248252726Srpaulo	return 0;
2249252726Srpaulo}
2250252726Srpaulo
2251252726Srpaulo
2252252726Srpauloint wpa_cipher_rsc_len(int cipher)
2253252726Srpaulo{
2254252726Srpaulo	switch (cipher) {
2255281806Srpaulo	case WPA_CIPHER_CCMP_256:
2256281806Srpaulo	case WPA_CIPHER_GCMP_256:
2257252726Srpaulo	case WPA_CIPHER_CCMP:
2258252726Srpaulo	case WPA_CIPHER_GCMP:
2259252726Srpaulo	case WPA_CIPHER_TKIP:
2260252726Srpaulo		return 6;
2261252726Srpaulo	}
2262252726Srpaulo
2263252726Srpaulo	return 0;
2264252726Srpaulo}
2265252726Srpaulo
2266252726Srpaulo
2267346981Scyenum wpa_alg wpa_cipher_to_alg(int cipher)
2268252726Srpaulo{
2269252726Srpaulo	switch (cipher) {
2270281806Srpaulo	case WPA_CIPHER_CCMP_256:
2271281806Srpaulo		return WPA_ALG_CCMP_256;
2272281806Srpaulo	case WPA_CIPHER_GCMP_256:
2273281806Srpaulo		return WPA_ALG_GCMP_256;
2274252726Srpaulo	case WPA_CIPHER_CCMP:
2275252726Srpaulo		return WPA_ALG_CCMP;
2276252726Srpaulo	case WPA_CIPHER_GCMP:
2277252726Srpaulo		return WPA_ALG_GCMP;
2278252726Srpaulo	case WPA_CIPHER_TKIP:
2279252726Srpaulo		return WPA_ALG_TKIP;
2280281806Srpaulo	case WPA_CIPHER_AES_128_CMAC:
2281281806Srpaulo		return WPA_ALG_IGTK;
2282281806Srpaulo	case WPA_CIPHER_BIP_GMAC_128:
2283281806Srpaulo		return WPA_ALG_BIP_GMAC_128;
2284281806Srpaulo	case WPA_CIPHER_BIP_GMAC_256:
2285281806Srpaulo		return WPA_ALG_BIP_GMAC_256;
2286281806Srpaulo	case WPA_CIPHER_BIP_CMAC_256:
2287281806Srpaulo		return WPA_ALG_BIP_CMAC_256;
2288252726Srpaulo	}
2289252726Srpaulo	return WPA_ALG_NONE;
2290252726Srpaulo}
2291252726Srpaulo
2292252726Srpaulo
2293252726Srpauloint wpa_cipher_valid_pairwise(int cipher)
2294252726Srpaulo{
2295281806Srpaulo	return cipher == WPA_CIPHER_CCMP_256 ||
2296281806Srpaulo		cipher == WPA_CIPHER_GCMP_256 ||
2297281806Srpaulo		cipher == WPA_CIPHER_CCMP ||
2298252726Srpaulo		cipher == WPA_CIPHER_GCMP ||
2299252726Srpaulo		cipher == WPA_CIPHER_TKIP;
2300252726Srpaulo}
2301252726Srpaulo
2302252726Srpaulo
2303252726Srpaulou32 wpa_cipher_to_suite(int proto, int cipher)
2304252726Srpaulo{
2305281806Srpaulo	if (cipher & WPA_CIPHER_CCMP_256)
2306281806Srpaulo		return RSN_CIPHER_SUITE_CCMP_256;
2307281806Srpaulo	if (cipher & WPA_CIPHER_GCMP_256)
2308281806Srpaulo		return RSN_CIPHER_SUITE_GCMP_256;
2309252726Srpaulo	if (cipher & WPA_CIPHER_CCMP)
2310252726Srpaulo		return (proto == WPA_PROTO_RSN ?
2311252726Srpaulo			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
2312252726Srpaulo	if (cipher & WPA_CIPHER_GCMP)
2313252726Srpaulo		return RSN_CIPHER_SUITE_GCMP;
2314252726Srpaulo	if (cipher & WPA_CIPHER_TKIP)
2315252726Srpaulo		return (proto == WPA_PROTO_RSN ?
2316252726Srpaulo			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
2317252726Srpaulo	if (cipher & WPA_CIPHER_NONE)
2318252726Srpaulo		return (proto == WPA_PROTO_RSN ?
2319252726Srpaulo			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
2320281806Srpaulo	if (cipher & WPA_CIPHER_GTK_NOT_USED)
2321281806Srpaulo		return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
2322281806Srpaulo	if (cipher & WPA_CIPHER_AES_128_CMAC)
2323281806Srpaulo		return RSN_CIPHER_SUITE_AES_128_CMAC;
2324281806Srpaulo	if (cipher & WPA_CIPHER_BIP_GMAC_128)
2325281806Srpaulo		return RSN_CIPHER_SUITE_BIP_GMAC_128;
2326281806Srpaulo	if (cipher & WPA_CIPHER_BIP_GMAC_256)
2327281806Srpaulo		return RSN_CIPHER_SUITE_BIP_GMAC_256;
2328281806Srpaulo	if (cipher & WPA_CIPHER_BIP_CMAC_256)
2329281806Srpaulo		return RSN_CIPHER_SUITE_BIP_CMAC_256;
2330252726Srpaulo	return 0;
2331252726Srpaulo}
2332252726Srpaulo
2333252726Srpaulo
2334281806Srpauloint rsn_cipher_put_suites(u8 *start, int ciphers)
2335252726Srpaulo{
2336281806Srpaulo	u8 *pos = start;
2337252726Srpaulo
2338281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP_256) {
2339281806Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
2340281806Srpaulo		pos += RSN_SELECTOR_LEN;
2341281806Srpaulo	}
2342281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP_256) {
2343281806Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
2344281806Srpaulo		pos += RSN_SELECTOR_LEN;
2345281806Srpaulo	}
2346252726Srpaulo	if (ciphers & WPA_CIPHER_CCMP) {
2347252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
2348252726Srpaulo		pos += RSN_SELECTOR_LEN;
2349252726Srpaulo	}
2350252726Srpaulo	if (ciphers & WPA_CIPHER_GCMP) {
2351252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
2352252726Srpaulo		pos += RSN_SELECTOR_LEN;
2353252726Srpaulo	}
2354252726Srpaulo	if (ciphers & WPA_CIPHER_TKIP) {
2355252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
2356252726Srpaulo		pos += RSN_SELECTOR_LEN;
2357252726Srpaulo	}
2358252726Srpaulo	if (ciphers & WPA_CIPHER_NONE) {
2359252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
2360252726Srpaulo		pos += RSN_SELECTOR_LEN;
2361252726Srpaulo	}
2362252726Srpaulo
2363281806Srpaulo	return (pos - start) / RSN_SELECTOR_LEN;
2364252726Srpaulo}
2365252726Srpaulo
2366252726Srpaulo
2367281806Srpauloint wpa_cipher_put_suites(u8 *start, int ciphers)
2368252726Srpaulo{
2369281806Srpaulo	u8 *pos = start;
2370252726Srpaulo
2371252726Srpaulo	if (ciphers & WPA_CIPHER_CCMP) {
2372252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
2373252726Srpaulo		pos += WPA_SELECTOR_LEN;
2374252726Srpaulo	}
2375252726Srpaulo	if (ciphers & WPA_CIPHER_TKIP) {
2376252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
2377252726Srpaulo		pos += WPA_SELECTOR_LEN;
2378252726Srpaulo	}
2379252726Srpaulo	if (ciphers & WPA_CIPHER_NONE) {
2380252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
2381252726Srpaulo		pos += WPA_SELECTOR_LEN;
2382252726Srpaulo	}
2383252726Srpaulo
2384281806Srpaulo	return (pos - start) / RSN_SELECTOR_LEN;
2385252726Srpaulo}
2386281806Srpaulo
2387281806Srpaulo
2388281806Srpauloint wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
2389281806Srpaulo{
2390281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP_256)
2391281806Srpaulo		return WPA_CIPHER_CCMP_256;
2392281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP_256)
2393281806Srpaulo		return WPA_CIPHER_GCMP_256;
2394281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP)
2395281806Srpaulo		return WPA_CIPHER_CCMP;
2396281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP)
2397281806Srpaulo		return WPA_CIPHER_GCMP;
2398281806Srpaulo	if (ciphers & WPA_CIPHER_TKIP)
2399281806Srpaulo		return WPA_CIPHER_TKIP;
2400281806Srpaulo	if (none_allowed && (ciphers & WPA_CIPHER_NONE))
2401281806Srpaulo		return WPA_CIPHER_NONE;
2402281806Srpaulo	return -1;
2403281806Srpaulo}
2404281806Srpaulo
2405281806Srpaulo
2406281806Srpauloint wpa_pick_group_cipher(int ciphers)
2407281806Srpaulo{
2408281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP_256)
2409281806Srpaulo		return WPA_CIPHER_CCMP_256;
2410281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP_256)
2411281806Srpaulo		return WPA_CIPHER_GCMP_256;
2412281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP)
2413281806Srpaulo		return WPA_CIPHER_CCMP;
2414281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP)
2415281806Srpaulo		return WPA_CIPHER_GCMP;
2416281806Srpaulo	if (ciphers & WPA_CIPHER_GTK_NOT_USED)
2417281806Srpaulo		return WPA_CIPHER_GTK_NOT_USED;
2418281806Srpaulo	if (ciphers & WPA_CIPHER_TKIP)
2419281806Srpaulo		return WPA_CIPHER_TKIP;
2420281806Srpaulo	return -1;
2421281806Srpaulo}
2422281806Srpaulo
2423281806Srpaulo
2424281806Srpauloint wpa_parse_cipher(const char *value)
2425281806Srpaulo{
2426281806Srpaulo	int val = 0, last;
2427281806Srpaulo	char *start, *end, *buf;
2428281806Srpaulo
2429281806Srpaulo	buf = os_strdup(value);
2430281806Srpaulo	if (buf == NULL)
2431281806Srpaulo		return -1;
2432281806Srpaulo	start = buf;
2433281806Srpaulo
2434281806Srpaulo	while (*start != '\0') {
2435281806Srpaulo		while (*start == ' ' || *start == '\t')
2436281806Srpaulo			start++;
2437281806Srpaulo		if (*start == '\0')
2438281806Srpaulo			break;
2439281806Srpaulo		end = start;
2440281806Srpaulo		while (*end != ' ' && *end != '\t' && *end != '\0')
2441281806Srpaulo			end++;
2442281806Srpaulo		last = *end == '\0';
2443281806Srpaulo		*end = '\0';
2444281806Srpaulo		if (os_strcmp(start, "CCMP-256") == 0)
2445281806Srpaulo			val |= WPA_CIPHER_CCMP_256;
2446281806Srpaulo		else if (os_strcmp(start, "GCMP-256") == 0)
2447281806Srpaulo			val |= WPA_CIPHER_GCMP_256;
2448281806Srpaulo		else if (os_strcmp(start, "CCMP") == 0)
2449281806Srpaulo			val |= WPA_CIPHER_CCMP;
2450281806Srpaulo		else if (os_strcmp(start, "GCMP") == 0)
2451281806Srpaulo			val |= WPA_CIPHER_GCMP;
2452281806Srpaulo		else if (os_strcmp(start, "TKIP") == 0)
2453281806Srpaulo			val |= WPA_CIPHER_TKIP;
2454281806Srpaulo		else if (os_strcmp(start, "WEP104") == 0)
2455281806Srpaulo			val |= WPA_CIPHER_WEP104;
2456281806Srpaulo		else if (os_strcmp(start, "WEP40") == 0)
2457281806Srpaulo			val |= WPA_CIPHER_WEP40;
2458281806Srpaulo		else if (os_strcmp(start, "NONE") == 0)
2459281806Srpaulo			val |= WPA_CIPHER_NONE;
2460281806Srpaulo		else if (os_strcmp(start, "GTK_NOT_USED") == 0)
2461281806Srpaulo			val |= WPA_CIPHER_GTK_NOT_USED;
2462346981Scy		else if (os_strcmp(start, "AES-128-CMAC") == 0)
2463346981Scy			val |= WPA_CIPHER_AES_128_CMAC;
2464346981Scy		else if (os_strcmp(start, "BIP-GMAC-128") == 0)
2465346981Scy			val |= WPA_CIPHER_BIP_GMAC_128;
2466346981Scy		else if (os_strcmp(start, "BIP-GMAC-256") == 0)
2467346981Scy			val |= WPA_CIPHER_BIP_GMAC_256;
2468346981Scy		else if (os_strcmp(start, "BIP-CMAC-256") == 0)
2469346981Scy			val |= WPA_CIPHER_BIP_CMAC_256;
2470281806Srpaulo		else {
2471281806Srpaulo			os_free(buf);
2472281806Srpaulo			return -1;
2473281806Srpaulo		}
2474281806Srpaulo
2475281806Srpaulo		if (last)
2476281806Srpaulo			break;
2477281806Srpaulo		start = end + 1;
2478281806Srpaulo	}
2479281806Srpaulo	os_free(buf);
2480281806Srpaulo
2481281806Srpaulo	return val;
2482281806Srpaulo}
2483281806Srpaulo
2484281806Srpaulo
2485281806Srpauloint wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
2486281806Srpaulo{
2487281806Srpaulo	char *pos = start;
2488281806Srpaulo	int ret;
2489281806Srpaulo
2490281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP_256) {
2491281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
2492281806Srpaulo				  pos == start ? "" : delim);
2493281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2494281806Srpaulo			return -1;
2495281806Srpaulo		pos += ret;
2496281806Srpaulo	}
2497281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP_256) {
2498281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
2499281806Srpaulo				  pos == start ? "" : delim);
2500281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2501281806Srpaulo			return -1;
2502281806Srpaulo		pos += ret;
2503281806Srpaulo	}
2504281806Srpaulo	if (ciphers & WPA_CIPHER_CCMP) {
2505281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sCCMP",
2506281806Srpaulo				  pos == start ? "" : delim);
2507281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2508281806Srpaulo			return -1;
2509281806Srpaulo		pos += ret;
2510281806Srpaulo	}
2511281806Srpaulo	if (ciphers & WPA_CIPHER_GCMP) {
2512281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sGCMP",
2513281806Srpaulo				  pos == start ? "" : delim);
2514281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2515281806Srpaulo			return -1;
2516281806Srpaulo		pos += ret;
2517281806Srpaulo	}
2518281806Srpaulo	if (ciphers & WPA_CIPHER_TKIP) {
2519281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sTKIP",
2520281806Srpaulo				  pos == start ? "" : delim);
2521281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2522281806Srpaulo			return -1;
2523281806Srpaulo		pos += ret;
2524281806Srpaulo	}
2525346981Scy	if (ciphers & WPA_CIPHER_AES_128_CMAC) {
2526346981Scy		ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC",
2527346981Scy				  pos == start ? "" : delim);
2528346981Scy		if (os_snprintf_error(end - pos, ret))
2529346981Scy			return -1;
2530346981Scy		pos += ret;
2531346981Scy	}
2532346981Scy	if (ciphers & WPA_CIPHER_BIP_GMAC_128) {
2533346981Scy		ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
2534346981Scy				  pos == start ? "" : delim);
2535346981Scy		if (os_snprintf_error(end - pos, ret))
2536346981Scy			return -1;
2537346981Scy		pos += ret;
2538346981Scy	}
2539346981Scy	if (ciphers & WPA_CIPHER_BIP_GMAC_256) {
2540346981Scy		ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
2541346981Scy				  pos == start ? "" : delim);
2542346981Scy		if (os_snprintf_error(end - pos, ret))
2543346981Scy			return -1;
2544346981Scy		pos += ret;
2545346981Scy	}
2546346981Scy	if (ciphers & WPA_CIPHER_BIP_CMAC_256) {
2547346981Scy		ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
2548346981Scy				  pos == start ? "" : delim);
2549346981Scy		if (os_snprintf_error(end - pos, ret))
2550346981Scy			return -1;
2551346981Scy		pos += ret;
2552346981Scy	}
2553281806Srpaulo	if (ciphers & WPA_CIPHER_NONE) {
2554281806Srpaulo		ret = os_snprintf(pos, end - pos, "%sNONE",
2555281806Srpaulo				  pos == start ? "" : delim);
2556281806Srpaulo		if (os_snprintf_error(end - pos, ret))
2557281806Srpaulo			return -1;
2558281806Srpaulo		pos += ret;
2559281806Srpaulo	}
2560281806Srpaulo
2561281806Srpaulo	return pos - start;
2562281806Srpaulo}
2563281806Srpaulo
2564281806Srpaulo
2565281806Srpauloint wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
2566281806Srpaulo{
2567281806Srpaulo	int pairwise = 0;
2568281806Srpaulo
2569281806Srpaulo	/* Select group cipher based on the enabled pairwise cipher suites */
2570281806Srpaulo	if (wpa & 1)
2571281806Srpaulo		pairwise |= wpa_pairwise;
2572281806Srpaulo	if (wpa & 2)
2573281806Srpaulo		pairwise |= rsn_pairwise;
2574281806Srpaulo
2575281806Srpaulo	if (pairwise & WPA_CIPHER_TKIP)
2576281806Srpaulo		return WPA_CIPHER_TKIP;
2577281806Srpaulo	if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
2578281806Srpaulo		return WPA_CIPHER_GCMP;
2579281806Srpaulo	if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
2580281806Srpaulo			 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
2581281806Srpaulo		return WPA_CIPHER_GCMP_256;
2582281806Srpaulo	if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
2583281806Srpaulo			 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
2584281806Srpaulo		return WPA_CIPHER_CCMP_256;
2585281806Srpaulo	return WPA_CIPHER_CCMP;
2586281806Srpaulo}
2587346981Scy
2588346981Scy
2589346981Scy#ifdef CONFIG_FILS
2590346981Scyint fils_domain_name_hash(const char *domain, u8 *hash)
2591346981Scy{
2592346981Scy	char buf[255], *wpos = buf;
2593346981Scy	const char *pos = domain;
2594346981Scy	size_t len;
2595346981Scy	const u8 *addr[1];
2596346981Scy	u8 mac[SHA256_MAC_LEN];
2597346981Scy
2598346981Scy	for (len = 0; len < sizeof(buf) && *pos; len++) {
2599346981Scy		if (isalpha(*pos) && isupper(*pos))
2600346981Scy			*wpos++ = tolower(*pos);
2601346981Scy		else
2602346981Scy			*wpos++ = *pos;
2603346981Scy		pos++;
2604346981Scy	}
2605346981Scy
2606346981Scy	addr[0] = (const u8 *) buf;
2607346981Scy	if (sha256_vector(1, addr, &len, mac) < 0)
2608346981Scy		return -1;
2609346981Scy	os_memcpy(hash, mac, 2);
2610346981Scy	return 0;
2611346981Scy}
2612346981Scy#endif /* CONFIG_FILS */
2613