]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/wpa_common.c
Add HMAC-SHA384
[thirdparty/hostap.git] / src / common / wpa_common.c
CommitLineData
6fc6879b
JM
1/*
2 * WPA/RSN - Shared functions for supplicant and authenticator
98cd3d1c 3 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10
11#include "common.h"
03da66bd
JM
12#include "crypto/md5.h"
13#include "crypto/sha1.h"
14#include "crypto/sha256.h"
15#include "crypto/aes_wrap.h"
16#include "crypto/crypto.h"
6fc6879b
JM
17#include "ieee802_11_defs.h"
18#include "defs.h"
19#include "wpa_common.h"
20
21
98cd3d1c
JM
22static unsigned int wpa_kck_len(int akmp)
23{
24 return 16;
25}
26
27
28static unsigned int wpa_kek_len(int akmp)
29{
30 return 16;
31}
32
33
6fc6879b
JM
34/**
35 * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
36 * @key: EAPOL-Key Key Confirmation Key (KCK)
98cd3d1c 37 * @key_len: KCK length in octets
929a2ea5 38 * @akmp: WPA_KEY_MGMT_* used in key derivation
6fc6879b
JM
39 * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
40 * @buf: Pointer to the beginning of the EAPOL header (version field)
41 * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
42 * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
43 * Returns: 0 on success, -1 on failure
44 *
45 * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
46 * to be cleared (all zeroes) when calling this function.
47 *
48 * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
49 * description of the Key MIC calculation. It includes packet data from the
50 * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
51 * happened during final editing of the standard and the correct behavior is
52 * defined in the last draft (IEEE 802.11i/D10).
53 */
98cd3d1c
JM
54int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
55 const u8 *buf, size_t len, u8 *mic)
6fc6879b 56{
929a2ea5 57 u8 hash[SHA256_MAC_LEN];
6fc6879b
JM
58
59 switch (ver) {
6e6909a9 60#ifndef CONFIG_FIPS
6fc6879b 61 case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
98cd3d1c 62 return hmac_md5(key, key_len, buf, len, mic);
6e6909a9 63#endif /* CONFIG_FIPS */
6fc6879b 64 case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
98cd3d1c 65 if (hmac_sha1(key, key_len, buf, len, hash))
04b6b3ed 66 return -1;
6fc6879b
JM
67 os_memcpy(mic, hash, MD5_MAC_LEN);
68 break;
a20088e5 69#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
6fc6879b
JM
70 case WPA_KEY_INFO_TYPE_AES_128_CMAC:
71 return omac1_aes_128(key, buf, len, mic);
a20088e5 72#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
a5d75636 73 case WPA_KEY_INFO_TYPE_AKM_DEFINED:
929a2ea5
JM
74 switch (akmp) {
75#ifdef CONFIG_HS20
76 case WPA_KEY_MGMT_OSEN:
77 return omac1_aes_128(key, buf, len, mic);
a5d75636 78#endif /* CONFIG_HS20 */
929a2ea5
JM
79#ifdef CONFIG_SUITEB
80 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
98cd3d1c 81 if (hmac_sha256(key, key_len, buf, len, hash))
929a2ea5
JM
82 return -1;
83 os_memcpy(mic, hash, MD5_MAC_LEN);
84 break;
85#endif /* CONFIG_SUITEB */
86 default:
87 return -1;
88 }
89 break;
6fc6879b
JM
90 default:
91 return -1;
92 }
93
94 return 0;
95}
96
97
98/**
99 * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
100 * @pmk: Pairwise master key
101 * @pmk_len: Length of PMK
102 * @label: Label to use in derivation
103 * @addr1: AA or SA
104 * @addr2: SA or AA
105 * @nonce1: ANonce or SNonce
106 * @nonce2: SNonce or ANonce
107 * @ptk: Buffer for pairwise transient key
98cd3d1c
JM
108 * @akmp: Negotiated AKM
109 * @cipher: Negotiated pairwise cipher
110 * Returns: 0 on success, -1 on failure
6fc6879b
JM
111 *
112 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
113 * PTK = PRF-X(PMK, "Pairwise key expansion",
114 * Min(AA, SA) || Max(AA, SA) ||
115 * Min(ANonce, SNonce) || Max(ANonce, SNonce))
116 *
117 * STK = PRF-X(SMK, "Peer key expansion",
118 * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
119 * Min(INonce, PNonce) || Max(INonce, PNonce))
120 */
98cd3d1c
JM
121int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
122 const u8 *addr1, const u8 *addr2,
123 const u8 *nonce1, const u8 *nonce2,
124 struct wpa_ptk *ptk, int akmp, int cipher)
6fc6879b
JM
125{
126 u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
98cd3d1c
JM
127 u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
128 size_t ptk_len;
6fc6879b
JM
129
130 if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
131 os_memcpy(data, addr1, ETH_ALEN);
132 os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
133 } else {
134 os_memcpy(data, addr2, ETH_ALEN);
135 os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
136 }
137
138 if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
139 os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
140 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
141 WPA_NONCE_LEN);
142 } else {
143 os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
144 os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
145 WPA_NONCE_LEN);
146 }
147
98cd3d1c
JM
148 ptk->kck_len = wpa_kck_len(akmp);
149 ptk->kek_len = wpa_kek_len(akmp);
150 ptk->tk_len = wpa_cipher_key_len(cipher);
151 ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
152
56586197 153#ifdef CONFIG_IEEE80211W
98cd3d1c 154 if (wpa_key_mgmt_sha256(akmp))
56586197 155 sha256_prf(pmk, pmk_len, label, data, sizeof(data),
98cd3d1c 156 tmp, ptk_len);
56586197
JM
157 else
158#endif /* CONFIG_IEEE80211W */
98cd3d1c 159 sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
6fc6879b
JM
160
161 wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
162 MAC2STR(addr1), MAC2STR(addr2));
bc8318ac
JM
163 wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
164 wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
6fc6879b 165 wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
98cd3d1c
JM
166 wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
167
168 os_memcpy(ptk->kck, tmp, ptk->kck_len);
169 wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
170
171 os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
172 wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
173
174 os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
175 wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
176
177 os_memset(tmp, 0, sizeof(tmp));
178 return 0;
6fc6879b
JM
179}
180
181
182#ifdef CONFIG_IEEE80211R
98cd3d1c
JM
183int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
184 const u8 *ap_addr, u8 transaction_seqnum,
185 const u8 *mdie, size_t mdie_len,
6fc6879b
JM
186 const u8 *ftie, size_t ftie_len,
187 const u8 *rsnie, size_t rsnie_len,
188 const u8 *ric, size_t ric_len, u8 *mic)
189{
190 u8 *buf, *pos;
191 size_t buf_len;
192
98cd3d1c
JM
193 if (kck_len != 16) {
194 wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
195 (unsigned int) kck_len);
196 return -1;
197 }
198
6fc6879b
JM
199 buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
200 buf = os_malloc(buf_len);
201 if (buf == NULL)
202 return -1;
203
204 pos = buf;
205 os_memcpy(pos, sta_addr, ETH_ALEN);
206 pos += ETH_ALEN;
207 os_memcpy(pos, ap_addr, ETH_ALEN);
208 pos += ETH_ALEN;
209 *pos++ = transaction_seqnum;
210 if (rsnie) {
211 os_memcpy(pos, rsnie, rsnie_len);
212 pos += rsnie_len;
213 }
214 if (mdie) {
215 os_memcpy(pos, mdie, mdie_len);
216 pos += mdie_len;
217 }
218 if (ftie) {
219 struct rsn_ftie *_ftie;
220 os_memcpy(pos, ftie, ftie_len);
221 if (ftie_len < 2 + sizeof(*_ftie)) {
222 os_free(buf);
223 return -1;
224 }
225 _ftie = (struct rsn_ftie *) (pos + 2);
226 os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
227 pos += ftie_len;
228 }
229 if (ric) {
230 os_memcpy(pos, ric, ric_len);
231 pos += ric_len;
232 }
233
234 wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
235 if (omac1_aes_128(kck, buf, pos - buf, mic)) {
236 os_free(buf);
237 return -1;
238 }
239
240 os_free(buf);
241
242 return 0;
243}
6554237f
JM
244
245
246static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
247 struct wpa_ft_ies *parse)
248{
249 const u8 *end, *pos;
250
251 parse->ftie = ie;
252 parse->ftie_len = ie_len;
253
254 pos = ie + sizeof(struct rsn_ftie);
255 end = ie + ie_len;
256
257 while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
258 switch (pos[0]) {
259 case FTIE_SUBELEM_R1KH_ID:
260 if (pos[1] != FT_R1KH_ID_LEN) {
261 wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
262 "length in FTIE: %d", pos[1]);
263 return -1;
264 }
265 parse->r1kh_id = pos + 2;
266 break;
267 case FTIE_SUBELEM_GTK:
268 parse->gtk = pos + 2;
269 parse->gtk_len = pos[1];
270 break;
271 case FTIE_SUBELEM_R0KH_ID:
272 if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
273 wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
274 "length in FTIE: %d", pos[1]);
275 return -1;
276 }
277 parse->r0kh_id = pos + 2;
278 parse->r0kh_id_len = pos[1];
279 break;
280#ifdef CONFIG_IEEE80211W
281 case FTIE_SUBELEM_IGTK:
282 parse->igtk = pos + 2;
283 parse->igtk_len = pos[1];
284 break;
285#endif /* CONFIG_IEEE80211W */
286 }
287
288 pos += 2 + pos[1];
289 }
290
291 return 0;
292}
293
294
295int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
296 struct wpa_ft_ies *parse)
297{
298 const u8 *end, *pos;
299 struct wpa_ie_data data;
300 int ret;
301 const struct rsn_ftie *ftie;
302 int prot_ie_count = 0;
303
304 os_memset(parse, 0, sizeof(*parse));
305 if (ies == NULL)
306 return 0;
307
308 pos = ies;
309 end = ies + ies_len;
310 while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
311 switch (pos[0]) {
312 case WLAN_EID_RSN:
313 parse->rsn = pos + 2;
314 parse->rsn_len = pos[1];
315 ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
316 parse->rsn_len + 2,
317 &data);
318 if (ret < 0) {
319 wpa_printf(MSG_DEBUG, "FT: Failed to parse "
320 "RSN IE: %d", ret);
321 return -1;
322 }
323 if (data.num_pmkid == 1 && data.pmkid)
324 parse->rsn_pmkid = data.pmkid;
325 break;
326 case WLAN_EID_MOBILITY_DOMAIN:
327 parse->mdie = pos + 2;
328 parse->mdie_len = pos[1];
329 break;
330 case WLAN_EID_FAST_BSS_TRANSITION:
331 if (pos[1] < sizeof(*ftie))
332 return -1;
333 ftie = (const struct rsn_ftie *) (pos + 2);
334 prot_ie_count = ftie->mic_control[1];
335 if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
336 return -1;
337 break;
338 case WLAN_EID_TIMEOUT_INTERVAL:
339 parse->tie = pos + 2;
340 parse->tie_len = pos[1];
341 break;
342 case WLAN_EID_RIC_DATA:
343 if (parse->ric == NULL)
344 parse->ric = pos;
345 break;
346 }
347
348 pos += 2 + pos[1];
349 }
350
351 if (prot_ie_count == 0)
352 return 0; /* no MIC */
353
354 /*
355 * Check that the protected IE count matches with IEs included in the
356 * frame.
357 */
358 if (parse->rsn)
359 prot_ie_count--;
360 if (parse->mdie)
361 prot_ie_count--;
362 if (parse->ftie)
363 prot_ie_count--;
364 if (prot_ie_count < 0) {
365 wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
366 "the protected IE count");
367 return -1;
368 }
369
370 if (prot_ie_count == 0 && parse->ric) {
371 wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
372 "included in protected IE count");
373 return -1;
374 }
375
376 /* Determine the end of the RIC IE(s) */
377 pos = parse->ric;
378 while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
379 prot_ie_count) {
380 prot_ie_count--;
381 pos += 2 + pos[1];
382 }
383 parse->ric_len = pos - parse->ric;
384 if (prot_ie_count) {
385 wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
386 "frame", (int) prot_ie_count);
387 return -1;
388 }
389
390 return 0;
391}
6fc6879b
JM
392#endif /* CONFIG_IEEE80211R */
393
394
6fc6879b
JM
395static int rsn_selector_to_bitfield(const u8 *s)
396{
397 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
398 return WPA_CIPHER_NONE;
399 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
400 return WPA_CIPHER_WEP40;
401 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
402 return WPA_CIPHER_TKIP;
403 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
404 return WPA_CIPHER_CCMP;
405 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
406 return WPA_CIPHER_WEP104;
407#ifdef CONFIG_IEEE80211W
408 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
409 return WPA_CIPHER_AES_128_CMAC;
410#endif /* CONFIG_IEEE80211W */
eb7719ff
JM
411 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
412 return WPA_CIPHER_GCMP;
30675c34
JM
413 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP_256)
414 return WPA_CIPHER_CCMP_256;
415 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP_256)
416 return WPA_CIPHER_GCMP_256;
417 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_128)
418 return WPA_CIPHER_BIP_GMAC_128;
419 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_GMAC_256)
420 return WPA_CIPHER_BIP_GMAC_256;
421 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256)
422 return WPA_CIPHER_BIP_CMAC_256;
8dd9f9cd
JM
423 if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
424 return WPA_CIPHER_GTK_NOT_USED;
6fc6879b
JM
425 return 0;
426}
427
428
429static int rsn_key_mgmt_to_bitfield(const u8 *s)
430{
431 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
432 return WPA_KEY_MGMT_IEEE8021X;
433 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
434 return WPA_KEY_MGMT_PSK;
435#ifdef CONFIG_IEEE80211R
436 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
437 return WPA_KEY_MGMT_FT_IEEE8021X;
438 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
439 return WPA_KEY_MGMT_FT_PSK;
440#endif /* CONFIG_IEEE80211R */
56586197
JM
441#ifdef CONFIG_IEEE80211W
442 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
443 return WPA_KEY_MGMT_IEEE8021X_SHA256;
444 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
445 return WPA_KEY_MGMT_PSK_SHA256;
446#endif /* CONFIG_IEEE80211W */
c10347f2
JM
447#ifdef CONFIG_SAE
448 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
449 return WPA_KEY_MGMT_SAE;
450 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
451 return WPA_KEY_MGMT_FT_SAE;
452#endif /* CONFIG_SAE */
666497c8
JM
453 if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
454 return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
6fc6879b
JM
455 return 0;
456}
6fc6879b
JM
457
458
8dd9f9cd
JM
459static int wpa_cipher_valid_group(int cipher)
460{
461 return wpa_cipher_valid_pairwise(cipher) ||
462 cipher == WPA_CIPHER_WEP104 ||
463 cipher == WPA_CIPHER_WEP40 ||
464 cipher == WPA_CIPHER_GTK_NOT_USED;
465}
466
467
468#ifdef CONFIG_IEEE80211W
469int wpa_cipher_valid_mgmt_group(int cipher)
470{
471 return cipher == WPA_CIPHER_AES_128_CMAC ||
472 cipher == WPA_CIPHER_BIP_GMAC_128 ||
473 cipher == WPA_CIPHER_BIP_GMAC_256 ||
474 cipher == WPA_CIPHER_BIP_CMAC_256;
475}
476#endif /* CONFIG_IEEE80211W */
477
478
6fc6879b
JM
479/**
480 * wpa_parse_wpa_ie_rsn - Parse RSN IE
481 * @rsn_ie: Buffer containing RSN IE
482 * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
483 * @data: Pointer to structure that will be filled in with parsed data
484 * Returns: 0 on success, <0 on failure
485 */
486int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
487 struct wpa_ie_data *data)
488{
6fc6879b
JM
489 const struct rsn_ie_hdr *hdr;
490 const u8 *pos;
491 int left;
492 int i, count;
493
494 os_memset(data, 0, sizeof(*data));
495 data->proto = WPA_PROTO_RSN;
496 data->pairwise_cipher = WPA_CIPHER_CCMP;
497 data->group_cipher = WPA_CIPHER_CCMP;
498 data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
499 data->capabilities = 0;
500 data->pmkid = NULL;
501 data->num_pmkid = 0;
502#ifdef CONFIG_IEEE80211W
503 data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
504#else /* CONFIG_IEEE80211W */
505 data->mgmt_group_cipher = 0;
506#endif /* CONFIG_IEEE80211W */
507
508 if (rsn_ie_len == 0) {
509 /* No RSN IE - fail silently */
510 return -1;
511 }
512
513 if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
514 wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
515 __func__, (unsigned long) rsn_ie_len);
516 return -1;
517 }
518
519 hdr = (const struct rsn_ie_hdr *) rsn_ie;
520
521 if (hdr->elem_id != WLAN_EID_RSN ||
522 hdr->len != rsn_ie_len - 2 ||
523 WPA_GET_LE16(hdr->version) != RSN_VERSION) {
524 wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
525 __func__);
526 return -2;
527 }
528
529 pos = (const u8 *) (hdr + 1);
530 left = rsn_ie_len - sizeof(*hdr);
531
532 if (left >= RSN_SELECTOR_LEN) {
533 data->group_cipher = rsn_selector_to_bitfield(pos);
8dd9f9cd
JM
534 if (!wpa_cipher_valid_group(data->group_cipher)) {
535 wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x",
536 __func__, data->group_cipher);
6fc6879b
JM
537 return -1;
538 }
6fc6879b
JM
539 pos += RSN_SELECTOR_LEN;
540 left -= RSN_SELECTOR_LEN;
541 } else if (left > 0) {
542 wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
543 __func__, left);
544 return -3;
545 }
546
547 if (left >= 2) {
548 data->pairwise_cipher = 0;
549 count = WPA_GET_LE16(pos);
550 pos += 2;
551 left -= 2;
649c0a69 552 if (count == 0 || count > left / RSN_SELECTOR_LEN) {
6fc6879b
JM
553 wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
554 "count %u left %u", __func__, count, left);
555 return -4;
556 }
557 for (i = 0; i < count; i++) {
558 data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
559 pos += RSN_SELECTOR_LEN;
560 left -= RSN_SELECTOR_LEN;
561 }
562#ifdef CONFIG_IEEE80211W
563 if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
564 wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
565 "pairwise cipher", __func__);
566 return -1;
567 }
568#endif /* CONFIG_IEEE80211W */
569 } else if (left == 1) {
570 wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
571 __func__);
572 return -5;
573 }
574
575 if (left >= 2) {
576 data->key_mgmt = 0;
577 count = WPA_GET_LE16(pos);
578 pos += 2;
579 left -= 2;
649c0a69 580 if (count == 0 || count > left / RSN_SELECTOR_LEN) {
6fc6879b
JM
581 wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
582 "count %u left %u", __func__, count, left);
583 return -6;
584 }
585 for (i = 0; i < count; i++) {
586 data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
587 pos += RSN_SELECTOR_LEN;
588 left -= RSN_SELECTOR_LEN;
589 }
590 } else if (left == 1) {
591 wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
592 __func__);
593 return -7;
594 }
595
596 if (left >= 2) {
597 data->capabilities = WPA_GET_LE16(pos);
598 pos += 2;
599 left -= 2;
600 }
601
602 if (left >= 2) {
46a03525 603 u16 num_pmkid = WPA_GET_LE16(pos);
6fc6879b
JM
604 pos += 2;
605 left -= 2;
46a03525 606 if (num_pmkid > (unsigned int) left / PMKID_LEN) {
6fc6879b 607 wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
46a03525
JM
608 "(num_pmkid=%u left=%d)",
609 __func__, num_pmkid, left);
6fc6879b
JM
610 data->num_pmkid = 0;
611 return -9;
612 } else {
46a03525 613 data->num_pmkid = num_pmkid;
6fc6879b
JM
614 data->pmkid = pos;
615 pos += data->num_pmkid * PMKID_LEN;
616 left -= data->num_pmkid * PMKID_LEN;
617 }
618 }
619
620#ifdef CONFIG_IEEE80211W
621 if (left >= 4) {
622 data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
8dd9f9cd 623 if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
6fc6879b
JM
624 wpa_printf(MSG_DEBUG, "%s: Unsupported management "
625 "group cipher 0x%x", __func__,
626 data->mgmt_group_cipher);
627 return -10;
628 }
629 pos += RSN_SELECTOR_LEN;
630 left -= RSN_SELECTOR_LEN;
631 }
632#endif /* CONFIG_IEEE80211W */
633
634 if (left > 0) {
749fa140
JM
635 wpa_hexdump(MSG_DEBUG,
636 "wpa_parse_wpa_ie_rsn: ignore trailing bytes",
637 pos, left);
6fc6879b
JM
638 }
639
640 return 0;
6fc6879b
JM
641}
642
643
f3b87561
JM
644static int wpa_selector_to_bitfield(const u8 *s)
645{
646 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
647 return WPA_CIPHER_NONE;
648 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
649 return WPA_CIPHER_WEP40;
650 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
651 return WPA_CIPHER_TKIP;
652 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
653 return WPA_CIPHER_CCMP;
654 if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
655 return WPA_CIPHER_WEP104;
656 return 0;
657}
658
659
660static int wpa_key_mgmt_to_bitfield(const u8 *s)
661{
662 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
663 return WPA_KEY_MGMT_IEEE8021X;
664 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
665 return WPA_KEY_MGMT_PSK;
666 if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
667 return WPA_KEY_MGMT_WPA_NONE;
668 return 0;
669}
670
671
672int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
673 struct wpa_ie_data *data)
674{
675 const struct wpa_ie_hdr *hdr;
676 const u8 *pos;
677 int left;
678 int i, count;
679
680 os_memset(data, 0, sizeof(*data));
681 data->proto = WPA_PROTO_WPA;
682 data->pairwise_cipher = WPA_CIPHER_TKIP;
683 data->group_cipher = WPA_CIPHER_TKIP;
684 data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
685 data->capabilities = 0;
686 data->pmkid = NULL;
687 data->num_pmkid = 0;
688 data->mgmt_group_cipher = 0;
689
690 if (wpa_ie_len == 0) {
691 /* No WPA IE - fail silently */
692 return -1;
693 }
694
695 if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
696 wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
697 __func__, (unsigned long) wpa_ie_len);
698 return -1;
699 }
700
701 hdr = (const struct wpa_ie_hdr *) wpa_ie;
702
703 if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
704 hdr->len != wpa_ie_len - 2 ||
705 RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
706 WPA_GET_LE16(hdr->version) != WPA_VERSION) {
707 wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
708 __func__);
709 return -2;
710 }
711
712 pos = (const u8 *) (hdr + 1);
713 left = wpa_ie_len - sizeof(*hdr);
714
715 if (left >= WPA_SELECTOR_LEN) {
716 data->group_cipher = wpa_selector_to_bitfield(pos);
717 pos += WPA_SELECTOR_LEN;
718 left -= WPA_SELECTOR_LEN;
719 } else if (left > 0) {
720 wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
721 __func__, left);
722 return -3;
723 }
724
725 if (left >= 2) {
726 data->pairwise_cipher = 0;
727 count = WPA_GET_LE16(pos);
728 pos += 2;
729 left -= 2;
649c0a69 730 if (count == 0 || count > left / WPA_SELECTOR_LEN) {
f3b87561
JM
731 wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
732 "count %u left %u", __func__, count, left);
733 return -4;
734 }
735 for (i = 0; i < count; i++) {
736 data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
737 pos += WPA_SELECTOR_LEN;
738 left -= WPA_SELECTOR_LEN;
739 }
740 } else if (left == 1) {
741 wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
742 __func__);
743 return -5;
744 }
745
746 if (left >= 2) {
747 data->key_mgmt = 0;
748 count = WPA_GET_LE16(pos);
749 pos += 2;
750 left -= 2;
649c0a69 751 if (count == 0 || count > left / WPA_SELECTOR_LEN) {
f3b87561
JM
752 wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
753 "count %u left %u", __func__, count, left);
754 return -6;
755 }
756 for (i = 0; i < count; i++) {
757 data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
758 pos += WPA_SELECTOR_LEN;
759 left -= WPA_SELECTOR_LEN;
760 }
761 } else if (left == 1) {
762 wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
763 __func__);
764 return -7;
765 }
766
767 if (left >= 2) {
768 data->capabilities = WPA_GET_LE16(pos);
769 pos += 2;
770 left -= 2;
771 }
772
773 if (left > 0) {
749fa140
JM
774 wpa_hexdump(MSG_DEBUG,
775 "wpa_parse_wpa_ie_wpa: ignore trailing bytes",
776 pos, left);
f3b87561
JM
777 }
778
779 return 0;
780}
781
782
6fc6879b
JM
783#ifdef CONFIG_IEEE80211R
784
785/**
786 * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
787 *
c1e033b0 788 * IEEE Std 802.11r-2008 - 8.5.1.5.3
6fc6879b
JM
789 */
790void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
791 const u8 *ssid, size_t ssid_len,
792 const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
793 const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
794{
795 u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
796 FT_R0KH_ID_MAX_LEN + ETH_ALEN];
797 u8 *pos, r0_key_data[48], hash[32];
798 const u8 *addr[2];
799 size_t len[2];
800
801 /*
802 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
803 * SSIDlength || SSID || MDID || R0KHlength ||
804 * R0KH-ID || S0KH-ID)
805 * XXKey is either the second 256 bits of MSK or PSK.
806 * PMK-R0 = L(R0-Key-Data, 0, 256)
807 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
808 */
809 if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
810 return;
811 pos = buf;
812 *pos++ = ssid_len;
813 os_memcpy(pos, ssid, ssid_len);
814 pos += ssid_len;
815 os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
816 pos += MOBILITY_DOMAIN_ID_LEN;
817 *pos++ = r0kh_id_len;
818 os_memcpy(pos, r0kh_id, r0kh_id_len);
819 pos += r0kh_id_len;
820 os_memcpy(pos, s0kh_id, ETH_ALEN);
821 pos += ETH_ALEN;
822
823 sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
824 r0_key_data, sizeof(r0_key_data));
825 os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
826
827 /*
828 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
829 */
830 addr[0] = (const u8 *) "FT-R0N";
831 len[0] = 6;
832 addr[1] = r0_key_data + PMK_LEN;
833 len[1] = 16;
834
835 sha256_vector(2, addr, len, hash);
836 os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
837}
838
839
840/**
841 * wpa_derive_pmk_r1_name - Derive PMKR1Name
842 *
c1e033b0 843 * IEEE Std 802.11r-2008 - 8.5.1.5.4
6fc6879b
JM
844 */
845void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
846 const u8 *s1kh_id, u8 *pmk_r1_name)
847{
848 u8 hash[32];
849 const u8 *addr[4];
850 size_t len[4];
851
852 /*
853 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
854 * R1KH-ID || S1KH-ID))
855 */
856 addr[0] = (const u8 *) "FT-R1N";
857 len[0] = 6;
858 addr[1] = pmk_r0_name;
859 len[1] = WPA_PMK_NAME_LEN;
860 addr[2] = r1kh_id;
861 len[2] = FT_R1KH_ID_LEN;
862 addr[3] = s1kh_id;
863 len[3] = ETH_ALEN;
864
865 sha256_vector(4, addr, len, hash);
866 os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
867}
868
869
870/**
871 * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
872 *
c1e033b0 873 * IEEE Std 802.11r-2008 - 8.5.1.5.4
6fc6879b
JM
874 */
875void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
876 const u8 *r1kh_id, const u8 *s1kh_id,
877 u8 *pmk_r1, u8 *pmk_r1_name)
878{
879 u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
880 u8 *pos;
881
882 /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
883 pos = buf;
884 os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
885 pos += FT_R1KH_ID_LEN;
886 os_memcpy(pos, s1kh_id, ETH_ALEN);
887 pos += ETH_ALEN;
888
889 sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
890
891 wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
892}
893
894
895/**
896 * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
897 *
c1e033b0 898 * IEEE Std 802.11r-2008 - 8.5.1.5.5
6fc6879b 899 */
98cd3d1c
JM
900int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
901 const u8 *sta_addr, const u8 *bssid,
902 const u8 *pmk_r1_name,
903 struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
6fc6879b
JM
904{
905 u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
906 u8 *pos, hash[32];
907 const u8 *addr[6];
908 size_t len[6];
98cd3d1c
JM
909 u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
910 size_t ptk_len;
6fc6879b
JM
911
912 /*
913 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
914 * BSSID || STA-ADDR)
915 */
916 pos = buf;
917 os_memcpy(pos, snonce, WPA_NONCE_LEN);
918 pos += WPA_NONCE_LEN;
919 os_memcpy(pos, anonce, WPA_NONCE_LEN);
920 pos += WPA_NONCE_LEN;
921 os_memcpy(pos, bssid, ETH_ALEN);
922 pos += ETH_ALEN;
923 os_memcpy(pos, sta_addr, ETH_ALEN);
924 pos += ETH_ALEN;
925
98cd3d1c
JM
926 ptk->kck_len = wpa_kck_len(akmp);
927 ptk->kek_len = wpa_kek_len(akmp);
928 ptk->tk_len = wpa_cipher_key_len(cipher);
929 ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
930
931 sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
6fc6879b
JM
932
933 /*
934 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
935 * ANonce || BSSID || STA-ADDR))
936 */
937 addr[0] = pmk_r1_name;
938 len[0] = WPA_PMK_NAME_LEN;
939 addr[1] = (const u8 *) "FT-PTKN";
940 len[1] = 7;
941 addr[2] = snonce;
942 len[2] = WPA_NONCE_LEN;
943 addr[3] = anonce;
944 len[3] = WPA_NONCE_LEN;
945 addr[4] = bssid;
946 len[4] = ETH_ALEN;
947 addr[5] = sta_addr;
948 len[5] = ETH_ALEN;
949
950 sha256_vector(6, addr, len, hash);
951 os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
98cd3d1c
JM
952
953 os_memcpy(ptk->kck, tmp, ptk->kck_len);
954 os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
955 os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
956
957 wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
958 wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
959 wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
960 wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
961
962 os_memset(tmp, 0, sizeof(tmp));
963
964 return 0;
6fc6879b
JM
965}
966
967#endif /* CONFIG_IEEE80211R */
13268290
JM
968
969
970/**
971 * rsn_pmkid - Calculate PMK identifier
972 * @pmk: Pairwise master key
973 * @pmk_len: Length of pmk in bytes
974 * @aa: Authenticator address
975 * @spa: Supplicant address
976 * @pmkid: Buffer for PMKID
977 * @use_sha256: Whether to use SHA256-based KDF
978 *
979 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
980 * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
981 */
982void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
983 u8 *pmkid, int use_sha256)
984{
985 char *title = "PMK Name";
986 const u8 *addr[3];
987 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
988 unsigned char hash[SHA256_MAC_LEN];
989
990 addr[0] = (u8 *) title;
991 addr[1] = aa;
992 addr[2] = spa;
993
994#ifdef CONFIG_IEEE80211W
995 if (use_sha256)
996 hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
997 else
998#endif /* CONFIG_IEEE80211W */
999 hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
1000 os_memcpy(pmkid, hash, PMKID_LEN);
1001}
43fb5297
JM
1002
1003
087a1f4e
JM
1004#ifdef CONFIG_SUITEB
1005/**
1006 * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
1007 * @kck: Key confirmation key
1008 * @kck_len: Length of kck in bytes
1009 * @aa: Authenticator address
1010 * @spa: Supplicant address
1011 * @pmkid: Buffer for PMKID
1012 * Returns: 0 on success, -1 on failure
1013 *
1014 * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
1015 * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
1016 */
1017int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
1018 const u8 *spa, u8 *pmkid)
1019{
1020 char *title = "PMK Name";
1021 const u8 *addr[3];
1022 const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
1023 unsigned char hash[SHA256_MAC_LEN];
1024
1025 addr[0] = (u8 *) title;
1026 addr[1] = aa;
1027 addr[2] = spa;
1028
1029 if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
1030 return -1;
1031 os_memcpy(pmkid, hash, PMKID_LEN);
1032 return 0;
1033}
1034#endif /* CONFIG_SUITEB */
1035
1036
43fb5297
JM
1037/**
1038 * wpa_cipher_txt - Convert cipher suite to a text string
1039 * @cipher: Cipher suite (WPA_CIPHER_* enum)
1040 * Returns: Pointer to a text string of the cipher suite name
1041 */
1042const char * wpa_cipher_txt(int cipher)
1043{
1044 switch (cipher) {
1045 case WPA_CIPHER_NONE:
1046 return "NONE";
1047 case WPA_CIPHER_WEP40:
1048 return "WEP-40";
1049 case WPA_CIPHER_WEP104:
1050 return "WEP-104";
1051 case WPA_CIPHER_TKIP:
1052 return "TKIP";
1053 case WPA_CIPHER_CCMP:
1054 return "CCMP";
1055 case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
1056 return "CCMP+TKIP";
eb7719ff
JM
1057 case WPA_CIPHER_GCMP:
1058 return "GCMP";
30675c34
JM
1059 case WPA_CIPHER_GCMP_256:
1060 return "GCMP-256";
1061 case WPA_CIPHER_CCMP_256:
1062 return "CCMP-256";
dff1e285
JM
1063 case WPA_CIPHER_GTK_NOT_USED:
1064 return "GTK_NOT_USED";
43fb5297
JM
1065 default:
1066 return "UNKNOWN";
1067 }
1068}
1069
1070
1071/**
1072 * wpa_key_mgmt_txt - Convert key management suite to a text string
1073 * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
1074 * @proto: WPA/WPA2 version (WPA_PROTO_*)
1075 * Returns: Pointer to a text string of the key management suite name
1076 */
1077const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
1078{
1079 switch (key_mgmt) {
1080 case WPA_KEY_MGMT_IEEE8021X:
1081 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1082 return "WPA2+WPA/IEEE 802.1X/EAP";
1083 return proto == WPA_PROTO_RSN ?
1084 "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
1085 case WPA_KEY_MGMT_PSK:
1086 if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
1087 return "WPA2-PSK+WPA-PSK";
1088 return proto == WPA_PROTO_RSN ?
1089 "WPA2-PSK" : "WPA-PSK";
1090 case WPA_KEY_MGMT_NONE:
1091 return "NONE";
1092 case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
1093 return "IEEE 802.1X (no WPA)";
1094#ifdef CONFIG_IEEE80211R
1095 case WPA_KEY_MGMT_FT_IEEE8021X:
1096 return "FT-EAP";
1097 case WPA_KEY_MGMT_FT_PSK:
1098 return "FT-PSK";
1099#endif /* CONFIG_IEEE80211R */
1100#ifdef CONFIG_IEEE80211W
1101 case WPA_KEY_MGMT_IEEE8021X_SHA256:
1102 return "WPA2-EAP-SHA256";
1103 case WPA_KEY_MGMT_PSK_SHA256:
1104 return "WPA2-PSK-SHA256";
1105#endif /* CONFIG_IEEE80211W */
72c5c289
JM
1106 case WPA_KEY_MGMT_WPS:
1107 return "WPS";
1108 case WPA_KEY_MGMT_SAE:
1109 return "SAE";
1110 case WPA_KEY_MGMT_FT_SAE:
1111 return "FT-SAE";
1112 case WPA_KEY_MGMT_OSEN:
1113 return "OSEN";
666497c8
JM
1114 case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
1115 return "WPA2-EAP-SUITE-B";
43fb5297
JM
1116 default:
1117 return "UNKNOWN";
1118 }
1119}
26e23750
JM
1120
1121
6c460eaf
JM
1122u32 wpa_akm_to_suite(int akm)
1123{
1124 if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
1125 return WLAN_AKM_SUITE_FT_8021X;
1126 if (akm & WPA_KEY_MGMT_FT_PSK)
1127 return WLAN_AKM_SUITE_FT_PSK;
1128 if (akm & WPA_KEY_MGMT_IEEE8021X)
1129 return WLAN_AKM_SUITE_8021X;
1130 if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
1131 return WLAN_AKM_SUITE_8021X_SHA256;
1132 if (akm & WPA_KEY_MGMT_IEEE8021X)
1133 return WLAN_AKM_SUITE_8021X;
1134 if (akm & WPA_KEY_MGMT_PSK_SHA256)
1135 return WLAN_AKM_SUITE_PSK_SHA256;
1136 if (akm & WPA_KEY_MGMT_PSK)
1137 return WLAN_AKM_SUITE_PSK;
1138 if (akm & WPA_KEY_MGMT_CCKM)
1139 return WLAN_AKM_SUITE_CCKM;
1140 if (akm & WPA_KEY_MGMT_OSEN)
1141 return WLAN_AKM_SUITE_OSEN;
666497c8
JM
1142 if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
1143 return WLAN_AKM_SUITE_8021X_SUITE_B;
6c460eaf
JM
1144 return 0;
1145}
1146
1147
26e23750
JM
1148int wpa_compare_rsn_ie(int ft_initial_assoc,
1149 const u8 *ie1, size_t ie1len,
1150 const u8 *ie2, size_t ie2len)
1151{
d3ccead3
JM
1152 if (ie1 == NULL || ie2 == NULL)
1153 return -1;
1154
26e23750
JM
1155 if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
1156 return 0; /* identical IEs */
1157
1158#ifdef CONFIG_IEEE80211R
1159 if (ft_initial_assoc) {
1160 struct wpa_ie_data ie1d, ie2d;
1161 /*
1162 * The PMKID-List in RSN IE is different between Beacon/Probe
1163 * Response/(Re)Association Request frames and EAPOL-Key
1164 * messages in FT initial mobility domain association. Allow
1165 * for this, but verify that other parts of the RSN IEs are
1166 * identical.
1167 */
1168 if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
1169 wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
1170 return -1;
1171 if (ie1d.proto == ie2d.proto &&
1172 ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
1173 ie1d.group_cipher == ie2d.group_cipher &&
1174 ie1d.key_mgmt == ie2d.key_mgmt &&
1175 ie1d.capabilities == ie2d.capabilities &&
1176 ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
1177 return 0;
1178 }
1179#endif /* CONFIG_IEEE80211R */
1180
1181 return -1;
1182}
1183
1184
1185#ifdef CONFIG_IEEE80211R
1186int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
1187{
1188 u8 *start, *end, *rpos, *rend;
1189 int added = 0;
1190
1191 start = ies;
1192 end = ies + ies_len;
1193
1194 while (start < end) {
1195 if (*start == WLAN_EID_RSN)
1196 break;
1197 start += 2 + start[1];
1198 }
1199 if (start >= end) {
1200 wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
1201 "IEs data");
1202 return -1;
1203 }
1204 wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
1205 start, 2 + start[1]);
1206
1207 /* Find start of PMKID-Count */
1208 rpos = start + 2;
1209 rend = rpos + start[1];
1210
1211 /* Skip Version and Group Data Cipher Suite */
1212 rpos += 2 + 4;
1213 /* Skip Pairwise Cipher Suite Count and List */
1214 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
1215 /* Skip AKM Suite Count and List */
1216 rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
1217
1218 if (rpos == rend) {
1219 /* Add RSN Capabilities */
1220 os_memmove(rpos + 2, rpos, end - rpos);
1221 *rpos++ = 0;
1222 *rpos++ = 0;
1223 } else {
1224 /* Skip RSN Capabilities */
1225 rpos += 2;
1226 if (rpos > rend) {
1227 wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
1228 "IEs data");
1229 return -1;
1230 }
1231 }
1232
1233 if (rpos == rend) {
1234 /* No PMKID-Count field included; add it */
1235 os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
1236 WPA_PUT_LE16(rpos, 1);
1237 rpos += 2;
1238 os_memcpy(rpos, pmkid, PMKID_LEN);
1239 added += 2 + PMKID_LEN;
1240 start[1] += 2 + PMKID_LEN;
1241 } else {
1242 /* PMKID-Count was included; use it */
1243 if (WPA_GET_LE16(rpos) != 0) {
1244 wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
1245 "in RSN IE in EAPOL-Key data");
1246 return -1;
1247 }
1248 WPA_PUT_LE16(rpos, 1);
1249 rpos += 2;
1250 os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
1251 os_memcpy(rpos, pmkid, PMKID_LEN);
1252 added += PMKID_LEN;
1253 start[1] += PMKID_LEN;
1254 }
1255
1256 wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
1257 "(PMKID inserted)", start, 2 + start[1]);
1258
1259 return added;
1260}
1261#endif /* CONFIG_IEEE80211R */
c3550295
JM
1262
1263
1264int wpa_cipher_key_len(int cipher)
1265{
1266 switch (cipher) {
30675c34
JM
1267 case WPA_CIPHER_CCMP_256:
1268 case WPA_CIPHER_GCMP_256:
8dd9f9cd
JM
1269 case WPA_CIPHER_BIP_GMAC_256:
1270 case WPA_CIPHER_BIP_CMAC_256:
30675c34 1271 return 32;
c3550295
JM
1272 case WPA_CIPHER_CCMP:
1273 case WPA_CIPHER_GCMP:
8dd9f9cd
JM
1274 case WPA_CIPHER_AES_128_CMAC:
1275 case WPA_CIPHER_BIP_GMAC_128:
c3550295
JM
1276 return 16;
1277 case WPA_CIPHER_TKIP:
1278 return 32;
1279 case WPA_CIPHER_WEP104:
1280 return 13;
1281 case WPA_CIPHER_WEP40:
1282 return 5;
1283 }
1284
1285 return 0;
1286}
1287
1288
1289int wpa_cipher_rsc_len(int cipher)
1290{
1291 switch (cipher) {
30675c34
JM
1292 case WPA_CIPHER_CCMP_256:
1293 case WPA_CIPHER_GCMP_256:
c3550295
JM
1294 case WPA_CIPHER_CCMP:
1295 case WPA_CIPHER_GCMP:
1296 case WPA_CIPHER_TKIP:
1297 return 6;
1298 case WPA_CIPHER_WEP104:
1299 case WPA_CIPHER_WEP40:
1300 return 0;
1301 }
1302
1303 return 0;
1304}
1305
1306
1307int wpa_cipher_to_alg(int cipher)
1308{
1309 switch (cipher) {
30675c34
JM
1310 case WPA_CIPHER_CCMP_256:
1311 return WPA_ALG_CCMP_256;
1312 case WPA_CIPHER_GCMP_256:
1313 return WPA_ALG_GCMP_256;
c3550295
JM
1314 case WPA_CIPHER_CCMP:
1315 return WPA_ALG_CCMP;
1316 case WPA_CIPHER_GCMP:
1317 return WPA_ALG_GCMP;
1318 case WPA_CIPHER_TKIP:
1319 return WPA_ALG_TKIP;
1320 case WPA_CIPHER_WEP104:
1321 case WPA_CIPHER_WEP40:
1322 return WPA_ALG_WEP;
8dd9f9cd
JM
1323 case WPA_CIPHER_AES_128_CMAC:
1324 return WPA_ALG_IGTK;
1325 case WPA_CIPHER_BIP_GMAC_128:
1326 return WPA_ALG_BIP_GMAC_128;
1327 case WPA_CIPHER_BIP_GMAC_256:
1328 return WPA_ALG_BIP_GMAC_256;
1329 case WPA_CIPHER_BIP_CMAC_256:
1330 return WPA_ALG_BIP_CMAC_256;
c3550295
JM
1331 }
1332 return WPA_ALG_NONE;
1333}
1334
1335
1336int wpa_cipher_valid_pairwise(int cipher)
1337{
30675c34
JM
1338 return cipher == WPA_CIPHER_CCMP_256 ||
1339 cipher == WPA_CIPHER_GCMP_256 ||
1340 cipher == WPA_CIPHER_CCMP ||
c3550295
JM
1341 cipher == WPA_CIPHER_GCMP ||
1342 cipher == WPA_CIPHER_TKIP;
1343}
1344
1345
1346u32 wpa_cipher_to_suite(int proto, int cipher)
1347{
30675c34
JM
1348 if (cipher & WPA_CIPHER_CCMP_256)
1349 return RSN_CIPHER_SUITE_CCMP_256;
1350 if (cipher & WPA_CIPHER_GCMP_256)
1351 return RSN_CIPHER_SUITE_GCMP_256;
c3550295
JM
1352 if (cipher & WPA_CIPHER_CCMP)
1353 return (proto == WPA_PROTO_RSN ?
1354 RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
1355 if (cipher & WPA_CIPHER_GCMP)
1356 return RSN_CIPHER_SUITE_GCMP;
1357 if (cipher & WPA_CIPHER_TKIP)
1358 return (proto == WPA_PROTO_RSN ?
1359 RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
1360 if (cipher & WPA_CIPHER_WEP104)
1361 return (proto == WPA_PROTO_RSN ?
1362 RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
1363 if (cipher & WPA_CIPHER_WEP40)
1364 return (proto == WPA_PROTO_RSN ?
1365 RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
1366 if (cipher & WPA_CIPHER_NONE)
1367 return (proto == WPA_PROTO_RSN ?
1368 RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
dff1e285
JM
1369 if (cipher & WPA_CIPHER_GTK_NOT_USED)
1370 return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
8dd9f9cd
JM
1371 if (cipher & WPA_CIPHER_AES_128_CMAC)
1372 return RSN_CIPHER_SUITE_AES_128_CMAC;
1373 if (cipher & WPA_CIPHER_BIP_GMAC_128)
1374 return RSN_CIPHER_SUITE_BIP_GMAC_128;
1375 if (cipher & WPA_CIPHER_BIP_GMAC_256)
1376 return RSN_CIPHER_SUITE_BIP_GMAC_256;
1377 if (cipher & WPA_CIPHER_BIP_CMAC_256)
1378 return RSN_CIPHER_SUITE_BIP_CMAC_256;
c3550295
JM
1379 return 0;
1380}
1381
1382
8a4ce280 1383int rsn_cipher_put_suites(u8 *start, int ciphers)
c3550295 1384{
8a4ce280 1385 u8 *pos = start;
c3550295 1386
30675c34
JM
1387 if (ciphers & WPA_CIPHER_CCMP_256) {
1388 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP_256);
1389 pos += RSN_SELECTOR_LEN;
30675c34
JM
1390 }
1391 if (ciphers & WPA_CIPHER_GCMP_256) {
1392 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP_256);
1393 pos += RSN_SELECTOR_LEN;
30675c34 1394 }
c3550295
JM
1395 if (ciphers & WPA_CIPHER_CCMP) {
1396 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
1397 pos += RSN_SELECTOR_LEN;
c3550295
JM
1398 }
1399 if (ciphers & WPA_CIPHER_GCMP) {
1400 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
1401 pos += RSN_SELECTOR_LEN;
c3550295
JM
1402 }
1403 if (ciphers & WPA_CIPHER_TKIP) {
1404 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
1405 pos += RSN_SELECTOR_LEN;
c3550295
JM
1406 }
1407 if (ciphers & WPA_CIPHER_NONE) {
1408 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
1409 pos += RSN_SELECTOR_LEN;
c3550295
JM
1410 }
1411
8a4ce280 1412 return (pos - start) / RSN_SELECTOR_LEN;
c3550295
JM
1413}
1414
1415
8a4ce280 1416int wpa_cipher_put_suites(u8 *start, int ciphers)
c3550295 1417{
8a4ce280 1418 u8 *pos = start;
c3550295
JM
1419
1420 if (ciphers & WPA_CIPHER_CCMP) {
1421 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
1422 pos += WPA_SELECTOR_LEN;
c3550295
JM
1423 }
1424 if (ciphers & WPA_CIPHER_TKIP) {
1425 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
1426 pos += WPA_SELECTOR_LEN;
c3550295
JM
1427 }
1428 if (ciphers & WPA_CIPHER_NONE) {
1429 RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
1430 pos += WPA_SELECTOR_LEN;
c3550295
JM
1431 }
1432
8a4ce280 1433 return (pos - start) / RSN_SELECTOR_LEN;
c3550295 1434}
edbd2a19
JM
1435
1436
1437int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
1438{
30675c34
JM
1439 if (ciphers & WPA_CIPHER_CCMP_256)
1440 return WPA_CIPHER_CCMP_256;
1441 if (ciphers & WPA_CIPHER_GCMP_256)
1442 return WPA_CIPHER_GCMP_256;
edbd2a19
JM
1443 if (ciphers & WPA_CIPHER_CCMP)
1444 return WPA_CIPHER_CCMP;
1445 if (ciphers & WPA_CIPHER_GCMP)
1446 return WPA_CIPHER_GCMP;
1447 if (ciphers & WPA_CIPHER_TKIP)
1448 return WPA_CIPHER_TKIP;
1449 if (none_allowed && (ciphers & WPA_CIPHER_NONE))
1450 return WPA_CIPHER_NONE;
1451 return -1;
1452}
1453
1454
1455int wpa_pick_group_cipher(int ciphers)
1456{
30675c34
JM
1457 if (ciphers & WPA_CIPHER_CCMP_256)
1458 return WPA_CIPHER_CCMP_256;
1459 if (ciphers & WPA_CIPHER_GCMP_256)
1460 return WPA_CIPHER_GCMP_256;
edbd2a19
JM
1461 if (ciphers & WPA_CIPHER_CCMP)
1462 return WPA_CIPHER_CCMP;
1463 if (ciphers & WPA_CIPHER_GCMP)
1464 return WPA_CIPHER_GCMP;
dff1e285
JM
1465 if (ciphers & WPA_CIPHER_GTK_NOT_USED)
1466 return WPA_CIPHER_GTK_NOT_USED;
edbd2a19
JM
1467 if (ciphers & WPA_CIPHER_TKIP)
1468 return WPA_CIPHER_TKIP;
1469 if (ciphers & WPA_CIPHER_WEP104)
1470 return WPA_CIPHER_WEP104;
1471 if (ciphers & WPA_CIPHER_WEP40)
1472 return WPA_CIPHER_WEP40;
1473 return -1;
1474}
a39c78be
JM
1475
1476
1477int wpa_parse_cipher(const char *value)
1478{
1479 int val = 0, last;
1480 char *start, *end, *buf;
1481
1482 buf = os_strdup(value);
1483 if (buf == NULL)
1484 return -1;
1485 start = buf;
1486
1487 while (*start != '\0') {
1488 while (*start == ' ' || *start == '\t')
1489 start++;
1490 if (*start == '\0')
1491 break;
1492 end = start;
1493 while (*end != ' ' && *end != '\t' && *end != '\0')
1494 end++;
1495 last = *end == '\0';
1496 *end = '\0';
30675c34
JM
1497 if (os_strcmp(start, "CCMP-256") == 0)
1498 val |= WPA_CIPHER_CCMP_256;
1499 else if (os_strcmp(start, "GCMP-256") == 0)
1500 val |= WPA_CIPHER_GCMP_256;
1501 else if (os_strcmp(start, "CCMP") == 0)
a39c78be
JM
1502 val |= WPA_CIPHER_CCMP;
1503 else if (os_strcmp(start, "GCMP") == 0)
1504 val |= WPA_CIPHER_GCMP;
1505 else if (os_strcmp(start, "TKIP") == 0)
1506 val |= WPA_CIPHER_TKIP;
1507 else if (os_strcmp(start, "WEP104") == 0)
1508 val |= WPA_CIPHER_WEP104;
1509 else if (os_strcmp(start, "WEP40") == 0)
1510 val |= WPA_CIPHER_WEP40;
1511 else if (os_strcmp(start, "NONE") == 0)
1512 val |= WPA_CIPHER_NONE;
dff1e285
JM
1513 else if (os_strcmp(start, "GTK_NOT_USED") == 0)
1514 val |= WPA_CIPHER_GTK_NOT_USED;
a39c78be
JM
1515 else {
1516 os_free(buf);
1517 return -1;
1518 }
1519
1520 if (last)
1521 break;
1522 start = end + 1;
1523 }
1524 os_free(buf);
1525
1526 return val;
1527}
0282a8c4
JM
1528
1529
1530int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
1531{
1532 char *pos = start;
1533 int ret;
1534
30675c34
JM
1535 if (ciphers & WPA_CIPHER_CCMP_256) {
1536 ret = os_snprintf(pos, end - pos, "%sCCMP-256",
1537 pos == start ? "" : delim);
d85e1fc8 1538 if (os_snprintf_error(end - pos, ret))
30675c34
JM
1539 return -1;
1540 pos += ret;
1541 }
1542 if (ciphers & WPA_CIPHER_GCMP_256) {
1543 ret = os_snprintf(pos, end - pos, "%sGCMP-256",
1544 pos == start ? "" : delim);
d85e1fc8 1545 if (os_snprintf_error(end - pos, ret))
30675c34
JM
1546 return -1;
1547 pos += ret;
1548 }
0282a8c4
JM
1549 if (ciphers & WPA_CIPHER_CCMP) {
1550 ret = os_snprintf(pos, end - pos, "%sCCMP",
1551 pos == start ? "" : delim);
d85e1fc8 1552 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1553 return -1;
1554 pos += ret;
1555 }
1556 if (ciphers & WPA_CIPHER_GCMP) {
1557 ret = os_snprintf(pos, end - pos, "%sGCMP",
1558 pos == start ? "" : delim);
d85e1fc8 1559 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1560 return -1;
1561 pos += ret;
1562 }
1563 if (ciphers & WPA_CIPHER_TKIP) {
1564 ret = os_snprintf(pos, end - pos, "%sTKIP",
1565 pos == start ? "" : delim);
d85e1fc8 1566 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1567 return -1;
1568 pos += ret;
1569 }
1570 if (ciphers & WPA_CIPHER_WEP104) {
1571 ret = os_snprintf(pos, end - pos, "%sWEP104",
1572 pos == start ? "" : delim);
d85e1fc8 1573 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1574 return -1;
1575 pos += ret;
1576 }
1577 if (ciphers & WPA_CIPHER_WEP40) {
1578 ret = os_snprintf(pos, end - pos, "%sWEP40",
1579 pos == start ? "" : delim);
d85e1fc8 1580 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1581 return -1;
1582 pos += ret;
1583 }
1584 if (ciphers & WPA_CIPHER_NONE) {
1585 ret = os_snprintf(pos, end - pos, "%sNONE",
1586 pos == start ? "" : delim);
d85e1fc8 1587 if (os_snprintf_error(end - pos, ret))
0282a8c4
JM
1588 return -1;
1589 pos += ret;
1590 }
1591
1592 return pos - start;
1593}
cf830c1c
JM
1594
1595
1596int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
1597{
1598 int pairwise = 0;
1599
1600 /* Select group cipher based on the enabled pairwise cipher suites */
1601 if (wpa & 1)
1602 pairwise |= wpa_pairwise;
1603 if (wpa & 2)
1604 pairwise |= rsn_pairwise;
1605
1606 if (pairwise & WPA_CIPHER_TKIP)
1607 return WPA_CIPHER_TKIP;
1608 if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
1609 return WPA_CIPHER_GCMP;
30675c34
JM
1610 if ((pairwise & (WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP |
1611 WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP_256)
1612 return WPA_CIPHER_GCMP_256;
1613 if ((pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
1614 WPA_CIPHER_GCMP)) == WPA_CIPHER_CCMP_256)
1615 return WPA_CIPHER_CCMP_256;
cf830c1c
JM
1616 return WPA_CIPHER_CCMP;
1617}