blob: ea9f7a21ceb7d4097c3669285b349951a6e64b11 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA/RSN - Shared functions for supplicant and authenticator
Roshan Pius3a1667e2018-07-03 15:17:14 -07003 * Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto/md5.h"
13#include "crypto/sha1.h"
14#include "crypto/sha256.h"
Dmitry Shmidt807291d2015-01-27 13:40:23 -080015#include "crypto/sha384.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070016#include "crypto/sha512.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "crypto/aes_wrap.h"
18#include "crypto/crypto.h"
19#include "ieee802_11_defs.h"
20#include "defs.h"
21#include "wpa_common.h"
22
23
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070024static unsigned int wpa_kck_len(int akmp, size_t pmk_len)
Dmitry Shmidt807291d2015-01-27 13:40:23 -080025{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080026 switch (akmp) {
27 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Roshan Pius3a1667e2018-07-03 15:17:14 -070028 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
Dmitry Shmidt807291d2015-01-27 13:40:23 -080029 return 24;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080030 case WPA_KEY_MGMT_FILS_SHA256:
31 case WPA_KEY_MGMT_FT_FILS_SHA256:
32 case WPA_KEY_MGMT_FILS_SHA384:
33 case WPA_KEY_MGMT_FT_FILS_SHA384:
34 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070035 case WPA_KEY_MGMT_DPP:
36 return pmk_len / 2;
37 case WPA_KEY_MGMT_OWE:
38 return pmk_len / 2;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080039 default:
40 return 16;
41 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -080042}
43
44
Roshan Pius3a1667e2018-07-03 15:17:14 -070045#ifdef CONFIG_IEEE80211R
46static unsigned int wpa_kck2_len(int akmp)
47{
48 switch (akmp) {
49 case WPA_KEY_MGMT_FT_FILS_SHA256:
50 return 16;
51 case WPA_KEY_MGMT_FT_FILS_SHA384:
52 return 24;
53 default:
54 return 0;
55 }
56}
57#endif /* CONFIG_IEEE80211R */
58
59
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070060static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
Dmitry Shmidt807291d2015-01-27 13:40:23 -080061{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080062 switch (akmp) {
63 case WPA_KEY_MGMT_FILS_SHA384:
64 case WPA_KEY_MGMT_FT_FILS_SHA384:
65 return 64;
66 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
67 case WPA_KEY_MGMT_FILS_SHA256:
68 case WPA_KEY_MGMT_FT_FILS_SHA256:
Roshan Pius3a1667e2018-07-03 15:17:14 -070069 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
Dmitry Shmidt807291d2015-01-27 13:40:23 -080070 return 32;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070071 case WPA_KEY_MGMT_DPP:
72 return pmk_len <= 32 ? 16 : 32;
73 case WPA_KEY_MGMT_OWE:
74 return pmk_len <= 32 ? 16 : 32;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080075 default:
76 return 16;
77 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -080078}
79
80
Roshan Pius3a1667e2018-07-03 15:17:14 -070081#ifdef CONFIG_IEEE80211R
82static unsigned int wpa_kek2_len(int akmp)
83{
84 switch (akmp) {
85 case WPA_KEY_MGMT_FT_FILS_SHA256:
86 return 16;
87 case WPA_KEY_MGMT_FT_FILS_SHA384:
88 return 32;
89 default:
90 return 0;
91 }
92}
93#endif /* CONFIG_IEEE80211R */
94
95
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070096unsigned int wpa_mic_len(int akmp, size_t pmk_len)
Dmitry Shmidt807291d2015-01-27 13:40:23 -080097{
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -080098 switch (akmp) {
99 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Roshan Pius3a1667e2018-07-03 15:17:14 -0700100 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800101 return 24;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800102 case WPA_KEY_MGMT_FILS_SHA256:
103 case WPA_KEY_MGMT_FILS_SHA384:
104 case WPA_KEY_MGMT_FT_FILS_SHA256:
105 case WPA_KEY_MGMT_FT_FILS_SHA384:
106 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700107 case WPA_KEY_MGMT_DPP:
108 return pmk_len / 2;
109 case WPA_KEY_MGMT_OWE:
110 return pmk_len / 2;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800111 default:
112 return 16;
113 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800114}
115
116
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117/**
Roshan Pius3a1667e2018-07-03 15:17:14 -0700118 * wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
119 * @akmp: WPA_KEY_MGMT_* used in key derivation
120 * Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
121 */
122int wpa_use_akm_defined(int akmp)
123{
124 return akmp == WPA_KEY_MGMT_OSEN ||
125 akmp == WPA_KEY_MGMT_OWE ||
126 akmp == WPA_KEY_MGMT_DPP ||
127 akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
128 wpa_key_mgmt_sae(akmp) ||
129 wpa_key_mgmt_suite_b(akmp) ||
130 wpa_key_mgmt_fils(akmp);
131}
132
133
134/**
135 * wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
136 * @akmp: WPA_KEY_MGMT_* used in key derivation
137 * Returns: 1 if CMAC is used; 0 otherwise
138 */
139int wpa_use_cmac(int akmp)
140{
141 return akmp == WPA_KEY_MGMT_OSEN ||
142 akmp == WPA_KEY_MGMT_OWE ||
143 akmp == WPA_KEY_MGMT_DPP ||
144 wpa_key_mgmt_ft(akmp) ||
145 wpa_key_mgmt_sha256(akmp) ||
146 wpa_key_mgmt_sae(akmp) ||
147 wpa_key_mgmt_suite_b(akmp);
148}
149
150
151/**
152 * wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
153 * @akmp: WPA_KEY_MGMT_* used in key derivation
154 * Returns: 1 if AES Keywrap is used; 0 otherwise
155 *
156 * Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
157 * to use AES Keywrap based on the negotiated pairwise cipher. This function
158 * does not cover those special cases.
159 */
160int wpa_use_aes_key_wrap(int akmp)
161{
162 return akmp == WPA_KEY_MGMT_OSEN ||
163 akmp == WPA_KEY_MGMT_OWE ||
164 akmp == WPA_KEY_MGMT_DPP ||
165 wpa_key_mgmt_ft(akmp) ||
166 wpa_key_mgmt_sha256(akmp) ||
167 wpa_key_mgmt_sae(akmp) ||
168 wpa_key_mgmt_suite_b(akmp);
169}
170
171
172/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700173 * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
174 * @key: EAPOL-Key Key Confirmation Key (KCK)
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800175 * @key_len: KCK length in octets
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800176 * @akmp: WPA_KEY_MGMT_* used in key derivation
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700177 * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
178 * @buf: Pointer to the beginning of the EAPOL header (version field)
179 * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
180 * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
181 * Returns: 0 on success, -1 on failure
182 *
183 * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
184 * to be cleared (all zeroes) when calling this function.
185 *
186 * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
187 * description of the Key MIC calculation. It includes packet data from the
188 * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
189 * happened during final editing of the standard and the correct behavior is
190 * defined in the last draft (IEEE 802.11i/D10).
191 */
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800192int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
193 const u8 *buf, size_t len, u8 *mic)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700194{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700195 u8 hash[SHA512_MAC_LEN];
196
197 if (key_len == 0) {
198 wpa_printf(MSG_DEBUG,
199 "WPA: KCK not set - cannot calculate MIC");
200 return -1;
201 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700202
203 switch (ver) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700204#ifndef CONFIG_FIPS
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700205 case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700206 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-MD5");
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800207 return hmac_md5(key, key_len, buf, len, mic);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700208#endif /* CONFIG_FIPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700209 case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700210 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA1");
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800211 if (hmac_sha1(key, key_len, buf, len, hash))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700212 return -1;
213 os_memcpy(mic, hash, MD5_MAC_LEN);
214 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700215 case WPA_KEY_INFO_TYPE_AES_128_CMAC:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700216 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using AES-CMAC");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 return omac1_aes_128(key, buf, len, mic);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800218 case WPA_KEY_INFO_TYPE_AKM_DEFINED:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800219 switch (akmp) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700220#ifdef CONFIG_SAE
221 case WPA_KEY_MGMT_SAE:
222 case WPA_KEY_MGMT_FT_SAE:
223 wpa_printf(MSG_DEBUG,
224 "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
225 return omac1_aes_128(key, buf, len, mic);
226#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800227#ifdef CONFIG_HS20
228 case WPA_KEY_MGMT_OSEN:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700229 wpa_printf(MSG_DEBUG,
230 "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800231 return omac1_aes_128(key, buf, len, mic);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800232#endif /* CONFIG_HS20 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800233#ifdef CONFIG_SUITEB
234 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700235 wpa_printf(MSG_DEBUG,
236 "WPA: EAPOL-Key MIC using HMAC-SHA256 (AKM-defined - Suite B)");
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800237 if (hmac_sha256(key, key_len, buf, len, hash))
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800238 return -1;
239 os_memcpy(mic, hash, MD5_MAC_LEN);
240 break;
241#endif /* CONFIG_SUITEB */
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800242#ifdef CONFIG_SUITEB192
243 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700244 wpa_printf(MSG_DEBUG,
245 "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - Suite B 192-bit)");
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800246 if (hmac_sha384(key, key_len, buf, len, hash))
247 return -1;
248 os_memcpy(mic, hash, 24);
249 break;
250#endif /* CONFIG_SUITEB192 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700251#ifdef CONFIG_OWE
252 case WPA_KEY_MGMT_OWE:
253 wpa_printf(MSG_DEBUG,
254 "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - OWE)",
255 (unsigned int) key_len * 8 * 2);
256 if (key_len == 128 / 8) {
257 if (hmac_sha256(key, key_len, buf, len, hash))
258 return -1;
259 } else if (key_len == 192 / 8) {
260 if (hmac_sha384(key, key_len, buf, len, hash))
261 return -1;
262 } else if (key_len == 256 / 8) {
263 if (hmac_sha512(key, key_len, buf, len, hash))
264 return -1;
265 } else {
266 wpa_printf(MSG_INFO,
267 "OWE: Unsupported KCK length: %u",
268 (unsigned int) key_len);
269 return -1;
270 }
271 os_memcpy(mic, hash, key_len);
272 break;
273#endif /* CONFIG_OWE */
274#ifdef CONFIG_DPP
275 case WPA_KEY_MGMT_DPP:
276 wpa_printf(MSG_DEBUG,
277 "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - DPP)",
278 (unsigned int) key_len * 8 * 2);
279 if (key_len == 128 / 8) {
280 if (hmac_sha256(key, key_len, buf, len, hash))
281 return -1;
282 } else if (key_len == 192 / 8) {
283 if (hmac_sha384(key, key_len, buf, len, hash))
284 return -1;
285 } else if (key_len == 256 / 8) {
286 if (hmac_sha512(key, key_len, buf, len, hash))
287 return -1;
288 } else {
289 wpa_printf(MSG_INFO,
290 "DPP: Unsupported KCK length: %u",
291 (unsigned int) key_len);
292 return -1;
293 }
294 os_memcpy(mic, hash, key_len);
295 break;
296#endif /* CONFIG_DPP */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700297#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384)
298 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
299 wpa_printf(MSG_DEBUG,
300 "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)");
301 if (hmac_sha384(key, key_len, buf, len, hash))
302 return -1;
303 os_memcpy(mic, hash, 24);
304 break;
305#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800306 default:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700307 wpa_printf(MSG_DEBUG,
308 "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)",
309 akmp);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800310 return -1;
311 }
312 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700313 default:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700314 wpa_printf(MSG_DEBUG,
315 "WPA: EAPOL-Key MIC algorithm not known (ver=%d)",
316 ver);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700317 return -1;
318 }
319
320 return 0;
321}
322
323
324/**
325 * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
326 * @pmk: Pairwise master key
327 * @pmk_len: Length of PMK
328 * @label: Label to use in derivation
329 * @addr1: AA or SA
330 * @addr2: SA or AA
331 * @nonce1: ANonce or SNonce
332 * @nonce2: SNonce or ANonce
333 * @ptk: Buffer for pairwise transient key
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800334 * @akmp: Negotiated AKM
335 * @cipher: Negotiated pairwise cipher
336 * Returns: 0 on success, -1 on failure
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700337 *
338 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
339 * PTK = PRF-X(PMK, "Pairwise key expansion",
340 * Min(AA, SA) || Max(AA, SA) ||
Hai Shalom021b0b52019-04-10 11:17:58 -0700341 * Min(ANonce, SNonce) || Max(ANonce, SNonce)
342 * [ || Z.x ])
343 *
344 * The optional Z.x component is used only with DPP and that part is not defined
345 * in IEEE 802.11.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346 */
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800347int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
348 const u8 *addr1, const u8 *addr2,
349 const u8 *nonce1, const u8 *nonce2,
Hai Shalom021b0b52019-04-10 11:17:58 -0700350 struct wpa_ptk *ptk, int akmp, int cipher,
351 const u8 *z, size_t z_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700352{
Hai Shalom021b0b52019-04-10 11:17:58 -0700353#define MAX_Z_LEN 66 /* with NIST P-521 */
354 u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
355 size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800356 u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
357 size_t ptk_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700359 if (pmk_len == 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700360 wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700361 return -1;
362 }
363
Hai Shalom021b0b52019-04-10 11:17:58 -0700364 if (z_len > MAX_Z_LEN)
365 return -1;
366
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700367 if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
368 os_memcpy(data, addr1, ETH_ALEN);
369 os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
370 } else {
371 os_memcpy(data, addr2, ETH_ALEN);
372 os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
373 }
374
375 if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
376 os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
377 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
378 WPA_NONCE_LEN);
379 } else {
380 os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
381 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
382 WPA_NONCE_LEN);
383 }
384
Hai Shalom021b0b52019-04-10 11:17:58 -0700385 if (z && z_len) {
386 os_memcpy(data + 2 * ETH_ALEN + 2 * WPA_NONCE_LEN, z, z_len);
387 data_len += z_len;
388 }
389
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700390 ptk->kck_len = wpa_kck_len(akmp, pmk_len);
391 ptk->kek_len = wpa_kek_len(akmp, pmk_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800392 ptk->tk_len = wpa_cipher_key_len(cipher);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700393 if (ptk->tk_len == 0) {
394 wpa_printf(MSG_ERROR,
395 "WPA: Unsupported cipher (0x%x) used in PTK derivation",
396 cipher);
397 return -1;
398 }
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800399 ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
400
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700401 if (wpa_key_mgmt_sha384(akmp)) {
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800402#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700403 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700404 if (sha384_prf(pmk, pmk_len, label, data, data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700405 tmp, ptk_len) < 0)
406 return -1;
407#else /* CONFIG_SUITEB192 || CONFIG_FILS */
408 return -1;
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800409#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700410 } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700411 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700412 if (sha256_prf(pmk, pmk_len, label, data, data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700413 tmp, ptk_len) < 0)
414 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700415#ifdef CONFIG_DPP
416 } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) {
417 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700418 if (sha256_prf(pmk, pmk_len, label, data, data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700419 tmp, ptk_len) < 0)
420 return -1;
421 } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 48) {
422 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700423 if (sha384_prf(pmk, pmk_len, label, data, data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700424 tmp, ptk_len) < 0)
425 return -1;
426 } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 64) {
427 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700428 if (sha512_prf(pmk, pmk_len, label, data, data_len,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700429 tmp, ptk_len) < 0)
430 return -1;
431 } else if (akmp == WPA_KEY_MGMT_DPP) {
432 wpa_printf(MSG_INFO, "DPP: Unknown PMK length %u",
433 (unsigned int) pmk_len);
434 return -1;
435#endif /* CONFIG_DPP */
436 } else {
437 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
Hai Shalom021b0b52019-04-10 11:17:58 -0700438 if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700439 ptk_len) < 0)
440 return -1;
441 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700442
443 wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
444 MAC2STR(addr1), MAC2STR(addr2));
445 wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
446 wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -0700447 if (z && z_len)
448 wpa_hexdump_key(MSG_DEBUG, "WPA: Z.x", z, z_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700449 wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800450 wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
451
452 os_memcpy(ptk->kck, tmp, ptk->kck_len);
453 wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
454
455 os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
456 wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
457
458 os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
459 wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
460
Roshan Pius3a1667e2018-07-03 15:17:14 -0700461 ptk->kek2_len = 0;
462 ptk->kck2_len = 0;
463
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800464 os_memset(tmp, 0, sizeof(tmp));
Hai Shalom021b0b52019-04-10 11:17:58 -0700465 os_memset(data, 0, data_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800466 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700467}
468
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800469#ifdef CONFIG_FILS
470
Paul Stewart092955c2017-02-06 09:13:09 -0800471int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
472 const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
473 size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
474{
475 u8 nonces[2 * FILS_NONCE_LEN];
476 const u8 *addr[2];
477 size_t len[2];
478 size_t num_elem;
479 int res;
480
481 /* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
482 wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
483
484 if (wpa_key_mgmt_sha384(akmp))
485 *pmk_len = SHA384_MAC_LEN;
486 else if (wpa_key_mgmt_sha256(akmp))
487 *pmk_len = SHA256_MAC_LEN;
488 else
489 return -1;
490
491 wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
492 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
493 wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
494 wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
495
496 os_memcpy(nonces, snonce, FILS_NONCE_LEN);
497 os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
498 addr[0] = rmsk;
499 len[0] = rmsk_len;
500 num_elem = 1;
501 if (dh_ss) {
502 addr[1] = dh_ss;
503 len[1] = dh_ss_len;
504 num_elem++;
505 }
506 if (wpa_key_mgmt_sha384(akmp))
507 res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
508 addr, len, pmk);
509 else
510 res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
511 addr, len, pmk);
512 if (res == 0)
513 wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700514 else
515 *pmk_len = 0;
Paul Stewart092955c2017-02-06 09:13:09 -0800516 return res;
517}
518
519
520int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
521 u8 *pmkid)
522{
523 const u8 *addr[1];
524 size_t len[1];
525 u8 hash[SHA384_MAC_LEN];
526 int res;
527
528 /* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
529 addr[0] = reauth;
530 len[0] = reauth_len;
531 if (wpa_key_mgmt_sha384(akmp))
532 res = sha384_vector(1, addr, len, hash);
533 else if (wpa_key_mgmt_sha256(akmp))
534 res = sha256_vector(1, addr, len, hash);
535 else
536 return -1;
537 if (res)
538 return res;
539 os_memcpy(pmkid, hash, PMKID_LEN);
540 wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
541 return 0;
542}
543
544
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800545int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700546 const u8 *snonce, const u8 *anonce, const u8 *dhss,
547 size_t dhss_len, struct wpa_ptk *ptk,
548 u8 *ick, size_t *ick_len, int akmp, int cipher,
549 u8 *fils_ft, size_t *fils_ft_len)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800550{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700551 u8 *data, *pos;
552 size_t data_len;
553 u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
554 FILS_FT_MAX_LEN];
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800555 size_t key_data_len;
556 const char *label = "FILS PTK Derivation";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700557 int ret = -1;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800558
559 /*
560 * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700561 * SPA || AA || SNonce || ANonce [ || DHss ])
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800562 * ICK = L(FILS-Key-Data, 0, ICK_bits)
563 * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits)
564 * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits)
565 * If doing FT initial mobility domain association:
566 * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
567 * FILS-FT_bits)
568 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700569 data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
570 data = os_malloc(data_len);
571 if (!data)
572 goto err;
573 pos = data;
574 os_memcpy(pos, spa, ETH_ALEN);
575 pos += ETH_ALEN;
576 os_memcpy(pos, aa, ETH_ALEN);
577 pos += ETH_ALEN;
578 os_memcpy(pos, snonce, FILS_NONCE_LEN);
579 pos += FILS_NONCE_LEN;
580 os_memcpy(pos, anonce, FILS_NONCE_LEN);
581 pos += FILS_NONCE_LEN;
582 if (dhss)
583 os_memcpy(pos, dhss, dhss_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800584
585 ptk->kck_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700586 ptk->kek_len = wpa_kek_len(akmp, pmk_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800587 ptk->tk_len = wpa_cipher_key_len(cipher);
588 if (wpa_key_mgmt_sha384(akmp))
589 *ick_len = 48;
590 else if (wpa_key_mgmt_sha256(akmp))
591 *ick_len = 32;
592 else
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700593 goto err;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800594 key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
595
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700596 if (fils_ft && fils_ft_len) {
597 if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
598 *fils_ft_len = 32;
599 } else if (akmp == WPA_KEY_MGMT_FT_FILS_SHA384) {
600 *fils_ft_len = 48;
601 } else {
602 *fils_ft_len = 0;
603 fils_ft = NULL;
604 }
605 key_data_len += *fils_ft_len;
606 }
607
608 if (wpa_key_mgmt_sha384(akmp)) {
609 wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA384)");
610 if (sha384_prf(pmk, pmk_len, label, data, data_len,
611 tmp, key_data_len) < 0)
612 goto err;
613 } else {
614 wpa_printf(MSG_DEBUG, "FILS: PTK derivation using PRF(SHA256)");
615 if (sha256_prf(pmk, pmk_len, label, data, data_len,
616 tmp, key_data_len) < 0)
617 goto err;
618 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800619
620 wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR
621 " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa));
622 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
623 wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700624 if (dhss)
625 wpa_hexdump_key(MSG_DEBUG, "FILS: DHss", dhss, dhss_len);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800626 wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len);
627 wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
628
629 os_memcpy(ick, tmp, *ick_len);
630 wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
631
632 os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
633 wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
634
635 os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
636 wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
637
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700638 if (fils_ft && fils_ft_len) {
639 os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
640 *fils_ft_len);
641 wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
642 fils_ft, *fils_ft_len);
643 }
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800644
Roshan Pius3a1667e2018-07-03 15:17:14 -0700645 ptk->kek2_len = 0;
646 ptk->kck2_len = 0;
647
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800648 os_memset(tmp, 0, sizeof(tmp));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700649 ret = 0;
650err:
651 bin_clear_free(data, data_len);
652 return ret;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800653}
654
655
656int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
657 const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
658 const u8 *g_sta, size_t g_sta_len,
659 const u8 *g_ap, size_t g_ap_len,
660 int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
661 size_t *key_auth_len)
662{
663 const u8 *addr[6];
664 size_t len[6];
665 size_t num_elem = 4;
666 int res;
667
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700668 wpa_printf(MSG_DEBUG, "FILS: Key-Auth derivation: STA-MAC=" MACSTR
669 " AP-BSSID=" MACSTR, MAC2STR(sta_addr), MAC2STR(bssid));
670 wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, ick_len);
671 wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
672 wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
673 wpa_hexdump(MSG_DEBUG, "FILS: gSTA", g_sta, g_sta_len);
674 wpa_hexdump(MSG_DEBUG, "FILS: gAP", g_ap, g_ap_len);
675
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800676 /*
677 * For (Re)Association Request frame (STA->AP):
678 * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID
679 * [ || gSTA || gAP ])
680 */
681 addr[0] = snonce;
682 len[0] = FILS_NONCE_LEN;
683 addr[1] = anonce;
684 len[1] = FILS_NONCE_LEN;
685 addr[2] = sta_addr;
686 len[2] = ETH_ALEN;
687 addr[3] = bssid;
688 len[3] = ETH_ALEN;
Hai Shalomc3565922019-10-28 11:58:20 -0700689 if (g_sta && g_sta_len && g_ap && g_ap_len) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800690 addr[4] = g_sta;
691 len[4] = g_sta_len;
692 addr[5] = g_ap;
693 len[5] = g_ap_len;
694 num_elem = 6;
695 }
696
697 if (wpa_key_mgmt_sha384(akmp)) {
698 *key_auth_len = 48;
699 res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
700 key_auth_sta);
701 } else if (wpa_key_mgmt_sha256(akmp)) {
702 *key_auth_len = 32;
703 res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
704 key_auth_sta);
705 } else {
706 return -1;
707 }
708 if (res < 0)
709 return res;
710
711 /*
712 * For (Re)Association Response frame (AP->STA):
713 * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC
714 * [ || gAP || gSTA ])
715 */
716 addr[0] = anonce;
717 addr[1] = snonce;
718 addr[2] = bssid;
719 addr[3] = sta_addr;
Hai Shalomc3565922019-10-28 11:58:20 -0700720 if (g_sta && g_sta_len && g_ap && g_ap_len) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800721 addr[4] = g_ap;
722 len[4] = g_ap_len;
723 addr[5] = g_sta;
724 len[5] = g_sta_len;
725 }
726
727 if (wpa_key_mgmt_sha384(akmp))
728 res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
729 key_auth_ap);
730 else if (wpa_key_mgmt_sha256(akmp))
731 res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
732 key_auth_ap);
733 if (res < 0)
734 return res;
735
736 wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)",
737 key_auth_sta, *key_auth_len);
738 wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)",
739 key_auth_ap, *key_auth_len);
740
741 return 0;
742}
743
744#endif /* CONFIG_FILS */
745
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700746
747#ifdef CONFIG_IEEE80211R
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800748int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
749 const u8 *ap_addr, u8 transaction_seqnum,
750 const u8 *mdie, size_t mdie_len,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700751 const u8 *ftie, size_t ftie_len,
752 const u8 *rsnie, size_t rsnie_len,
Hai Shalomc3565922019-10-28 11:58:20 -0700753 const u8 *ric, size_t ric_len,
754 const u8 *rsnxe, size_t rsnxe_len,
755 u8 *mic)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700756{
Hai Shalomc3565922019-10-28 11:58:20 -0700757 const u8 *addr[10];
758 size_t len[10];
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700759 size_t i, num_elem = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700760 u8 zero_mic[24];
761 size_t mic_len, fte_fixed_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700762
Roshan Pius3a1667e2018-07-03 15:17:14 -0700763 if (kck_len == 16) {
764 mic_len = 16;
765#ifdef CONFIG_SHA384
766 } else if (kck_len == 24) {
767 mic_len = 24;
768#endif /* CONFIG_SHA384 */
769 } else {
Dmitry Shmidt807291d2015-01-27 13:40:23 -0800770 wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
771 (unsigned int) kck_len);
772 return -1;
773 }
774
Roshan Pius3a1667e2018-07-03 15:17:14 -0700775 fte_fixed_len = sizeof(struct rsn_ftie) - 16 + mic_len;
776
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700777 addr[num_elem] = sta_addr;
778 len[num_elem] = ETH_ALEN;
779 num_elem++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700780
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700781 addr[num_elem] = ap_addr;
782 len[num_elem] = ETH_ALEN;
783 num_elem++;
784
785 addr[num_elem] = &transaction_seqnum;
786 len[num_elem] = 1;
787 num_elem++;
788
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700789 if (rsnie) {
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700790 addr[num_elem] = rsnie;
791 len[num_elem] = rsnie_len;
792 num_elem++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700793 }
794 if (mdie) {
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700795 addr[num_elem] = mdie;
796 len[num_elem] = mdie_len;
797 num_elem++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700798 }
799 if (ftie) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700800 if (ftie_len < 2 + fte_fixed_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700801 return -1;
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700802
803 /* IE hdr and mic_control */
804 addr[num_elem] = ftie;
805 len[num_elem] = 2 + 2;
806 num_elem++;
807
808 /* MIC field with all zeros */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700809 os_memset(zero_mic, 0, mic_len);
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700810 addr[num_elem] = zero_mic;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700811 len[num_elem] = mic_len;
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700812 num_elem++;
813
814 /* Rest of FTIE */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700815 addr[num_elem] = ftie + 2 + 2 + mic_len;
816 len[num_elem] = ftie_len - (2 + 2 + mic_len);
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700817 num_elem++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700818 }
819 if (ric) {
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700820 addr[num_elem] = ric;
821 len[num_elem] = ric_len;
822 num_elem++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700823 }
824
Hai Shalomc3565922019-10-28 11:58:20 -0700825 if (rsnxe) {
826 addr[num_elem] = rsnxe;
827 len[num_elem] = rsnxe_len;
828 num_elem++;
829 }
830
Dmitry Shmidtf73259c2015-03-17 11:00:54 -0700831 for (i = 0; i < num_elem; i++)
832 wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700833#ifdef CONFIG_SHA384
834 if (kck_len == 24) {
835 u8 hash[SHA384_MAC_LEN];
836
837 if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash))
838 return -1;
839 os_memcpy(mic, hash, 24);
840 }
841#endif /* CONFIG_SHA384 */
842 if (kck_len == 16 &&
843 omac1_aes_128_vector(kck, num_elem, addr, len, mic))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700844 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700845
846 return 0;
847}
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800848
849
850static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700851 struct wpa_ft_ies *parse, int use_sha384)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800852{
853 const u8 *end, *pos;
854
855 parse->ftie = ie;
856 parse->ftie_len = ie_len;
857
Roshan Pius3a1667e2018-07-03 15:17:14 -0700858 pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) :
859 sizeof(struct rsn_ftie));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800860 end = ie + ie_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700861 wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800862
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800863 while (end - pos >= 2) {
864 u8 id, len;
865
866 id = *pos++;
867 len = *pos++;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700868 if (len > end - pos) {
869 wpa_printf(MSG_DEBUG, "FT: Truncated subelement");
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800870 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700871 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800872
873 switch (id) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800874 case FTIE_SUBELEM_R1KH_ID:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800875 if (len != FT_R1KH_ID_LEN) {
876 wpa_printf(MSG_DEBUG,
877 "FT: Invalid R1KH-ID length in FTIE: %d",
878 len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800879 return -1;
880 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800881 parse->r1kh_id = pos;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800882 break;
883 case FTIE_SUBELEM_GTK:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800884 parse->gtk = pos;
885 parse->gtk_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800886 break;
887 case FTIE_SUBELEM_R0KH_ID:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800888 if (len < 1 || len > FT_R0KH_ID_MAX_LEN) {
889 wpa_printf(MSG_DEBUG,
890 "FT: Invalid R0KH-ID length in FTIE: %d",
891 len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800892 return -1;
893 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800894 parse->r0kh_id = pos;
895 parse->r0kh_id_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800896 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800897 case FTIE_SUBELEM_IGTK:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800898 parse->igtk = pos;
899 parse->igtk_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800900 break;
Hai Shalom74f70d42019-02-11 14:42:39 -0800901#ifdef CONFIG_OCV
902 case FTIE_SUBELEM_OCI:
903 parse->oci = pos;
904 parse->oci_len = len;
905 break;
906#endif /* CONFIG_OCV */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700907 default:
908 wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
909 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800910 }
911
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800912 pos += len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800913 }
914
915 return 0;
916}
917
918
919int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -0700920 struct wpa_ft_ies *parse, int use_sha384)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800921{
922 const u8 *end, *pos;
923 struct wpa_ie_data data;
924 int ret;
925 const struct rsn_ftie *ftie;
926 int prot_ie_count = 0;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700927 int update_use_sha384 = 0;
928
929 if (use_sha384 < 0) {
930 use_sha384 = 0;
931 update_use_sha384 = 1;
932 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800933
934 os_memset(parse, 0, sizeof(*parse));
935 if (ies == NULL)
936 return 0;
937
938 pos = ies;
939 end = ies + ies_len;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800940 while (end - pos >= 2) {
941 u8 id, len;
942
943 id = *pos++;
944 len = *pos++;
945 if (len > end - pos)
946 break;
947
948 switch (id) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800949 case WLAN_EID_RSN:
Roshan Pius3a1667e2018-07-03 15:17:14 -0700950 wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800951 parse->rsn = pos;
952 parse->rsn_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800953 ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
954 parse->rsn_len + 2,
955 &data);
956 if (ret < 0) {
957 wpa_printf(MSG_DEBUG, "FT: Failed to parse "
958 "RSN IE: %d", ret);
959 return -1;
960 }
Hai Shalomc3565922019-10-28 11:58:20 -0700961 parse->rsn_capab = data.capabilities;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800962 if (data.num_pmkid == 1 && data.pmkid)
963 parse->rsn_pmkid = data.pmkid;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800964 parse->key_mgmt = data.key_mgmt;
965 parse->pairwise_cipher = data.pairwise_cipher;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700966 if (update_use_sha384) {
967 use_sha384 =
968 wpa_key_mgmt_sha384(parse->key_mgmt);
969 update_use_sha384 = 0;
970 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800971 break;
Hai Shalomc3565922019-10-28 11:58:20 -0700972 case WLAN_EID_RSNX:
973 wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
974 if (len < 1)
975 break;
976 parse->rsnxe = pos;
977 parse->rsnxe_len = len;
978 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800979 case WLAN_EID_MOBILITY_DOMAIN:
Roshan Pius3a1667e2018-07-03 15:17:14 -0700980 wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800981 if (len < sizeof(struct rsn_mdie))
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700982 return -1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800983 parse->mdie = pos;
984 parse->mdie_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800985 break;
986 case WLAN_EID_FAST_BSS_TRANSITION:
Roshan Pius3a1667e2018-07-03 15:17:14 -0700987 wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len);
988 if (use_sha384) {
989 const struct rsn_ftie_sha384 *ftie_sha384;
990
991 if (len < sizeof(*ftie_sha384))
992 return -1;
993 ftie_sha384 =
994 (const struct rsn_ftie_sha384 *) pos;
995 wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
996 ftie_sha384->mic_control, 2);
997 wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
998 ftie_sha384->mic,
999 sizeof(ftie_sha384->mic));
Hai Shalomc3565922019-10-28 11:58:20 -07001000 parse->fte_anonce = ftie_sha384->anonce;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001001 wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
1002 ftie_sha384->anonce,
1003 WPA_NONCE_LEN);
Hai Shalomc3565922019-10-28 11:58:20 -07001004 parse->fte_snonce = ftie_sha384->snonce;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001005 wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
1006 ftie_sha384->snonce,
1007 WPA_NONCE_LEN);
1008 prot_ie_count = ftie_sha384->mic_control[1];
1009 if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0)
1010 return -1;
1011 break;
1012 }
1013
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001014 if (len < sizeof(*ftie))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001015 return -1;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001016 ftie = (const struct rsn_ftie *) pos;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001017 wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control",
1018 ftie->mic_control, 2);
1019 wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC",
1020 ftie->mic, sizeof(ftie->mic));
Hai Shalomc3565922019-10-28 11:58:20 -07001021 parse->fte_anonce = ftie->anonce;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001022 wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce",
1023 ftie->anonce, WPA_NONCE_LEN);
Hai Shalomc3565922019-10-28 11:58:20 -07001024 parse->fte_snonce = ftie->snonce;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001025 wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce",
1026 ftie->snonce, WPA_NONCE_LEN);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001027 prot_ie_count = ftie->mic_control[1];
Roshan Pius3a1667e2018-07-03 15:17:14 -07001028 if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0)
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001029 return -1;
1030 break;
1031 case WLAN_EID_TIMEOUT_INTERVAL:
Roshan Pius3a1667e2018-07-03 15:17:14 -07001032 wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval",
1033 pos, len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001034 if (len != 5)
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001035 break;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001036 parse->tie = pos;
1037 parse->tie_len = len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001038 break;
1039 case WLAN_EID_RIC_DATA:
1040 if (parse->ric == NULL)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001041 parse->ric = pos - 2;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001042 break;
1043 }
1044
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001045 pos += len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001046 }
1047
1048 if (prot_ie_count == 0)
1049 return 0; /* no MIC */
1050
1051 /*
1052 * Check that the protected IE count matches with IEs included in the
1053 * frame.
1054 */
1055 if (parse->rsn)
1056 prot_ie_count--;
1057 if (parse->mdie)
1058 prot_ie_count--;
1059 if (parse->ftie)
1060 prot_ie_count--;
Hai Shalomc3565922019-10-28 11:58:20 -07001061 if (parse->rsnxe)
1062 prot_ie_count--;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001063 if (prot_ie_count < 0) {
1064 wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
1065 "the protected IE count");
1066 return -1;
1067 }
1068
1069 if (prot_ie_count == 0 && parse->ric) {
1070 wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
1071 "included in protected IE count");
1072 return -1;
1073 }
1074
1075 /* Determine the end of the RIC IE(s) */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001076 if (parse->ric) {
1077 pos = parse->ric;
1078 while (end - pos >= 2 && 2 + pos[1] <= end - pos &&
1079 prot_ie_count) {
1080 prot_ie_count--;
1081 pos += 2 + pos[1];
1082 }
1083 parse->ric_len = pos - parse->ric;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001084 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001085 if (prot_ie_count) {
1086 wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
1087 "frame", (int) prot_ie_count);
1088 return -1;
1089 }
1090
1091 return 0;
1092}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001093#endif /* CONFIG_IEEE80211R */
1094
1095
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001096static int rsn_selector_to_bitfield(const u8 *s)
1097{
1098 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
1099 return WPA_CIPHER_NONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001100 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
1101 return WPA_CIPHER_TKIP;
1102 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
1103 return WPA_CIPHER_CCMP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001104 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
1105 return WPA_CIPHER_AES_128_CMAC;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001106 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
1107 return WPA_CIPHER_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001108 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
1109 return WPA_CIPHER_CCMP_256;
1110 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
1111 return WPA_CIPHER_GCMP_256;
1112 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
1113 return WPA_CIPHER_BIP_GMAC_128;
1114 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
1115 return WPA_CIPHER_BIP_GMAC_256;
1116 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
1117 return WPA_CIPHER_BIP_CMAC_256;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001118 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
1119 return WPA_CIPHER_GTK_NOT_USED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001120 return 0;
1121}
1122
1123
1124static int rsn_key_mgmt_to_bitfield(const u8 *s)
1125{
1126 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
1127 return WPA_KEY_MGMT_IEEE8021X;
1128 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
1129 return WPA_KEY_MGMT_PSK;
1130#ifdef CONFIG_IEEE80211R
1131 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
1132 return WPA_KEY_MGMT_FT_IEEE8021X;
1133 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
1134 return WPA_KEY_MGMT_FT_PSK;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001135#ifdef CONFIG_SHA384
1136 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384)
1137 return WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
1138#endif /* CONFIG_SHA384 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001139#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001140 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
1141 return WPA_KEY_MGMT_IEEE8021X_SHA256;
1142 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
1143 return WPA_KEY_MGMT_PSK_SHA256;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001144#ifdef CONFIG_SAE
1145 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
1146 return WPA_KEY_MGMT_SAE;
1147 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
1148 return WPA_KEY_MGMT_FT_SAE;
1149#endif /* CONFIG_SAE */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001150 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
1151 return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001152 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
1153 return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001154 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256)
1155 return WPA_KEY_MGMT_FILS_SHA256;
1156 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384)
1157 return WPA_KEY_MGMT_FILS_SHA384;
1158 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256)
1159 return WPA_KEY_MGMT_FT_FILS_SHA256;
1160 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384)
1161 return WPA_KEY_MGMT_FT_FILS_SHA384;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001162#ifdef CONFIG_OWE
1163 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OWE)
1164 return WPA_KEY_MGMT_OWE;
1165#endif /* CONFIG_OWE */
1166#ifdef CONFIG_DPP
1167 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP)
1168 return WPA_KEY_MGMT_DPP;
1169#endif /* CONFIG_DPP */
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07001170 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
1171 return WPA_KEY_MGMT_OSEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001172 return 0;
1173}
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001174
1175
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001176int wpa_cipher_valid_group(int cipher)
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001177{
1178 return wpa_cipher_valid_pairwise(cipher) ||
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001179 cipher == WPA_CIPHER_GTK_NOT_USED;
1180}
1181
1182
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001183int wpa_cipher_valid_mgmt_group(int cipher)
1184{
1185 return cipher == WPA_CIPHER_AES_128_CMAC ||
1186 cipher == WPA_CIPHER_BIP_GMAC_128 ||
1187 cipher == WPA_CIPHER_BIP_GMAC_256 ||
1188 cipher == WPA_CIPHER_BIP_CMAC_256;
1189}
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001190
1191
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001192/**
1193 * wpa_parse_wpa_ie_rsn - Parse RSN IE
1194 * @rsn_ie: Buffer containing RSN IE
1195 * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
1196 * @data: Pointer to structure that will be filled in with parsed data
1197 * Returns: 0 on success, <0 on failure
1198 */
1199int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
1200 struct wpa_ie_data *data)
1201{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001202 const u8 *pos;
1203 int left;
1204 int i, count;
1205
1206 os_memset(data, 0, sizeof(*data));
1207 data->proto = WPA_PROTO_RSN;
1208 data->pairwise_cipher = WPA_CIPHER_CCMP;
1209 data->group_cipher = WPA_CIPHER_CCMP;
1210 data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
1211 data->capabilities = 0;
1212 data->pmkid = NULL;
1213 data->num_pmkid = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001214 data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001215
1216 if (rsn_ie_len == 0) {
1217 /* No RSN IE - fail silently */
1218 return -1;
1219 }
1220
1221 if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
1222 wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
1223 __func__, (unsigned long) rsn_ie_len);
1224 return -1;
1225 }
1226
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07001227 if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
1228 rsn_ie[1] == rsn_ie_len - 2 &&
1229 WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
1230 pos = rsn_ie + 6;
1231 left = rsn_ie_len - 6;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001232
Hai Shalom74f70d42019-02-11 14:42:39 -08001233 data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
Hai Shalom021b0b52019-04-10 11:17:58 -07001234 data->has_group = 1;
Hai Shalom74f70d42019-02-11 14:42:39 -08001235 data->key_mgmt = WPA_KEY_MGMT_OSEN;
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07001236 data->proto = WPA_PROTO_OSEN;
1237 } else {
1238 const struct rsn_ie_hdr *hdr;
1239
1240 hdr = (const struct rsn_ie_hdr *) rsn_ie;
1241
1242 if (hdr->elem_id != WLAN_EID_RSN ||
1243 hdr->len != rsn_ie_len - 2 ||
1244 WPA_GET_LE16(hdr->version) != RSN_VERSION) {
1245 wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
1246 __func__);
1247 return -2;
1248 }
1249
1250 pos = (const u8 *) (hdr + 1);
1251 left = rsn_ie_len - sizeof(*hdr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001252 }
1253
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001254 if (left >= RSN_SELECTOR_LEN) {
1255 data->group_cipher = rsn_selector_to_bitfield(pos);
Hai Shalom021b0b52019-04-10 11:17:58 -07001256 data->has_group = 1;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001257 if (!wpa_cipher_valid_group(data->group_cipher)) {
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08001258 wpa_printf(MSG_DEBUG,
1259 "%s: invalid group cipher 0x%x (%08x)",
1260 __func__, data->group_cipher,
1261 WPA_GET_BE32(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001262 return -1;
1263 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001264 pos += RSN_SELECTOR_LEN;
1265 left -= RSN_SELECTOR_LEN;
1266 } else if (left > 0) {
1267 wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
1268 __func__, left);
1269 return -3;
1270 }
1271
1272 if (left >= 2) {
1273 data->pairwise_cipher = 0;
1274 count = WPA_GET_LE16(pos);
1275 pos += 2;
1276 left -= 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001277 if (count == 0 || count > left / RSN_SELECTOR_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001278 wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
1279 "count %u left %u", __func__, count, left);
1280 return -4;
1281 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001282 if (count)
1283 data->has_pairwise = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001284 for (i = 0; i < count; i++) {
1285 data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
1286 pos += RSN_SELECTOR_LEN;
1287 left -= RSN_SELECTOR_LEN;
1288 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001289 if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
1290 wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
1291 "pairwise cipher", __func__);
1292 return -1;
1293 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001294 } else if (left == 1) {
1295 wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
1296 __func__);
1297 return -5;
1298 }
1299
1300 if (left >= 2) {
1301 data->key_mgmt = 0;
1302 count = WPA_GET_LE16(pos);
1303 pos += 2;
1304 left -= 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001305 if (count == 0 || count > left / RSN_SELECTOR_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001306 wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
1307 "count %u left %u", __func__, count, left);
1308 return -6;
1309 }
1310 for (i = 0; i < count; i++) {
1311 data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
1312 pos += RSN_SELECTOR_LEN;
1313 left -= RSN_SELECTOR_LEN;
1314 }
1315 } else if (left == 1) {
1316 wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
1317 __func__);
1318 return -7;
1319 }
1320
1321 if (left >= 2) {
1322 data->capabilities = WPA_GET_LE16(pos);
1323 pos += 2;
1324 left -= 2;
1325 }
1326
1327 if (left >= 2) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001328 u16 num_pmkid = WPA_GET_LE16(pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001329 pos += 2;
1330 left -= 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001331 if (num_pmkid > (unsigned int) left / PMKID_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001332 wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001333 "(num_pmkid=%u left=%d)",
1334 __func__, num_pmkid, left);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001335 data->num_pmkid = 0;
1336 return -9;
1337 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001338 data->num_pmkid = num_pmkid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001339 data->pmkid = pos;
1340 pos += data->num_pmkid * PMKID_LEN;
1341 left -= data->num_pmkid * PMKID_LEN;
1342 }
1343 }
1344
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001345 if (left >= 4) {
1346 data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07001347 if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08001348 wpa_printf(MSG_DEBUG,
1349 "%s: Unsupported management group cipher 0x%x (%08x)",
1350 __func__, data->mgmt_group_cipher,
1351 WPA_GET_BE32(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001352 return -10;
1353 }
1354 pos += RSN_SELECTOR_LEN;
1355 left -= RSN_SELECTOR_LEN;
1356 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001357
1358 if (left > 0) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001359 wpa_hexdump(MSG_DEBUG,
1360 "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
1361 pos, left);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362 }
1363
1364 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001365}
1366
1367
1368static int wpa_selector_to_bitfield(const u8 *s)
1369{
1370 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
1371 return WPA_CIPHER_NONE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001372 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
1373 return WPA_CIPHER_TKIP;
1374 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
1375 return WPA_CIPHER_CCMP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001376 return 0;
1377}
1378
1379
1380static int wpa_key_mgmt_to_bitfield(const u8 *s)
1381{
1382 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
1383 return WPA_KEY_MGMT_IEEE8021X;
1384 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
1385 return WPA_KEY_MGMT_PSK;
1386 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
1387 return WPA_KEY_MGMT_WPA_NONE;
1388 return 0;
1389}
1390
1391
1392int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
1393 struct wpa_ie_data *data)
1394{
1395 const struct wpa_ie_hdr *hdr;
1396 const u8 *pos;
1397 int left;
1398 int i, count;
1399
1400 os_memset(data, 0, sizeof(*data));
1401 data->proto = WPA_PROTO_WPA;
1402 data->pairwise_cipher = WPA_CIPHER_TKIP;
1403 data->group_cipher = WPA_CIPHER_TKIP;
1404 data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
1405 data->capabilities = 0;
1406 data->pmkid = NULL;
1407 data->num_pmkid = 0;
1408 data->mgmt_group_cipher = 0;
1409
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001410 if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
1411 wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
1412 __func__, (unsigned long) wpa_ie_len);
1413 return -1;
1414 }
1415
1416 hdr = (const struct wpa_ie_hdr *) wpa_ie;
1417
1418 if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
1419 hdr->len != wpa_ie_len - 2 ||
1420 RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
1421 WPA_GET_LE16(hdr->version) != WPA_VERSION) {
1422 wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
1423 __func__);
1424 return -2;
1425 }
1426
1427 pos = (const u8 *) (hdr + 1);
1428 left = wpa_ie_len - sizeof(*hdr);
1429
1430 if (left >= WPA_SELECTOR_LEN) {
1431 data->group_cipher = wpa_selector_to_bitfield(pos);
1432 pos += WPA_SELECTOR_LEN;
1433 left -= WPA_SELECTOR_LEN;
1434 } else if (left > 0) {
1435 wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
1436 __func__, left);
1437 return -3;
1438 }
1439
1440 if (left >= 2) {
1441 data->pairwise_cipher = 0;
1442 count = WPA_GET_LE16(pos);
1443 pos += 2;
1444 left -= 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001445 if (count == 0 || count > left / WPA_SELECTOR_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001446 wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
1447 "count %u left %u", __func__, count, left);
1448 return -4;
1449 }
1450 for (i = 0; i < count; i++) {
1451 data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
1452 pos += WPA_SELECTOR_LEN;
1453 left -= WPA_SELECTOR_LEN;
1454 }
1455 } else if (left == 1) {
1456 wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
1457 __func__);
1458 return -5;
1459 }
1460
1461 if (left >= 2) {
1462 data->key_mgmt = 0;
1463 count = WPA_GET_LE16(pos);
1464 pos += 2;
1465 left -= 2;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001466 if (count == 0 || count > left / WPA_SELECTOR_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001467 wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
1468 "count %u left %u", __func__, count, left);
1469 return -6;
1470 }
1471 for (i = 0; i < count; i++) {
1472 data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
1473 pos += WPA_SELECTOR_LEN;
1474 left -= WPA_SELECTOR_LEN;
1475 }
1476 } else if (left == 1) {
1477 wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
1478 __func__);
1479 return -7;
1480 }
1481
1482 if (left >= 2) {
1483 data->capabilities = WPA_GET_LE16(pos);
1484 pos += 2;
1485 left -= 2;
1486 }
1487
1488 if (left > 0) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001489 wpa_hexdump(MSG_DEBUG,
1490 "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
1491 pos, left);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001492 }
1493
1494 return 0;
1495}
1496
1497
Hai Shalom021b0b52019-04-10 11:17:58 -07001498int wpa_default_rsn_cipher(int freq)
1499{
1500 if (freq > 56160)
1501 return WPA_CIPHER_GCMP; /* DMG */
1502
1503 return WPA_CIPHER_CCMP;
1504}
1505
1506
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001507#ifdef CONFIG_IEEE80211R
1508
1509/**
1510 * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
1511 *
1512 * IEEE Std 802.11r-2008 - 8.5.1.5.3
1513 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001514int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
1515 const u8 *ssid, size_t ssid_len,
1516 const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001517 const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name,
1518 int use_sha384)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001519{
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001520 u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001521 FT_R0KH_ID_MAX_LEN + ETH_ALEN];
Roshan Pius3a1667e2018-07-03 15:17:14 -07001522 u8 *pos, r0_key_data[64], hash[48];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001523 const u8 *addr[2];
1524 size_t len[2];
Roshan Pius3a1667e2018-07-03 15:17:14 -07001525 size_t q = use_sha384 ? 48 : 32;
1526 size_t r0_key_data_len = q + 16;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001527
1528 /*
1529 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
1530 * SSIDlength || SSID || MDID || R0KHlength ||
1531 * R0KH-ID || S0KH-ID)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001532 * XXKey is either the second 256 bits of MSK or PSK; or the first
1533 * 384 bits of MSK for FT-EAP-SHA384.
1534 * PMK-R0 = L(R0-Key-Data, 0, Q)
1535 * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128)
1536 * Q = 384 for FT-EAP-SHA384; otherwise, 256
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001537 */
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001538 if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001539 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001540 wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s",
1541 use_sha384 ? "SHA384" : "SHA256");
1542 wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len);
1543 wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len);
1544 wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN);
1545 wpa_hexdump_ascii(MSG_DEBUG, "FT: R0KH-ID", r0kh_id, r0kh_id_len);
1546 wpa_printf(MSG_DEBUG, "FT: S0KH-ID: " MACSTR, MAC2STR(s0kh_id));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001547 pos = buf;
1548 *pos++ = ssid_len;
1549 os_memcpy(pos, ssid, ssid_len);
1550 pos += ssid_len;
1551 os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
1552 pos += MOBILITY_DOMAIN_ID_LEN;
1553 *pos++ = r0kh_id_len;
1554 os_memcpy(pos, r0kh_id, r0kh_id_len);
1555 pos += r0kh_id_len;
1556 os_memcpy(pos, s0kh_id, ETH_ALEN);
1557 pos += ETH_ALEN;
1558
Roshan Pius3a1667e2018-07-03 15:17:14 -07001559#ifdef CONFIG_SHA384
1560 if (use_sha384) {
1561 if (xxkey_len != SHA384_MAC_LEN) {
1562 wpa_printf(MSG_ERROR,
1563 "FT: Unexpected XXKey length %d (expected %d)",
1564 (int) xxkey_len, SHA384_MAC_LEN);
1565 return -1;
1566 }
1567 if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
1568 r0_key_data, r0_key_data_len) < 0)
1569 return -1;
1570 }
1571#endif /* CONFIG_SHA384 */
1572 if (!use_sha384) {
1573 if (xxkey_len != PMK_LEN) {
1574 wpa_printf(MSG_ERROR,
1575 "FT: Unexpected XXKey length %d (expected %d)",
1576 (int) xxkey_len, PMK_LEN);
1577 return -1;
1578 }
1579 if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
1580 r0_key_data, r0_key_data_len) < 0)
1581 return -1;
1582 }
1583 os_memcpy(pmk_r0, r0_key_data, q);
1584 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q);
1585 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001586
1587 /*
Roshan Pius3a1667e2018-07-03 15:17:14 -07001588 * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001589 */
1590 addr[0] = (const u8 *) "FT-R0N";
1591 len[0] = 6;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001592 addr[1] = &r0_key_data[q];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001593 len[1] = 16;
1594
Roshan Pius3a1667e2018-07-03 15:17:14 -07001595#ifdef CONFIG_SHA384
1596 if (use_sha384 && sha384_vector(2, addr, len, hash) < 0)
1597 return -1;
1598#endif /* CONFIG_SHA384 */
1599 if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001600 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001601 os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001602 os_memset(r0_key_data, 0, sizeof(r0_key_data));
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001603 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001604}
1605
1606
1607/**
1608 * wpa_derive_pmk_r1_name - Derive PMKR1Name
1609 *
1610 * IEEE Std 802.11r-2008 - 8.5.1.5.4
1611 */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001612int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001613 const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001614{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001615 u8 hash[48];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001616 const u8 *addr[4];
1617 size_t len[4];
1618
1619 /*
Roshan Pius3a1667e2018-07-03 15:17:14 -07001620 * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name ||
1621 * R1KH-ID || S1KH-ID))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001622 */
1623 addr[0] = (const u8 *) "FT-R1N";
1624 len[0] = 6;
1625 addr[1] = pmk_r0_name;
1626 len[1] = WPA_PMK_NAME_LEN;
1627 addr[2] = r1kh_id;
1628 len[2] = FT_R1KH_ID_LEN;
1629 addr[3] = s1kh_id;
1630 len[3] = ETH_ALEN;
1631
Roshan Pius3a1667e2018-07-03 15:17:14 -07001632#ifdef CONFIG_SHA384
1633 if (use_sha384 && sha384_vector(4, addr, len, hash) < 0)
1634 return -1;
1635#endif /* CONFIG_SHA384 */
1636 if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001637 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001638 os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001639 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001640}
1641
1642
1643/**
1644 * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
1645 *
1646 * IEEE Std 802.11r-2008 - 8.5.1.5.4
1647 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001648int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
1649 const u8 *pmk_r0_name,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001650 const u8 *r1kh_id, const u8 *s1kh_id,
1651 u8 *pmk_r1, u8 *pmk_r1_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001652{
1653 u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
1654 u8 *pos;
1655
1656 /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001657 wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s",
1658 pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256");
1659 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
1660 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN);
1661 wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR, MAC2STR(s1kh_id));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001662 pos = buf;
1663 os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
1664 pos += FT_R1KH_ID_LEN;
1665 os_memcpy(pos, s1kh_id, ETH_ALEN);
1666 pos += ETH_ALEN;
1667
Roshan Pius3a1667e2018-07-03 15:17:14 -07001668#ifdef CONFIG_SHA384
1669 if (pmk_r0_len == SHA384_MAC_LEN &&
1670 sha384_prf(pmk_r0, pmk_r0_len, "FT-R1",
1671 buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001672 return -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001673#endif /* CONFIG_SHA384 */
1674 if (pmk_r0_len == PMK_LEN &&
1675 sha256_prf(pmk_r0, pmk_r0_len, "FT-R1",
1676 buf, pos - buf, pmk_r1, pmk_r0_len) < 0)
1677 return -1;
1678 if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) {
1679 wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d",
1680 (int) pmk_r0_len);
1681 return -1;
1682 }
1683 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001684
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001685 return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
Roshan Pius3a1667e2018-07-03 15:17:14 -07001686 pmk_r1_name,
1687 pmk_r0_len == SHA384_MAC_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001688}
1689
1690
1691/**
1692 * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
1693 *
1694 * IEEE Std 802.11r-2008 - 8.5.1.5.5
1695 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001696int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
1697 const u8 *snonce, const u8 *anonce,
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001698 const u8 *sta_addr, const u8 *bssid,
1699 const u8 *pmk_r1_name,
1700 struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001701{
1702 u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
1703 u8 *pos, hash[32];
1704 const u8 *addr[6];
1705 size_t len[6];
Roshan Pius3a1667e2018-07-03 15:17:14 -07001706 u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
1707 size_t ptk_len, offset;
1708 int use_sha384 = wpa_key_mgmt_sha384(akmp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001709
1710 /*
1711 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
1712 * BSSID || STA-ADDR)
1713 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001714 wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s",
1715 use_sha384 ? "SHA384" : "SHA256");
1716 wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
1717 wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN);
1718 wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN);
1719 wpa_printf(MSG_DEBUG, "FT: BSSID=" MACSTR " STA-ADDR=" MACSTR,
1720 MAC2STR(bssid), MAC2STR(sta_addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001721 pos = buf;
1722 os_memcpy(pos, snonce, WPA_NONCE_LEN);
1723 pos += WPA_NONCE_LEN;
1724 os_memcpy(pos, anonce, WPA_NONCE_LEN);
1725 pos += WPA_NONCE_LEN;
1726 os_memcpy(pos, bssid, ETH_ALEN);
1727 pos += ETH_ALEN;
1728 os_memcpy(pos, sta_addr, ETH_ALEN);
1729 pos += ETH_ALEN;
1730
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001731 ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001732 ptk->kck2_len = wpa_kck2_len(akmp);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001733 ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001734 ptk->kek2_len = wpa_kek2_len(akmp);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001735 ptk->tk_len = wpa_cipher_key_len(cipher);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001736 ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
1737 ptk->kck2_len + ptk->kek2_len;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001738
Roshan Pius3a1667e2018-07-03 15:17:14 -07001739#ifdef CONFIG_SHA384
1740 if (use_sha384) {
1741 if (pmk_r1_len != SHA384_MAC_LEN) {
1742 wpa_printf(MSG_ERROR,
1743 "FT: Unexpected PMK-R1 length %d (expected %d)",
1744 (int) pmk_r1_len, SHA384_MAC_LEN);
1745 return -1;
1746 }
1747 if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK",
1748 buf, pos - buf, tmp, ptk_len) < 0)
1749 return -1;
1750 }
1751#endif /* CONFIG_SHA384 */
1752 if (!use_sha384) {
1753 if (pmk_r1_len != PMK_LEN) {
1754 wpa_printf(MSG_ERROR,
1755 "FT: Unexpected PMK-R1 length %d (expected %d)",
1756 (int) pmk_r1_len, PMK_LEN);
1757 return -1;
1758 }
1759 if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK",
1760 buf, pos - buf, tmp, ptk_len) < 0)
1761 return -1;
1762 }
1763 wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001764
1765 /*
1766 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
1767 * ANonce || BSSID || STA-ADDR))
1768 */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001769 wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001770 addr[0] = pmk_r1_name;
1771 len[0] = WPA_PMK_NAME_LEN;
1772 addr[1] = (const u8 *) "FT-PTKN";
1773 len[1] = 7;
1774 addr[2] = snonce;
1775 len[2] = WPA_NONCE_LEN;
1776 addr[3] = anonce;
1777 len[3] = WPA_NONCE_LEN;
1778 addr[4] = bssid;
1779 len[4] = ETH_ALEN;
1780 addr[5] = sta_addr;
1781 len[5] = ETH_ALEN;
1782
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08001783 if (sha256_vector(6, addr, len, hash) < 0)
1784 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001785 os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001786
1787 os_memcpy(ptk->kck, tmp, ptk->kck_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001788 offset = ptk->kck_len;
1789 os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
1790 offset += ptk->kek_len;
1791 os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
1792 offset += ptk->tk_len;
1793 os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07001794 offset += ptk->kck2_len;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001795 os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001796
1797 wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
1798 wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001799 if (ptk->kck2_len)
1800 wpa_hexdump_key(MSG_DEBUG, "FT: KCK2",
1801 ptk->kck2, ptk->kck2_len);
1802 if (ptk->kek2_len)
1803 wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
1804 ptk->kek2, ptk->kek2_len);
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001805 wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
1806 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
1807
1808 os_memset(tmp, 0, sizeof(tmp));
1809
1810 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001811}
1812
1813#endif /* CONFIG_IEEE80211R */
1814
1815
1816/**
1817 * rsn_pmkid - Calculate PMK identifier
1818 * @pmk: Pairwise master key
1819 * @pmk_len: Length of pmk in bytes
1820 * @aa: Authenticator address
1821 * @spa: Supplicant address
1822 * @pmkid: Buffer for PMKID
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001823 * @akmp: Negotiated key management protocol
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001824 *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001825 * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy
1826 * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16
1827 * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA))
1828 * AKM: 00-0F-AC:11
1829 * See rsn_pmkid_suite_b()
1830 * AKM: 00-0F-AC:12
1831 * See rsn_pmkid_suite_b_192()
Roshan Pius3a1667e2018-07-03 15:17:14 -07001832 * AKM: 00-0F-AC:13, 00-0F-AC:15, 00-0F-AC:17
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001833 * PMKID = Truncate-128(HMAC-SHA-384(PMK, "PMK Name" || AA || SPA))
1834 * Otherwise:
1835 * PMKID = Truncate-128(HMAC-SHA-1(PMK, "PMK Name" || AA || SPA))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001836 */
1837void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001838 u8 *pmkid, int akmp)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001839{
1840 char *title = "PMK Name";
1841 const u8 *addr[3];
1842 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001843 unsigned char hash[SHA384_MAC_LEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001844
1845 addr[0] = (u8 *) title;
1846 addr[1] = aa;
1847 addr[2] = spa;
1848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001849 if (0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001850#if defined(CONFIG_FILS) || defined(CONFIG_SHA384)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001851 } else if (wpa_key_mgmt_sha384(akmp)) {
1852 wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-384");
1853 hmac_sha384_vector(pmk, pmk_len, 3, addr, len, hash);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001854#endif /* CONFIG_FILS || CONFIG_SHA384 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001855 } else if (wpa_key_mgmt_sha256(akmp)) {
1856 wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-256");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001857 hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001858 } else {
1859 wpa_printf(MSG_DEBUG, "RSN: Derive PMKID using HMAC-SHA-1");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001860 hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001861 }
1862 wpa_hexdump(MSG_DEBUG, "RSN: Derived PMKID", hash, PMKID_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001863 os_memcpy(pmkid, hash, PMKID_LEN);
1864}
1865
1866
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001867#ifdef CONFIG_SUITEB
1868/**
1869 * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
1870 * @kck: Key confirmation key
1871 * @kck_len: Length of kck in bytes
1872 * @aa: Authenticator address
1873 * @spa: Supplicant address
1874 * @pmkid: Buffer for PMKID
1875 * Returns: 0 on success, -1 on failure
1876 *
1877 * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1878 * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
1879 */
1880int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
1881 const u8 *spa, u8 *pmkid)
1882{
1883 char *title = "PMK Name";
1884 const u8 *addr[3];
1885 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1886 unsigned char hash[SHA256_MAC_LEN];
1887
1888 addr[0] = (u8 *) title;
1889 addr[1] = aa;
1890 addr[2] = spa;
1891
1892 if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
1893 return -1;
1894 os_memcpy(pmkid, hash, PMKID_LEN);
1895 return 0;
1896}
1897#endif /* CONFIG_SUITEB */
1898
1899
Dmitry Shmidt807291d2015-01-27 13:40:23 -08001900#ifdef CONFIG_SUITEB192
1901/**
1902 * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
1903 * @kck: Key confirmation key
1904 * @kck_len: Length of kck in bytes
1905 * @aa: Authenticator address
1906 * @spa: Supplicant address
1907 * @pmkid: Buffer for PMKID
1908 * Returns: 0 on success, -1 on failure
1909 *
1910 * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1911 * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
1912 */
1913int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
1914 const u8 *spa, u8 *pmkid)
1915{
1916 char *title = "PMK Name";
1917 const u8 *addr[3];
1918 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1919 unsigned char hash[SHA384_MAC_LEN];
1920
1921 addr[0] = (u8 *) title;
1922 addr[1] = aa;
1923 addr[2] = spa;
1924
1925 if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
1926 return -1;
1927 os_memcpy(pmkid, hash, PMKID_LEN);
1928 return 0;
1929}
1930#endif /* CONFIG_SUITEB192 */
1931
1932
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001933/**
1934 * wpa_cipher_txt - Convert cipher suite to a text string
1935 * @cipher: Cipher suite (WPA_CIPHER_* enum)
1936 * Returns: Pointer to a text string of the cipher suite name
1937 */
1938const char * wpa_cipher_txt(int cipher)
1939{
1940 switch (cipher) {
1941 case WPA_CIPHER_NONE:
1942 return "NONE";
1943 case WPA_CIPHER_WEP40:
1944 return "WEP-40";
1945 case WPA_CIPHER_WEP104:
1946 return "WEP-104";
1947 case WPA_CIPHER_TKIP:
1948 return "TKIP";
1949 case WPA_CIPHER_CCMP:
1950 return "CCMP";
1951 case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
1952 return "CCMP+TKIP";
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001953 case WPA_CIPHER_GCMP:
1954 return "GCMP";
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001955 case WPA_CIPHER_GCMP_256:
1956 return "GCMP-256";
1957 case WPA_CIPHER_CCMP_256:
1958 return "CCMP-256";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001959 case WPA_CIPHER_AES_128_CMAC:
1960 return "BIP";
1961 case WPA_CIPHER_BIP_GMAC_128:
1962 return "BIP-GMAC-128";
1963 case WPA_CIPHER_BIP_GMAC_256:
1964 return "BIP-GMAC-256";
1965 case WPA_CIPHER_BIP_CMAC_256:
1966 return "BIP-CMAC-256";
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001967 case WPA_CIPHER_GTK_NOT_USED:
1968 return "GTK_NOT_USED";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001969 default:
1970 return "UNKNOWN";
1971 }
1972}
1973
1974
1975/**
1976 * wpa_key_mgmt_txt - Convert key management suite to a text string
1977 * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
1978 * @proto: WPA/WPA2 version (WPA_PROTO_*)
1979 * Returns: Pointer to a text string of the key management suite name
1980 */
1981const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
1982{
1983 switch (key_mgmt) {
1984 case WPA_KEY_MGMT_IEEE8021X:
1985 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1986 return "WPA2+WPA/IEEE 802.1X/EAP";
1987 return proto == WPA_PROTO_RSN ?
1988 "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
1989 case WPA_KEY_MGMT_PSK:
1990 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1991 return "WPA2-PSK+WPA-PSK";
1992 return proto == WPA_PROTO_RSN ?
1993 "WPA2-PSK" : "WPA-PSK";
1994 case WPA_KEY_MGMT_NONE:
1995 return "NONE";
Dmitry Shmidt58d12ad2016-07-28 10:07:03 -07001996 case WPA_KEY_MGMT_WPA_NONE:
1997 return "WPA-NONE";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001998 case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
1999 return "IEEE 802.1X (no WPA)";
2000#ifdef CONFIG_IEEE80211R
2001 case WPA_KEY_MGMT_FT_IEEE8021X:
2002 return "FT-EAP";
Roshan Pius3a1667e2018-07-03 15:17:14 -07002003 case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
2004 return "FT-EAP-SHA384";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002005 case WPA_KEY_MGMT_FT_PSK:
2006 return "FT-PSK";
2007#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002008 case WPA_KEY_MGMT_IEEE8021X_SHA256:
2009 return "WPA2-EAP-SHA256";
2010 case WPA_KEY_MGMT_PSK_SHA256:
2011 return "WPA2-PSK-SHA256";
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002012 case WPA_KEY_MGMT_WPS:
2013 return "WPS";
2014 case WPA_KEY_MGMT_SAE:
2015 return "SAE";
2016 case WPA_KEY_MGMT_FT_SAE:
2017 return "FT-SAE";
2018 case WPA_KEY_MGMT_OSEN:
2019 return "OSEN";
2020 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
2021 return "WPA2-EAP-SUITE-B";
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002022 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
2023 return "WPA2-EAP-SUITE-B-192";
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002024 case WPA_KEY_MGMT_FILS_SHA256:
2025 return "FILS-SHA256";
2026 case WPA_KEY_MGMT_FILS_SHA384:
2027 return "FILS-SHA384";
2028 case WPA_KEY_MGMT_FT_FILS_SHA256:
2029 return "FT-FILS-SHA256";
2030 case WPA_KEY_MGMT_FT_FILS_SHA384:
2031 return "FT-FILS-SHA384";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002032 case WPA_KEY_MGMT_OWE:
2033 return "OWE";
2034 case WPA_KEY_MGMT_DPP:
2035 return "DPP";
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002036 default:
2037 return "UNKNOWN";
2038 }
2039}
2040
2041
Dmitry Shmidt03658832014-08-13 11:03:49 -07002042u32 wpa_akm_to_suite(int akm)
2043{
Roshan Pius3a1667e2018-07-03 15:17:14 -07002044 if (akm & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
2045 return RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002046 if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
Paul Stewart092955c2017-02-06 09:13:09 -08002047 return RSN_AUTH_KEY_MGMT_FT_802_1X;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002048 if (akm & WPA_KEY_MGMT_FT_PSK)
Paul Stewart092955c2017-02-06 09:13:09 -08002049 return RSN_AUTH_KEY_MGMT_FT_PSK;
Rebecca Silberstein055a67c2017-02-01 23:05:56 +00002050 if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
Paul Stewart092955c2017-02-06 09:13:09 -08002051 return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
Rebecca Silberstein055a67c2017-02-01 23:05:56 +00002052 if (akm & WPA_KEY_MGMT_IEEE8021X)
Paul Stewart092955c2017-02-06 09:13:09 -08002053 return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002054 if (akm & WPA_KEY_MGMT_PSK_SHA256)
Paul Stewart092955c2017-02-06 09:13:09 -08002055 return RSN_AUTH_KEY_MGMT_PSK_SHA256;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002056 if (akm & WPA_KEY_MGMT_PSK)
Paul Stewart092955c2017-02-06 09:13:09 -08002057 return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002058 if (akm & WPA_KEY_MGMT_CCKM)
Paul Stewart092955c2017-02-06 09:13:09 -08002059 return RSN_AUTH_KEY_MGMT_CCKM;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002060 if (akm & WPA_KEY_MGMT_OSEN)
Paul Stewart092955c2017-02-06 09:13:09 -08002061 return RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002062 if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
Paul Stewart092955c2017-02-06 09:13:09 -08002063 return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
Dmitry Shmidt807291d2015-01-27 13:40:23 -08002064 if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
Paul Stewart092955c2017-02-06 09:13:09 -08002065 return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002066 if (akm & WPA_KEY_MGMT_FILS_SHA256)
Paul Stewart092955c2017-02-06 09:13:09 -08002067 return RSN_AUTH_KEY_MGMT_FILS_SHA256;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002068 if (akm & WPA_KEY_MGMT_FILS_SHA384)
Paul Stewart092955c2017-02-06 09:13:09 -08002069 return RSN_AUTH_KEY_MGMT_FILS_SHA384;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002070 if (akm & WPA_KEY_MGMT_FT_FILS_SHA256)
Paul Stewart092955c2017-02-06 09:13:09 -08002071 return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002072 if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
Paul Stewart092955c2017-02-06 09:13:09 -08002073 return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
Hai Shalomc3565922019-10-28 11:58:20 -07002074 if (akm & WPA_KEY_MGMT_SAE)
2075 return RSN_AUTH_KEY_MGMT_SAE;
2076 if (akm & WPA_KEY_MGMT_FT_SAE)
2077 return RSN_AUTH_KEY_MGMT_FT_SAE;
2078 if (akm & WPA_KEY_MGMT_OWE)
2079 return RSN_AUTH_KEY_MGMT_OWE;
2080 if (akm & WPA_KEY_MGMT_DPP)
2081 return RSN_AUTH_KEY_MGMT_DPP;
2082 if (akm & WPA_KEY_MGMT_OSEN)
2083 return RSN_AUTH_KEY_MGMT_OSEN;
Dmitry Shmidt03658832014-08-13 11:03:49 -07002084 return 0;
2085}
2086
2087
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002088int wpa_compare_rsn_ie(int ft_initial_assoc,
2089 const u8 *ie1, size_t ie1len,
2090 const u8 *ie2, size_t ie2len)
2091{
2092 if (ie1 == NULL || ie2 == NULL)
2093 return -1;
2094
2095 if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
2096 return 0; /* identical IEs */
2097
2098#ifdef CONFIG_IEEE80211R
2099 if (ft_initial_assoc) {
2100 struct wpa_ie_data ie1d, ie2d;
2101 /*
2102 * The PMKID-List in RSN IE is different between Beacon/Probe
2103 * Response/(Re)Association Request frames and EAPOL-Key
2104 * messages in FT initial mobility domain association. Allow
2105 * for this, but verify that other parts of the RSN IEs are
2106 * identical.
2107 */
2108 if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
2109 wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
2110 return -1;
2111 if (ie1d.proto == ie2d.proto &&
2112 ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
2113 ie1d.group_cipher == ie2d.group_cipher &&
2114 ie1d.key_mgmt == ie2d.key_mgmt &&
2115 ie1d.capabilities == ie2d.capabilities &&
2116 ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
2117 return 0;
2118 }
2119#endif /* CONFIG_IEEE80211R */
2120
2121 return -1;
2122}
2123
2124
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002125int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002126{
2127 u8 *start, *end, *rpos, *rend;
2128 int added = 0;
2129
2130 start = ies;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002131 end = ies + *ies_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002132
2133 while (start < end) {
2134 if (*start == WLAN_EID_RSN)
2135 break;
2136 start += 2 + start[1];
2137 }
2138 if (start >= end) {
Hai Shalomc3565922019-10-28 11:58:20 -07002139 wpa_printf(MSG_ERROR, "RSN: Could not find RSNE in IEs data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002140 return -1;
2141 }
Hai Shalomc3565922019-10-28 11:58:20 -07002142 wpa_hexdump(MSG_DEBUG, "RSN: RSNE before modification",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002143 start, 2 + start[1]);
2144
2145 /* Find start of PMKID-Count */
2146 rpos = start + 2;
2147 rend = rpos + start[1];
2148
2149 /* Skip Version and Group Data Cipher Suite */
2150 rpos += 2 + 4;
2151 /* Skip Pairwise Cipher Suite Count and List */
2152 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2153 /* Skip AKM Suite Count and List */
2154 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
2155
2156 if (rpos == rend) {
2157 /* Add RSN Capabilities */
2158 os_memmove(rpos + 2, rpos, end - rpos);
2159 *rpos++ = 0;
2160 *rpos++ = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002161 added += 2;
2162 start[1] += 2;
2163 rend = rpos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002164 } else {
2165 /* Skip RSN Capabilities */
2166 rpos += 2;
2167 if (rpos > rend) {
Hai Shalomc3565922019-10-28 11:58:20 -07002168 wpa_printf(MSG_ERROR,
2169 "RSN: Could not parse RSNE in IEs data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002170 return -1;
2171 }
2172 }
2173
2174 if (rpos == rend) {
2175 /* No PMKID-Count field included; add it */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002176 os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002177 WPA_PUT_LE16(rpos, 1);
2178 rpos += 2;
2179 os_memcpy(rpos, pmkid, PMKID_LEN);
2180 added += 2 + PMKID_LEN;
2181 start[1] += 2 + PMKID_LEN;
2182 } else {
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002183 u16 num_pmkid;
2184
2185 if (rend - rpos < 2)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002186 return -1;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002187 num_pmkid = WPA_GET_LE16(rpos);
2188 /* PMKID-Count was included; use it */
2189 if (num_pmkid != 0) {
2190 u8 *after;
2191
2192 if (num_pmkid * PMKID_LEN > rend - rpos - 2)
2193 return -1;
2194 /*
2195 * PMKID may have been included in RSN IE in
2196 * (Re)Association Request frame, so remove the old
2197 * PMKID(s) first before adding the new one.
2198 */
2199 wpa_printf(MSG_DEBUG,
Hai Shalomc3565922019-10-28 11:58:20 -07002200 "RSN: Remove %u old PMKID(s) from RSNE",
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002201 num_pmkid);
2202 after = rpos + 2 + num_pmkid * PMKID_LEN;
2203 os_memmove(rpos + 2, after, rend - after);
2204 start[1] -= num_pmkid * PMKID_LEN;
2205 added -= num_pmkid * PMKID_LEN;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002206 }
2207 WPA_PUT_LE16(rpos, 1);
2208 rpos += 2;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002209 os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002210 os_memcpy(rpos, pmkid, PMKID_LEN);
2211 added += PMKID_LEN;
2212 start[1] += PMKID_LEN;
2213 }
2214
Hai Shalomc3565922019-10-28 11:58:20 -07002215 wpa_hexdump(MSG_DEBUG, "RSN: RSNE after modification (PMKID inserted)",
2216 start, 2 + start[1]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002217
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002218 *ies_len += added;
2219
2220 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002221}
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002222
2223
2224int wpa_cipher_key_len(int cipher)
2225{
2226 switch (cipher) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002227 case WPA_CIPHER_CCMP_256:
2228 case WPA_CIPHER_GCMP_256:
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002229 case WPA_CIPHER_BIP_GMAC_256:
2230 case WPA_CIPHER_BIP_CMAC_256:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002231 return 32;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002232 case WPA_CIPHER_CCMP:
2233 case WPA_CIPHER_GCMP:
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002234 case WPA_CIPHER_AES_128_CMAC:
2235 case WPA_CIPHER_BIP_GMAC_128:
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002236 return 16;
2237 case WPA_CIPHER_TKIP:
2238 return 32;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002239 }
2240
2241 return 0;
2242}
2243
2244
2245int wpa_cipher_rsc_len(int cipher)
2246{
2247 switch (cipher) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002248 case WPA_CIPHER_CCMP_256:
2249 case WPA_CIPHER_GCMP_256:
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002250 case WPA_CIPHER_CCMP:
2251 case WPA_CIPHER_GCMP:
2252 case WPA_CIPHER_TKIP:
2253 return 6;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002254 }
2255
2256 return 0;
2257}
2258
2259
Dmitry Shmidt29333592017-01-09 12:27:11 -08002260enum wpa_alg wpa_cipher_to_alg(int cipher)
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002261{
2262 switch (cipher) {
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002263 case WPA_CIPHER_CCMP_256:
2264 return WPA_ALG_CCMP_256;
2265 case WPA_CIPHER_GCMP_256:
2266 return WPA_ALG_GCMP_256;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002267 case WPA_CIPHER_CCMP:
2268 return WPA_ALG_CCMP;
2269 case WPA_CIPHER_GCMP:
2270 return WPA_ALG_GCMP;
2271 case WPA_CIPHER_TKIP:
2272 return WPA_ALG_TKIP;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002273 case WPA_CIPHER_AES_128_CMAC:
2274 return WPA_ALG_IGTK;
2275 case WPA_CIPHER_BIP_GMAC_128:
2276 return WPA_ALG_BIP_GMAC_128;
2277 case WPA_CIPHER_BIP_GMAC_256:
2278 return WPA_ALG_BIP_GMAC_256;
2279 case WPA_CIPHER_BIP_CMAC_256:
2280 return WPA_ALG_BIP_CMAC_256;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002281 }
2282 return WPA_ALG_NONE;
2283}
2284
2285
2286int wpa_cipher_valid_pairwise(int cipher)
2287{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002288 return cipher == WPA_CIPHER_CCMP_256 ||
2289 cipher == WPA_CIPHER_GCMP_256 ||
2290 cipher == WPA_CIPHER_CCMP ||
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002291 cipher == WPA_CIPHER_GCMP ||
2292 cipher == WPA_CIPHER_TKIP;
2293}
2294
2295
2296u32 wpa_cipher_to_suite(int proto, int cipher)
2297{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002298 if (cipher & WPA_CIPHER_CCMP_256)
2299 return RSN_CIPHER_SUITE_CCMP_256;
2300 if (cipher & WPA_CIPHER_GCMP_256)
2301 return RSN_CIPHER_SUITE_GCMP_256;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002302 if (cipher & WPA_CIPHER_CCMP)
2303 return (proto == WPA_PROTO_RSN ?
2304 RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
2305 if (cipher & WPA_CIPHER_GCMP)
2306 return RSN_CIPHER_SUITE_GCMP;
2307 if (cipher & WPA_CIPHER_TKIP)
2308 return (proto == WPA_PROTO_RSN ?
2309 RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002310 if (cipher & WPA_CIPHER_NONE)
2311 return (proto == WPA_PROTO_RSN ?
2312 RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002313 if (cipher & WPA_CIPHER_GTK_NOT_USED)
2314 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -07002315 if (cipher & WPA_CIPHER_AES_128_CMAC)
2316 return RSN_CIPHER_SUITE_AES_128_CMAC;
2317 if (cipher & WPA_CIPHER_BIP_GMAC_128)
2318 return RSN_CIPHER_SUITE_BIP_GMAC_128;
2319 if (cipher & WPA_CIPHER_BIP_GMAC_256)
2320 return RSN_CIPHER_SUITE_BIP_GMAC_256;
2321 if (cipher & WPA_CIPHER_BIP_CMAC_256)
2322 return RSN_CIPHER_SUITE_BIP_CMAC_256;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002323 return 0;
2324}
2325
2326
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002327int rsn_cipher_put_suites(u8 *start, int ciphers)
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002328{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002329 u8 *pos = start;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002330
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002331 if (ciphers & WPA_CIPHER_CCMP_256) {
2332 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
2333 pos += RSN_SELECTOR_LEN;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002334 }
2335 if (ciphers & WPA_CIPHER_GCMP_256) {
2336 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
2337 pos += RSN_SELECTOR_LEN;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002338 }
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002339 if (ciphers & WPA_CIPHER_CCMP) {
2340 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
2341 pos += RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002342 }
2343 if (ciphers & WPA_CIPHER_GCMP) {
2344 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
2345 pos += RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002346 }
2347 if (ciphers & WPA_CIPHER_TKIP) {
2348 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
2349 pos += RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002350 }
2351 if (ciphers & WPA_CIPHER_NONE) {
2352 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
2353 pos += RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002354 }
2355
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002356 return (pos - start) / RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002357}
2358
2359
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002360int wpa_cipher_put_suites(u8 *start, int ciphers)
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002361{
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002362 u8 *pos = start;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002363
2364 if (ciphers & WPA_CIPHER_CCMP) {
2365 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
2366 pos += WPA_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002367 }
2368 if (ciphers & WPA_CIPHER_TKIP) {
2369 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
2370 pos += WPA_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002371 }
2372 if (ciphers & WPA_CIPHER_NONE) {
2373 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
2374 pos += WPA_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002375 }
2376
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002377 return (pos - start) / RSN_SELECTOR_LEN;
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07002378}
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002379
2380
2381int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
2382{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002383 if (ciphers & WPA_CIPHER_CCMP_256)
2384 return WPA_CIPHER_CCMP_256;
2385 if (ciphers & WPA_CIPHER_GCMP_256)
2386 return WPA_CIPHER_GCMP_256;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002387 if (ciphers & WPA_CIPHER_CCMP)
2388 return WPA_CIPHER_CCMP;
2389 if (ciphers & WPA_CIPHER_GCMP)
2390 return WPA_CIPHER_GCMP;
2391 if (ciphers & WPA_CIPHER_TKIP)
2392 return WPA_CIPHER_TKIP;
2393 if (none_allowed && (ciphers & WPA_CIPHER_NONE))
2394 return WPA_CIPHER_NONE;
2395 return -1;
2396}
2397
2398
2399int wpa_pick_group_cipher(int ciphers)
2400{
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002401 if (ciphers & WPA_CIPHER_CCMP_256)
2402 return WPA_CIPHER_CCMP_256;
2403 if (ciphers & WPA_CIPHER_GCMP_256)
2404 return WPA_CIPHER_GCMP_256;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002405 if (ciphers & WPA_CIPHER_CCMP)
2406 return WPA_CIPHER_CCMP;
2407 if (ciphers & WPA_CIPHER_GCMP)
2408 return WPA_CIPHER_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002409 if (ciphers & WPA_CIPHER_GTK_NOT_USED)
2410 return WPA_CIPHER_GTK_NOT_USED;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002411 if (ciphers & WPA_CIPHER_TKIP)
2412 return WPA_CIPHER_TKIP;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002413 return -1;
2414}
2415
2416
2417int wpa_parse_cipher(const char *value)
2418{
2419 int val = 0, last;
2420 char *start, *end, *buf;
2421
2422 buf = os_strdup(value);
2423 if (buf == NULL)
2424 return -1;
2425 start = buf;
2426
2427 while (*start != '\0') {
2428 while (*start == ' ' || *start == '\t')
2429 start++;
2430 if (*start == '\0')
2431 break;
2432 end = start;
2433 while (*end != ' ' && *end != '\t' && *end != '\0')
2434 end++;
2435 last = *end == '\0';
2436 *end = '\0';
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002437 if (os_strcmp(start, "CCMP-256") == 0)
2438 val |= WPA_CIPHER_CCMP_256;
2439 else if (os_strcmp(start, "GCMP-256") == 0)
2440 val |= WPA_CIPHER_GCMP_256;
2441 else if (os_strcmp(start, "CCMP") == 0)
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002442 val |= WPA_CIPHER_CCMP;
2443 else if (os_strcmp(start, "GCMP") == 0)
2444 val |= WPA_CIPHER_GCMP;
2445 else if (os_strcmp(start, "TKIP") == 0)
2446 val |= WPA_CIPHER_TKIP;
2447 else if (os_strcmp(start, "WEP104") == 0)
2448 val |= WPA_CIPHER_WEP104;
2449 else if (os_strcmp(start, "WEP40") == 0)
2450 val |= WPA_CIPHER_WEP40;
2451 else if (os_strcmp(start, "NONE") == 0)
2452 val |= WPA_CIPHER_NONE;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002453 else if (os_strcmp(start, "GTK_NOT_USED") == 0)
2454 val |= WPA_CIPHER_GTK_NOT_USED;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002455 else if (os_strcmp(start, "AES-128-CMAC") == 0)
2456 val |= WPA_CIPHER_AES_128_CMAC;
2457 else if (os_strcmp(start, "BIP-GMAC-128") == 0)
2458 val |= WPA_CIPHER_BIP_GMAC_128;
2459 else if (os_strcmp(start, "BIP-GMAC-256") == 0)
2460 val |= WPA_CIPHER_BIP_GMAC_256;
2461 else if (os_strcmp(start, "BIP-CMAC-256") == 0)
2462 val |= WPA_CIPHER_BIP_CMAC_256;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002463 else {
2464 os_free(buf);
2465 return -1;
2466 }
2467
2468 if (last)
2469 break;
2470 start = end + 1;
2471 }
2472 os_free(buf);
2473
2474 return val;
2475}
2476
2477
2478int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
2479{
2480 char *pos = start;
2481 int ret;
2482
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002483 if (ciphers & WPA_CIPHER_CCMP_256) {
2484 ret = os_snprintf(pos, end - pos, "%sCCMP-256",
2485 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002486 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002487 return -1;
2488 pos += ret;
2489 }
2490 if (ciphers & WPA_CIPHER_GCMP_256) {
2491 ret = os_snprintf(pos, end - pos, "%sGCMP-256",
2492 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002493 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002494 return -1;
2495 pos += ret;
2496 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002497 if (ciphers & WPA_CIPHER_CCMP) {
2498 ret = os_snprintf(pos, end - pos, "%sCCMP",
2499 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002500 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002501 return -1;
2502 pos += ret;
2503 }
2504 if (ciphers & WPA_CIPHER_GCMP) {
2505 ret = os_snprintf(pos, end - pos, "%sGCMP",
2506 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002507 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002508 return -1;
2509 pos += ret;
2510 }
2511 if (ciphers & WPA_CIPHER_TKIP) {
2512 ret = os_snprintf(pos, end - pos, "%sTKIP",
2513 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002514 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002515 return -1;
2516 pos += ret;
2517 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002518 if (ciphers & WPA_CIPHER_AES_128_CMAC) {
2519 ret = os_snprintf(pos, end - pos, "%sAES-128-CMAC",
2520 pos == start ? "" : delim);
2521 if (os_snprintf_error(end - pos, ret))
2522 return -1;
2523 pos += ret;
2524 }
2525 if (ciphers & WPA_CIPHER_BIP_GMAC_128) {
2526 ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-128",
2527 pos == start ? "" : delim);
2528 if (os_snprintf_error(end - pos, ret))
2529 return -1;
2530 pos += ret;
2531 }
2532 if (ciphers & WPA_CIPHER_BIP_GMAC_256) {
2533 ret = os_snprintf(pos, end - pos, "%sBIP-GMAC-256",
2534 pos == start ? "" : delim);
2535 if (os_snprintf_error(end - pos, ret))
2536 return -1;
2537 pos += ret;
2538 }
2539 if (ciphers & WPA_CIPHER_BIP_CMAC_256) {
2540 ret = os_snprintf(pos, end - pos, "%sBIP-CMAC-256",
2541 pos == start ? "" : delim);
2542 if (os_snprintf_error(end - pos, ret))
2543 return -1;
2544 pos += ret;
2545 }
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002546 if (ciphers & WPA_CIPHER_NONE) {
2547 ret = os_snprintf(pos, end - pos, "%sNONE",
2548 pos == start ? "" : delim);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002549 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002550 return -1;
2551 pos += ret;
2552 }
2553
2554 return pos - start;
2555}
2556
2557
2558int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
2559{
2560 int pairwise = 0;
2561
2562 /* Select group cipher based on the enabled pairwise cipher suites */
2563 if (wpa & 1)
2564 pairwise |= wpa_pairwise;
2565 if (wpa & 2)
2566 pairwise |= rsn_pairwise;
2567
2568 if (pairwise & WPA_CIPHER_TKIP)
2569 return WPA_CIPHER_TKIP;
2570 if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
2571 return WPA_CIPHER_GCMP;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002572 if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
2573 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
2574 return WPA_CIPHER_GCMP_256;
2575 if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
2576 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
2577 return WPA_CIPHER_CCMP_256;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002578 return WPA_CIPHER_CCMP;
2579}
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002580
2581
2582#ifdef CONFIG_FILS
Dmitry Shmidt29333592017-01-09 12:27:11 -08002583int fils_domain_name_hash(const char *domain, u8 *hash)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002584{
2585 char buf[255], *wpos = buf;
2586 const char *pos = domain;
2587 size_t len;
Dmitry Shmidt29333592017-01-09 12:27:11 -08002588 const u8 *addr[1];
2589 u8 mac[SHA256_MAC_LEN];
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002590
2591 for (len = 0; len < sizeof(buf) && *pos; len++) {
2592 if (isalpha(*pos) && isupper(*pos))
2593 *wpos++ = tolower(*pos);
2594 else
2595 *wpos++ = *pos;
2596 pos++;
2597 }
2598
Dmitry Shmidt29333592017-01-09 12:27:11 -08002599 addr[0] = (const u8 *) buf;
2600 if (sha256_vector(1, addr, &len, mac) < 0)
2601 return -1;
2602 os_memcpy(hash, mac, 2);
2603 return 0;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002604}
2605#endif /* CONFIG_FILS */
Hai Shalomc3565922019-10-28 11:58:20 -07002606
2607
2608/**
2609 * wpa_parse_vendor_specific - Parse Vendor Specific IEs
2610 * @pos: Pointer to the IE header
2611 * @end: Pointer to the end of the Key Data buffer
2612 * @ie: Pointer to parsed IE data
2613 * Returns: 0 on success, 1 if end mark is found, -1 on failure
2614 */
2615static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
2616 struct wpa_eapol_ie_parse *ie)
2617{
2618 unsigned int oui;
2619
2620 if (pos[1] < 4) {
2621 wpa_printf(MSG_MSGDUMP,
2622 "Too short vendor specific IE ignored (len=%u)",
2623 pos[1]);
2624 return 1;
2625 }
2626
2627 oui = WPA_GET_BE24(&pos[2]);
2628 if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
2629 if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
2630 ie->wmm = &pos[2];
2631 ie->wmm_len = pos[1];
2632 wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
2633 ie->wmm, ie->wmm_len);
2634 } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
2635 ie->wmm = &pos[2];
2636 ie->wmm_len = pos[1];
2637 wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
2638 ie->wmm, ie->wmm_len);
2639 }
2640 }
2641 return 0;
2642}
2643
2644
2645/**
2646 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
2647 * @pos: Pointer to the IE header
2648 * @end: Pointer to the end of the Key Data buffer
2649 * @ie: Pointer to parsed IE data
2650 * Returns: 0 on success, 1 if end mark is found, -1 on failure
2651 */
2652static int wpa_parse_generic(const u8 *pos, const u8 *end,
2653 struct wpa_eapol_ie_parse *ie)
2654{
2655 if (pos[1] == 0)
2656 return 1;
2657
2658 if (pos[1] >= 6 &&
2659 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
2660 pos[2 + WPA_SELECTOR_LEN] == 1 &&
2661 pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
2662 ie->wpa_ie = pos;
2663 ie->wpa_ie_len = pos[1] + 2;
2664 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
2665 ie->wpa_ie, ie->wpa_ie_len);
2666 return 0;
2667 }
2668
2669 if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
2670 ie->osen = pos;
2671 ie->osen_len = pos[1] + 2;
2672 return 0;
2673 }
2674
2675 if (1 + RSN_SELECTOR_LEN < end - pos &&
2676 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
2677 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
2678 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
2679 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
2680 pos, pos[1] + 2);
2681 return 0;
2682 }
2683
2684 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
2685 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
2686 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
2687 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
2688 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
2689 pos, pos[1] + 2);
2690 return 0;
2691 }
2692
2693 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
2694 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
2695 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
2696 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
2697 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
2698 pos, pos[1] + 2);
2699 return 0;
2700 }
2701
2702 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
2703 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
2704 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
2705 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
2706 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
2707 pos, pos[1] + 2);
2708 return 0;
2709 }
2710
2711 if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
2712 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
2713 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
2714 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
2715 ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
2716 return 0;
2717 }
2718
2719 if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
2720 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
2721 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
2722 wpa_hexdump(MSG_DEBUG,
2723 "WPA: IP Address Allocation in EAPOL-Key",
2724 ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
2725 return 0;
2726 }
2727
2728 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
2729 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
2730 ie->oci = pos + 2 + RSN_SELECTOR_LEN;
2731 ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
2732 wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
2733 pos, pos[1] + 2);
2734 return 0;
2735 }
2736
2737 return 0;
2738}
2739
2740
2741/**
2742 * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
2743 * @buf: Pointer to the Key Data buffer
2744 * @len: Key Data Length
2745 * @ie: Pointer to parsed IE data
2746 * Returns: 0 on success, -1 on failure
2747 */
2748int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
2749{
2750 const u8 *pos, *end;
2751 int ret = 0;
2752
2753 os_memset(ie, 0, sizeof(*ie));
2754 for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
2755 if (pos[0] == 0xdd &&
2756 ((pos == buf + len - 1) || pos[1] == 0)) {
2757 /* Ignore padding */
2758 break;
2759 }
2760 if (2 + pos[1] > end - pos) {
2761 wpa_printf(MSG_DEBUG,
2762 "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
2763 pos[0], pos[1], (int) (pos - buf));
2764 wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
2765 ret = -1;
2766 break;
2767 }
2768 if (*pos == WLAN_EID_RSN) {
2769 ie->rsn_ie = pos;
2770 ie->rsn_ie_len = pos[1] + 2;
2771 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
2772 ie->rsn_ie, ie->rsn_ie_len);
2773 } else if (*pos == WLAN_EID_RSNX) {
2774 ie->rsnxe = pos;
2775 ie->rsnxe_len = pos[1] + 2;
2776 wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
2777 ie->rsnxe, ie->rsnxe_len);
2778 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
2779 ie->mdie = pos;
2780 ie->mdie_len = pos[1] + 2;
2781 wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
2782 ie->mdie, ie->mdie_len);
2783 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
2784 ie->ftie = pos;
2785 ie->ftie_len = pos[1] + 2;
2786 wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
2787 ie->ftie, ie->ftie_len);
2788 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
2789 if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
2790 ie->reassoc_deadline = pos;
2791 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
2792 "in EAPOL-Key",
2793 ie->reassoc_deadline, pos[1] + 2);
2794 } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
2795 ie->key_lifetime = pos;
2796 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
2797 "in EAPOL-Key",
2798 ie->key_lifetime, pos[1] + 2);
2799 } else {
2800 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
2801 "EAPOL-Key Key Data IE",
2802 pos, 2 + pos[1]);
2803 }
2804 } else if (*pos == WLAN_EID_LINK_ID) {
2805 if (pos[1] >= 18) {
2806 ie->lnkid = pos;
2807 ie->lnkid_len = pos[1] + 2;
2808 }
2809 } else if (*pos == WLAN_EID_EXT_CAPAB) {
2810 ie->ext_capab = pos;
2811 ie->ext_capab_len = pos[1] + 2;
2812 } else if (*pos == WLAN_EID_SUPP_RATES) {
2813 ie->supp_rates = pos;
2814 ie->supp_rates_len = pos[1] + 2;
2815 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
2816 ie->ext_supp_rates = pos;
2817 ie->ext_supp_rates_len = pos[1] + 2;
2818 } else if (*pos == WLAN_EID_HT_CAP &&
2819 pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
2820 ie->ht_capabilities = pos + 2;
2821 } else if (*pos == WLAN_EID_VHT_AID) {
2822 if (pos[1] >= 2)
2823 ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
2824 } else if (*pos == WLAN_EID_VHT_CAP &&
2825 pos[1] >= sizeof(struct ieee80211_vht_capabilities))
2826 {
2827 ie->vht_capabilities = pos + 2;
2828 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
2829 ie->qosinfo = pos[2];
2830 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
2831 ie->supp_channels = pos + 2;
2832 ie->supp_channels_len = pos[1];
2833 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
2834 /*
2835 * The value of the Length field of the Supported
2836 * Operating Classes element is between 2 and 253.
2837 * Silently skip invalid elements to avoid interop
2838 * issues when trying to use the value.
2839 */
2840 if (pos[1] >= 2 && pos[1] <= 253) {
2841 ie->supp_oper_classes = pos + 2;
2842 ie->supp_oper_classes_len = pos[1];
2843 }
2844 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
2845 ret = wpa_parse_generic(pos, end, ie);
2846 if (ret < 0)
2847 break;
2848 if (ret > 0) {
2849 ret = 0;
2850 break;
2851 }
2852
2853 ret = wpa_parse_vendor_specific(pos, end, ie);
2854 if (ret < 0)
2855 break;
2856 if (ret > 0) {
2857 ret = 0;
2858 break;
2859 }
2860 } else {
2861 wpa_hexdump(MSG_DEBUG,
2862 "WPA: Unrecognized EAPOL-Key Key Data IE",
2863 pos, 2 + pos[1]);
2864 }
2865 }
2866
2867 return ret;
2868}