]>
Commit | Line | Data |
---|---|---|
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 |
22 | static unsigned int wpa_kck_len(int akmp) |
23 | { | |
24 | return 16; | |
25 | } | |
26 | ||
27 | ||
28 | static 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 |
54 | int 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 |
121 | int 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 |
183 | int 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 | ||
246 | static 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 | ||
295 | int 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 |
395 | static 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 | ||
429 | static 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 |
459 | static 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 | |
469 | int 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 | */ | |
486 | int 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 |
644 | static 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 | ||
660 | static 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 | ||
672 | int 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 | */ |
790 | void 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 | */ |
845 | void 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 | */ |
875 | void 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 |
900 | int 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 | */ | |
982 | void 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 | */ | |
1017 | int 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 | */ | |
1042 | const 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 | */ | |
1077 | const 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 |
1122 | u32 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 |
1148 | int 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 | |
1186 | int 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 | ||
1264 | int 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 | ||
1289 | int 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 | ||
1307 | int 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 | ||
1336 | int 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 | ||
1346 | u32 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 | 1383 | int 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 | 1416 | int 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 | ||
1437 | int 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 | ||
1455 | int 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 | ||
1477 | int 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 | ||
1530 | int 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 | ||
1596 | int 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 | } |