]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA/RSN - Shared functions for supplicant and authenticator | |
edbd2a19 | 3 | * Copyright (c) 2002-2013, 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 | ||
22 | /** | |
23 | * wpa_eapol_key_mic - Calculate EAPOL-Key MIC | |
24 | * @key: EAPOL-Key Key Confirmation Key (KCK) | |
25 | * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) | |
26 | * @buf: Pointer to the beginning of the EAPOL header (version field) | |
27 | * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) | |
28 | * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written | |
29 | * Returns: 0 on success, -1 on failure | |
30 | * | |
31 | * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has | |
32 | * to be cleared (all zeroes) when calling this function. | |
33 | * | |
34 | * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the | |
35 | * description of the Key MIC calculation. It includes packet data from the | |
36 | * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change | |
37 | * happened during final editing of the standard and the correct behavior is | |
38 | * defined in the last draft (IEEE 802.11i/D10). | |
39 | */ | |
40 | int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, | |
41 | u8 *mic) | |
42 | { | |
43 | u8 hash[SHA1_MAC_LEN]; | |
44 | ||
45 | switch (ver) { | |
6e6909a9 | 46 | #ifndef CONFIG_FIPS |
6fc6879b | 47 | case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: |
04b6b3ed | 48 | return hmac_md5(key, 16, buf, len, mic); |
6e6909a9 | 49 | #endif /* CONFIG_FIPS */ |
6fc6879b | 50 | case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: |
04b6b3ed JM |
51 | if (hmac_sha1(key, 16, buf, len, hash)) |
52 | return -1; | |
6fc6879b JM |
53 | os_memcpy(mic, hash, MD5_MAC_LEN); |
54 | break; | |
a20088e5 | 55 | #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) |
6fc6879b JM |
56 | case WPA_KEY_INFO_TYPE_AES_128_CMAC: |
57 | return omac1_aes_128(key, buf, len, mic); | |
a20088e5 | 58 | #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ |
6fc6879b JM |
59 | default: |
60 | return -1; | |
61 | } | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | ||
67 | /** | |
68 | * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces | |
69 | * @pmk: Pairwise master key | |
70 | * @pmk_len: Length of PMK | |
71 | * @label: Label to use in derivation | |
72 | * @addr1: AA or SA | |
73 | * @addr2: SA or AA | |
74 | * @nonce1: ANonce or SNonce | |
75 | * @nonce2: SNonce or ANonce | |
76 | * @ptk: Buffer for pairwise transient key | |
77 | * @ptk_len: Length of PTK | |
56586197 | 78 | * @use_sha256: Whether to use SHA256-based KDF |
6fc6879b JM |
79 | * |
80 | * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy | |
81 | * PTK = PRF-X(PMK, "Pairwise key expansion", | |
82 | * Min(AA, SA) || Max(AA, SA) || | |
83 | * Min(ANonce, SNonce) || Max(ANonce, SNonce)) | |
84 | * | |
85 | * STK = PRF-X(SMK, "Peer key expansion", | |
86 | * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || | |
87 | * Min(INonce, PNonce) || Max(INonce, PNonce)) | |
88 | */ | |
89 | void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, | |
90 | const u8 *addr1, const u8 *addr2, | |
91 | const u8 *nonce1, const u8 *nonce2, | |
56586197 | 92 | u8 *ptk, size_t ptk_len, int use_sha256) |
6fc6879b JM |
93 | { |
94 | u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; | |
95 | ||
96 | if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { | |
97 | os_memcpy(data, addr1, ETH_ALEN); | |
98 | os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); | |
99 | } else { | |
100 | os_memcpy(data, addr2, ETH_ALEN); | |
101 | os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); | |
102 | } | |
103 | ||
104 | if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { | |
105 | os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); | |
106 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, | |
107 | WPA_NONCE_LEN); | |
108 | } else { | |
109 | os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); | |
110 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, | |
111 | WPA_NONCE_LEN); | |
112 | } | |
113 | ||
56586197 JM |
114 | #ifdef CONFIG_IEEE80211W |
115 | if (use_sha256) | |
116 | sha256_prf(pmk, pmk_len, label, data, sizeof(data), | |
117 | ptk, ptk_len); | |
118 | else | |
119 | #endif /* CONFIG_IEEE80211W */ | |
120 | sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, | |
121 | ptk_len); | |
6fc6879b JM |
122 | |
123 | wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, | |
124 | MAC2STR(addr1), MAC2STR(addr2)); | |
bc8318ac JM |
125 | wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); |
126 | wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); | |
6fc6879b JM |
127 | wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); |
128 | wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); | |
129 | } | |
130 | ||
131 | ||
132 | #ifdef CONFIG_IEEE80211R | |
133 | int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, | |
134 | u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, | |
135 | const u8 *ftie, size_t ftie_len, | |
136 | const u8 *rsnie, size_t rsnie_len, | |
137 | const u8 *ric, size_t ric_len, u8 *mic) | |
138 | { | |
139 | u8 *buf, *pos; | |
140 | size_t buf_len; | |
141 | ||
142 | buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; | |
143 | buf = os_malloc(buf_len); | |
144 | if (buf == NULL) | |
145 | return -1; | |
146 | ||
147 | pos = buf; | |
148 | os_memcpy(pos, sta_addr, ETH_ALEN); | |
149 | pos += ETH_ALEN; | |
150 | os_memcpy(pos, ap_addr, ETH_ALEN); | |
151 | pos += ETH_ALEN; | |
152 | *pos++ = transaction_seqnum; | |
153 | if (rsnie) { | |
154 | os_memcpy(pos, rsnie, rsnie_len); | |
155 | pos += rsnie_len; | |
156 | } | |
157 | if (mdie) { | |
158 | os_memcpy(pos, mdie, mdie_len); | |
159 | pos += mdie_len; | |
160 | } | |
161 | if (ftie) { | |
162 | struct rsn_ftie *_ftie; | |
163 | os_memcpy(pos, ftie, ftie_len); | |
164 | if (ftie_len < 2 + sizeof(*_ftie)) { | |
165 | os_free(buf); | |
166 | return -1; | |
167 | } | |
168 | _ftie = (struct rsn_ftie *) (pos + 2); | |
169 | os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); | |
170 | pos += ftie_len; | |
171 | } | |
172 | if (ric) { | |
173 | os_memcpy(pos, ric, ric_len); | |
174 | pos += ric_len; | |
175 | } | |
176 | ||
177 | wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); | |
178 | if (omac1_aes_128(kck, buf, pos - buf, mic)) { | |
179 | os_free(buf); | |
180 | return -1; | |
181 | } | |
182 | ||
183 | os_free(buf); | |
184 | ||
185 | return 0; | |
186 | } | |
6554237f JM |
187 | |
188 | ||
189 | static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, | |
190 | struct wpa_ft_ies *parse) | |
191 | { | |
192 | const u8 *end, *pos; | |
193 | ||
194 | parse->ftie = ie; | |
195 | parse->ftie_len = ie_len; | |
196 | ||
197 | pos = ie + sizeof(struct rsn_ftie); | |
198 | end = ie + ie_len; | |
199 | ||
200 | while (pos + 2 <= end && pos + 2 + pos[1] <= end) { | |
201 | switch (pos[0]) { | |
202 | case FTIE_SUBELEM_R1KH_ID: | |
203 | if (pos[1] != FT_R1KH_ID_LEN) { | |
204 | wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " | |
205 | "length in FTIE: %d", pos[1]); | |
206 | return -1; | |
207 | } | |
208 | parse->r1kh_id = pos + 2; | |
209 | break; | |
210 | case FTIE_SUBELEM_GTK: | |
211 | parse->gtk = pos + 2; | |
212 | parse->gtk_len = pos[1]; | |
213 | break; | |
214 | case FTIE_SUBELEM_R0KH_ID: | |
215 | if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { | |
216 | wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " | |
217 | "length in FTIE: %d", pos[1]); | |
218 | return -1; | |
219 | } | |
220 | parse->r0kh_id = pos + 2; | |
221 | parse->r0kh_id_len = pos[1]; | |
222 | break; | |
223 | #ifdef CONFIG_IEEE80211W | |
224 | case FTIE_SUBELEM_IGTK: | |
225 | parse->igtk = pos + 2; | |
226 | parse->igtk_len = pos[1]; | |
227 | break; | |
228 | #endif /* CONFIG_IEEE80211W */ | |
229 | } | |
230 | ||
231 | pos += 2 + pos[1]; | |
232 | } | |
233 | ||
234 | return 0; | |
235 | } | |
236 | ||
237 | ||
238 | int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, | |
239 | struct wpa_ft_ies *parse) | |
240 | { | |
241 | const u8 *end, *pos; | |
242 | struct wpa_ie_data data; | |
243 | int ret; | |
244 | const struct rsn_ftie *ftie; | |
245 | int prot_ie_count = 0; | |
246 | ||
247 | os_memset(parse, 0, sizeof(*parse)); | |
248 | if (ies == NULL) | |
249 | return 0; | |
250 | ||
251 | pos = ies; | |
252 | end = ies + ies_len; | |
253 | while (pos + 2 <= end && pos + 2 + pos[1] <= end) { | |
254 | switch (pos[0]) { | |
255 | case WLAN_EID_RSN: | |
256 | parse->rsn = pos + 2; | |
257 | parse->rsn_len = pos[1]; | |
258 | ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, | |
259 | parse->rsn_len + 2, | |
260 | &data); | |
261 | if (ret < 0) { | |
262 | wpa_printf(MSG_DEBUG, "FT: Failed to parse " | |
263 | "RSN IE: %d", ret); | |
264 | return -1; | |
265 | } | |
266 | if (data.num_pmkid == 1 && data.pmkid) | |
267 | parse->rsn_pmkid = data.pmkid; | |
268 | break; | |
269 | case WLAN_EID_MOBILITY_DOMAIN: | |
270 | parse->mdie = pos + 2; | |
271 | parse->mdie_len = pos[1]; | |
272 | break; | |
273 | case WLAN_EID_FAST_BSS_TRANSITION: | |
274 | if (pos[1] < sizeof(*ftie)) | |
275 | return -1; | |
276 | ftie = (const struct rsn_ftie *) (pos + 2); | |
277 | prot_ie_count = ftie->mic_control[1]; | |
278 | if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) | |
279 | return -1; | |
280 | break; | |
281 | case WLAN_EID_TIMEOUT_INTERVAL: | |
282 | parse->tie = pos + 2; | |
283 | parse->tie_len = pos[1]; | |
284 | break; | |
285 | case WLAN_EID_RIC_DATA: | |
286 | if (parse->ric == NULL) | |
287 | parse->ric = pos; | |
288 | break; | |
289 | } | |
290 | ||
291 | pos += 2 + pos[1]; | |
292 | } | |
293 | ||
294 | if (prot_ie_count == 0) | |
295 | return 0; /* no MIC */ | |
296 | ||
297 | /* | |
298 | * Check that the protected IE count matches with IEs included in the | |
299 | * frame. | |
300 | */ | |
301 | if (parse->rsn) | |
302 | prot_ie_count--; | |
303 | if (parse->mdie) | |
304 | prot_ie_count--; | |
305 | if (parse->ftie) | |
306 | prot_ie_count--; | |
307 | if (prot_ie_count < 0) { | |
308 | wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " | |
309 | "the protected IE count"); | |
310 | return -1; | |
311 | } | |
312 | ||
313 | if (prot_ie_count == 0 && parse->ric) { | |
314 | wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " | |
315 | "included in protected IE count"); | |
316 | return -1; | |
317 | } | |
318 | ||
319 | /* Determine the end of the RIC IE(s) */ | |
320 | pos = parse->ric; | |
321 | while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && | |
322 | prot_ie_count) { | |
323 | prot_ie_count--; | |
324 | pos += 2 + pos[1]; | |
325 | } | |
326 | parse->ric_len = pos - parse->ric; | |
327 | if (prot_ie_count) { | |
328 | wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " | |
329 | "frame", (int) prot_ie_count); | |
330 | return -1; | |
331 | } | |
332 | ||
333 | return 0; | |
334 | } | |
6fc6879b JM |
335 | #endif /* CONFIG_IEEE80211R */ |
336 | ||
337 | ||
338 | #ifndef CONFIG_NO_WPA2 | |
339 | static int rsn_selector_to_bitfield(const u8 *s) | |
340 | { | |
341 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) | |
342 | return WPA_CIPHER_NONE; | |
343 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) | |
344 | return WPA_CIPHER_WEP40; | |
345 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) | |
346 | return WPA_CIPHER_TKIP; | |
347 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) | |
348 | return WPA_CIPHER_CCMP; | |
349 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) | |
350 | return WPA_CIPHER_WEP104; | |
351 | #ifdef CONFIG_IEEE80211W | |
352 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) | |
353 | return WPA_CIPHER_AES_128_CMAC; | |
354 | #endif /* CONFIG_IEEE80211W */ | |
eb7719ff JM |
355 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP) |
356 | return WPA_CIPHER_GCMP; | |
6fc6879b JM |
357 | return 0; |
358 | } | |
359 | ||
360 | ||
361 | static int rsn_key_mgmt_to_bitfield(const u8 *s) | |
362 | { | |
363 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) | |
364 | return WPA_KEY_MGMT_IEEE8021X; | |
365 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) | |
366 | return WPA_KEY_MGMT_PSK; | |
367 | #ifdef CONFIG_IEEE80211R | |
368 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) | |
369 | return WPA_KEY_MGMT_FT_IEEE8021X; | |
370 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) | |
371 | return WPA_KEY_MGMT_FT_PSK; | |
372 | #endif /* CONFIG_IEEE80211R */ | |
56586197 JM |
373 | #ifdef CONFIG_IEEE80211W |
374 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) | |
375 | return WPA_KEY_MGMT_IEEE8021X_SHA256; | |
376 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) | |
377 | return WPA_KEY_MGMT_PSK_SHA256; | |
378 | #endif /* CONFIG_IEEE80211W */ | |
c10347f2 JM |
379 | #ifdef CONFIG_SAE |
380 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE) | |
381 | return WPA_KEY_MGMT_SAE; | |
382 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) | |
383 | return WPA_KEY_MGMT_FT_SAE; | |
384 | #endif /* CONFIG_SAE */ | |
6fc6879b JM |
385 | return 0; |
386 | } | |
387 | #endif /* CONFIG_NO_WPA2 */ | |
388 | ||
389 | ||
390 | /** | |
391 | * wpa_parse_wpa_ie_rsn - Parse RSN IE | |
392 | * @rsn_ie: Buffer containing RSN IE | |
393 | * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) | |
394 | * @data: Pointer to structure that will be filled in with parsed data | |
395 | * Returns: 0 on success, <0 on failure | |
396 | */ | |
397 | int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, | |
398 | struct wpa_ie_data *data) | |
399 | { | |
400 | #ifndef CONFIG_NO_WPA2 | |
401 | const struct rsn_ie_hdr *hdr; | |
402 | const u8 *pos; | |
403 | int left; | |
404 | int i, count; | |
405 | ||
406 | os_memset(data, 0, sizeof(*data)); | |
407 | data->proto = WPA_PROTO_RSN; | |
408 | data->pairwise_cipher = WPA_CIPHER_CCMP; | |
409 | data->group_cipher = WPA_CIPHER_CCMP; | |
410 | data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
411 | data->capabilities = 0; | |
412 | data->pmkid = NULL; | |
413 | data->num_pmkid = 0; | |
414 | #ifdef CONFIG_IEEE80211W | |
415 | data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; | |
416 | #else /* CONFIG_IEEE80211W */ | |
417 | data->mgmt_group_cipher = 0; | |
418 | #endif /* CONFIG_IEEE80211W */ | |
419 | ||
420 | if (rsn_ie_len == 0) { | |
421 | /* No RSN IE - fail silently */ | |
422 | return -1; | |
423 | } | |
424 | ||
425 | if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { | |
426 | wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", | |
427 | __func__, (unsigned long) rsn_ie_len); | |
428 | return -1; | |
429 | } | |
430 | ||
431 | hdr = (const struct rsn_ie_hdr *) rsn_ie; | |
432 | ||
433 | if (hdr->elem_id != WLAN_EID_RSN || | |
434 | hdr->len != rsn_ie_len - 2 || | |
435 | WPA_GET_LE16(hdr->version) != RSN_VERSION) { | |
436 | wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", | |
437 | __func__); | |
438 | return -2; | |
439 | } | |
440 | ||
441 | pos = (const u8 *) (hdr + 1); | |
442 | left = rsn_ie_len - sizeof(*hdr); | |
443 | ||
444 | if (left >= RSN_SELECTOR_LEN) { | |
445 | data->group_cipher = rsn_selector_to_bitfield(pos); | |
446 | #ifdef CONFIG_IEEE80211W | |
447 | if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { | |
448 | wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " | |
449 | "cipher", __func__); | |
450 | return -1; | |
451 | } | |
452 | #endif /* CONFIG_IEEE80211W */ | |
453 | pos += RSN_SELECTOR_LEN; | |
454 | left -= RSN_SELECTOR_LEN; | |
455 | } else if (left > 0) { | |
456 | wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", | |
457 | __func__, left); | |
458 | return -3; | |
459 | } | |
460 | ||
461 | if (left >= 2) { | |
462 | data->pairwise_cipher = 0; | |
463 | count = WPA_GET_LE16(pos); | |
464 | pos += 2; | |
465 | left -= 2; | |
466 | if (count == 0 || left < count * RSN_SELECTOR_LEN) { | |
467 | wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " | |
468 | "count %u left %u", __func__, count, left); | |
469 | return -4; | |
470 | } | |
471 | for (i = 0; i < count; i++) { | |
472 | data->pairwise_cipher |= rsn_selector_to_bitfield(pos); | |
473 | pos += RSN_SELECTOR_LEN; | |
474 | left -= RSN_SELECTOR_LEN; | |
475 | } | |
476 | #ifdef CONFIG_IEEE80211W | |
477 | if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { | |
478 | wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " | |
479 | "pairwise cipher", __func__); | |
480 | return -1; | |
481 | } | |
482 | #endif /* CONFIG_IEEE80211W */ | |
483 | } else if (left == 1) { | |
484 | wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", | |
485 | __func__); | |
486 | return -5; | |
487 | } | |
488 | ||
489 | if (left >= 2) { | |
490 | data->key_mgmt = 0; | |
491 | count = WPA_GET_LE16(pos); | |
492 | pos += 2; | |
493 | left -= 2; | |
494 | if (count == 0 || left < count * RSN_SELECTOR_LEN) { | |
495 | wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " | |
496 | "count %u left %u", __func__, count, left); | |
497 | return -6; | |
498 | } | |
499 | for (i = 0; i < count; i++) { | |
500 | data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); | |
501 | pos += RSN_SELECTOR_LEN; | |
502 | left -= RSN_SELECTOR_LEN; | |
503 | } | |
504 | } else if (left == 1) { | |
505 | wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", | |
506 | __func__); | |
507 | return -7; | |
508 | } | |
509 | ||
510 | if (left >= 2) { | |
511 | data->capabilities = WPA_GET_LE16(pos); | |
512 | pos += 2; | |
513 | left -= 2; | |
514 | } | |
515 | ||
516 | if (left >= 2) { | |
517 | data->num_pmkid = WPA_GET_LE16(pos); | |
518 | pos += 2; | |
519 | left -= 2; | |
520 | if (left < (int) data->num_pmkid * PMKID_LEN) { | |
521 | wpa_printf(MSG_DEBUG, "%s: PMKID underflow " | |
522 | "(num_pmkid=%lu left=%d)", | |
523 | __func__, (unsigned long) data->num_pmkid, | |
524 | left); | |
525 | data->num_pmkid = 0; | |
526 | return -9; | |
527 | } else { | |
528 | data->pmkid = pos; | |
529 | pos += data->num_pmkid * PMKID_LEN; | |
530 | left -= data->num_pmkid * PMKID_LEN; | |
531 | } | |
532 | } | |
533 | ||
534 | #ifdef CONFIG_IEEE80211W | |
535 | if (left >= 4) { | |
536 | data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); | |
537 | if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { | |
538 | wpa_printf(MSG_DEBUG, "%s: Unsupported management " | |
539 | "group cipher 0x%x", __func__, | |
540 | data->mgmt_group_cipher); | |
541 | return -10; | |
542 | } | |
543 | pos += RSN_SELECTOR_LEN; | |
544 | left -= RSN_SELECTOR_LEN; | |
545 | } | |
546 | #endif /* CONFIG_IEEE80211W */ | |
547 | ||
548 | if (left > 0) { | |
549 | wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", | |
550 | __func__, left); | |
551 | } | |
552 | ||
553 | return 0; | |
554 | #else /* CONFIG_NO_WPA2 */ | |
555 | return -1; | |
556 | #endif /* CONFIG_NO_WPA2 */ | |
557 | } | |
558 | ||
559 | ||
f3b87561 JM |
560 | static int wpa_selector_to_bitfield(const u8 *s) |
561 | { | |
562 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) | |
563 | return WPA_CIPHER_NONE; | |
564 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) | |
565 | return WPA_CIPHER_WEP40; | |
566 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) | |
567 | return WPA_CIPHER_TKIP; | |
568 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) | |
569 | return WPA_CIPHER_CCMP; | |
570 | if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) | |
571 | return WPA_CIPHER_WEP104; | |
572 | return 0; | |
573 | } | |
574 | ||
575 | ||
576 | static int wpa_key_mgmt_to_bitfield(const u8 *s) | |
577 | { | |
578 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) | |
579 | return WPA_KEY_MGMT_IEEE8021X; | |
580 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) | |
581 | return WPA_KEY_MGMT_PSK; | |
582 | if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) | |
583 | return WPA_KEY_MGMT_WPA_NONE; | |
584 | return 0; | |
585 | } | |
586 | ||
587 | ||
588 | int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, | |
589 | struct wpa_ie_data *data) | |
590 | { | |
591 | const struct wpa_ie_hdr *hdr; | |
592 | const u8 *pos; | |
593 | int left; | |
594 | int i, count; | |
595 | ||
596 | os_memset(data, 0, sizeof(*data)); | |
597 | data->proto = WPA_PROTO_WPA; | |
598 | data->pairwise_cipher = WPA_CIPHER_TKIP; | |
599 | data->group_cipher = WPA_CIPHER_TKIP; | |
600 | data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
601 | data->capabilities = 0; | |
602 | data->pmkid = NULL; | |
603 | data->num_pmkid = 0; | |
604 | data->mgmt_group_cipher = 0; | |
605 | ||
606 | if (wpa_ie_len == 0) { | |
607 | /* No WPA IE - fail silently */ | |
608 | return -1; | |
609 | } | |
610 | ||
611 | if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { | |
612 | wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", | |
613 | __func__, (unsigned long) wpa_ie_len); | |
614 | return -1; | |
615 | } | |
616 | ||
617 | hdr = (const struct wpa_ie_hdr *) wpa_ie; | |
618 | ||
619 | if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || | |
620 | hdr->len != wpa_ie_len - 2 || | |
621 | RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || | |
622 | WPA_GET_LE16(hdr->version) != WPA_VERSION) { | |
623 | wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", | |
624 | __func__); | |
625 | return -2; | |
626 | } | |
627 | ||
628 | pos = (const u8 *) (hdr + 1); | |
629 | left = wpa_ie_len - sizeof(*hdr); | |
630 | ||
631 | if (left >= WPA_SELECTOR_LEN) { | |
632 | data->group_cipher = wpa_selector_to_bitfield(pos); | |
633 | pos += WPA_SELECTOR_LEN; | |
634 | left -= WPA_SELECTOR_LEN; | |
635 | } else if (left > 0) { | |
636 | wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", | |
637 | __func__, left); | |
638 | return -3; | |
639 | } | |
640 | ||
641 | if (left >= 2) { | |
642 | data->pairwise_cipher = 0; | |
643 | count = WPA_GET_LE16(pos); | |
644 | pos += 2; | |
645 | left -= 2; | |
646 | if (count == 0 || left < count * WPA_SELECTOR_LEN) { | |
647 | wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " | |
648 | "count %u left %u", __func__, count, left); | |
649 | return -4; | |
650 | } | |
651 | for (i = 0; i < count; i++) { | |
652 | data->pairwise_cipher |= wpa_selector_to_bitfield(pos); | |
653 | pos += WPA_SELECTOR_LEN; | |
654 | left -= WPA_SELECTOR_LEN; | |
655 | } | |
656 | } else if (left == 1) { | |
657 | wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", | |
658 | __func__); | |
659 | return -5; | |
660 | } | |
661 | ||
662 | if (left >= 2) { | |
663 | data->key_mgmt = 0; | |
664 | count = WPA_GET_LE16(pos); | |
665 | pos += 2; | |
666 | left -= 2; | |
667 | if (count == 0 || left < count * WPA_SELECTOR_LEN) { | |
668 | wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " | |
669 | "count %u left %u", __func__, count, left); | |
670 | return -6; | |
671 | } | |
672 | for (i = 0; i < count; i++) { | |
673 | data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); | |
674 | pos += WPA_SELECTOR_LEN; | |
675 | left -= WPA_SELECTOR_LEN; | |
676 | } | |
677 | } else if (left == 1) { | |
678 | wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", | |
679 | __func__); | |
680 | return -7; | |
681 | } | |
682 | ||
683 | if (left >= 2) { | |
684 | data->capabilities = WPA_GET_LE16(pos); | |
685 | pos += 2; | |
686 | left -= 2; | |
687 | } | |
688 | ||
689 | if (left > 0) { | |
690 | wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", | |
691 | __func__, left); | |
692 | } | |
693 | ||
694 | return 0; | |
695 | } | |
696 | ||
697 | ||
6fc6879b JM |
698 | #ifdef CONFIG_IEEE80211R |
699 | ||
700 | /** | |
701 | * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name | |
702 | * | |
c1e033b0 | 703 | * IEEE Std 802.11r-2008 - 8.5.1.5.3 |
6fc6879b JM |
704 | */ |
705 | void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, | |
706 | const u8 *ssid, size_t ssid_len, | |
707 | const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, | |
708 | const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) | |
709 | { | |
710 | u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + | |
711 | FT_R0KH_ID_MAX_LEN + ETH_ALEN]; | |
712 | u8 *pos, r0_key_data[48], hash[32]; | |
713 | const u8 *addr[2]; | |
714 | size_t len[2]; | |
715 | ||
716 | /* | |
717 | * R0-Key-Data = KDF-384(XXKey, "FT-R0", | |
718 | * SSIDlength || SSID || MDID || R0KHlength || | |
719 | * R0KH-ID || S0KH-ID) | |
720 | * XXKey is either the second 256 bits of MSK or PSK. | |
721 | * PMK-R0 = L(R0-Key-Data, 0, 256) | |
722 | * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) | |
723 | */ | |
724 | if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) | |
725 | return; | |
726 | pos = buf; | |
727 | *pos++ = ssid_len; | |
728 | os_memcpy(pos, ssid, ssid_len); | |
729 | pos += ssid_len; | |
730 | os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); | |
731 | pos += MOBILITY_DOMAIN_ID_LEN; | |
732 | *pos++ = r0kh_id_len; | |
733 | os_memcpy(pos, r0kh_id, r0kh_id_len); | |
734 | pos += r0kh_id_len; | |
735 | os_memcpy(pos, s0kh_id, ETH_ALEN); | |
736 | pos += ETH_ALEN; | |
737 | ||
738 | sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, | |
739 | r0_key_data, sizeof(r0_key_data)); | |
740 | os_memcpy(pmk_r0, r0_key_data, PMK_LEN); | |
741 | ||
742 | /* | |
743 | * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) | |
744 | */ | |
745 | addr[0] = (const u8 *) "FT-R0N"; | |
746 | len[0] = 6; | |
747 | addr[1] = r0_key_data + PMK_LEN; | |
748 | len[1] = 16; | |
749 | ||
750 | sha256_vector(2, addr, len, hash); | |
751 | os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); | |
752 | } | |
753 | ||
754 | ||
755 | /** | |
756 | * wpa_derive_pmk_r1_name - Derive PMKR1Name | |
757 | * | |
c1e033b0 | 758 | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
6fc6879b JM |
759 | */ |
760 | void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, | |
761 | const u8 *s1kh_id, u8 *pmk_r1_name) | |
762 | { | |
763 | u8 hash[32]; | |
764 | const u8 *addr[4]; | |
765 | size_t len[4]; | |
766 | ||
767 | /* | |
768 | * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || | |
769 | * R1KH-ID || S1KH-ID)) | |
770 | */ | |
771 | addr[0] = (const u8 *) "FT-R1N"; | |
772 | len[0] = 6; | |
773 | addr[1] = pmk_r0_name; | |
774 | len[1] = WPA_PMK_NAME_LEN; | |
775 | addr[2] = r1kh_id; | |
776 | len[2] = FT_R1KH_ID_LEN; | |
777 | addr[3] = s1kh_id; | |
778 | len[3] = ETH_ALEN; | |
779 | ||
780 | sha256_vector(4, addr, len, hash); | |
781 | os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); | |
782 | } | |
783 | ||
784 | ||
785 | /** | |
786 | * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 | |
787 | * | |
c1e033b0 | 788 | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
6fc6879b JM |
789 | */ |
790 | void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, | |
791 | const u8 *r1kh_id, const u8 *s1kh_id, | |
792 | u8 *pmk_r1, u8 *pmk_r1_name) | |
793 | { | |
794 | u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; | |
795 | u8 *pos; | |
796 | ||
797 | /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ | |
798 | pos = buf; | |
799 | os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); | |
800 | pos += FT_R1KH_ID_LEN; | |
801 | os_memcpy(pos, s1kh_id, ETH_ALEN); | |
802 | pos += ETH_ALEN; | |
803 | ||
804 | sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); | |
805 | ||
806 | wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); | |
807 | } | |
808 | ||
809 | ||
810 | /** | |
811 | * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 | |
812 | * | |
c1e033b0 | 813 | * IEEE Std 802.11r-2008 - 8.5.1.5.5 |
6fc6879b JM |
814 | */ |
815 | void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, | |
816 | const u8 *sta_addr, const u8 *bssid, | |
817 | const u8 *pmk_r1_name, | |
818 | u8 *ptk, size_t ptk_len, u8 *ptk_name) | |
819 | { | |
820 | u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; | |
821 | u8 *pos, hash[32]; | |
822 | const u8 *addr[6]; | |
823 | size_t len[6]; | |
824 | ||
825 | /* | |
826 | * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || | |
827 | * BSSID || STA-ADDR) | |
828 | */ | |
829 | pos = buf; | |
830 | os_memcpy(pos, snonce, WPA_NONCE_LEN); | |
831 | pos += WPA_NONCE_LEN; | |
832 | os_memcpy(pos, anonce, WPA_NONCE_LEN); | |
833 | pos += WPA_NONCE_LEN; | |
834 | os_memcpy(pos, bssid, ETH_ALEN); | |
835 | pos += ETH_ALEN; | |
836 | os_memcpy(pos, sta_addr, ETH_ALEN); | |
837 | pos += ETH_ALEN; | |
838 | ||
839 | sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); | |
840 | ||
841 | /* | |
842 | * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || | |
843 | * ANonce || BSSID || STA-ADDR)) | |
844 | */ | |
845 | addr[0] = pmk_r1_name; | |
846 | len[0] = WPA_PMK_NAME_LEN; | |
847 | addr[1] = (const u8 *) "FT-PTKN"; | |
848 | len[1] = 7; | |
849 | addr[2] = snonce; | |
850 | len[2] = WPA_NONCE_LEN; | |
851 | addr[3] = anonce; | |
852 | len[3] = WPA_NONCE_LEN; | |
853 | addr[4] = bssid; | |
854 | len[4] = ETH_ALEN; | |
855 | addr[5] = sta_addr; | |
856 | len[5] = ETH_ALEN; | |
857 | ||
858 | sha256_vector(6, addr, len, hash); | |
859 | os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); | |
860 | } | |
861 | ||
862 | #endif /* CONFIG_IEEE80211R */ | |
13268290 JM |
863 | |
864 | ||
865 | /** | |
866 | * rsn_pmkid - Calculate PMK identifier | |
867 | * @pmk: Pairwise master key | |
868 | * @pmk_len: Length of pmk in bytes | |
869 | * @aa: Authenticator address | |
870 | * @spa: Supplicant address | |
871 | * @pmkid: Buffer for PMKID | |
872 | * @use_sha256: Whether to use SHA256-based KDF | |
873 | * | |
874 | * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy | |
875 | * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) | |
876 | */ | |
877 | void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, | |
878 | u8 *pmkid, int use_sha256) | |
879 | { | |
880 | char *title = "PMK Name"; | |
881 | const u8 *addr[3]; | |
882 | const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; | |
883 | unsigned char hash[SHA256_MAC_LEN]; | |
884 | ||
885 | addr[0] = (u8 *) title; | |
886 | addr[1] = aa; | |
887 | addr[2] = spa; | |
888 | ||
889 | #ifdef CONFIG_IEEE80211W | |
890 | if (use_sha256) | |
891 | hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); | |
892 | else | |
893 | #endif /* CONFIG_IEEE80211W */ | |
894 | hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); | |
895 | os_memcpy(pmkid, hash, PMKID_LEN); | |
896 | } | |
43fb5297 JM |
897 | |
898 | ||
899 | /** | |
900 | * wpa_cipher_txt - Convert cipher suite to a text string | |
901 | * @cipher: Cipher suite (WPA_CIPHER_* enum) | |
902 | * Returns: Pointer to a text string of the cipher suite name | |
903 | */ | |
904 | const char * wpa_cipher_txt(int cipher) | |
905 | { | |
906 | switch (cipher) { | |
907 | case WPA_CIPHER_NONE: | |
908 | return "NONE"; | |
909 | case WPA_CIPHER_WEP40: | |
910 | return "WEP-40"; | |
911 | case WPA_CIPHER_WEP104: | |
912 | return "WEP-104"; | |
913 | case WPA_CIPHER_TKIP: | |
914 | return "TKIP"; | |
915 | case WPA_CIPHER_CCMP: | |
916 | return "CCMP"; | |
917 | case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: | |
918 | return "CCMP+TKIP"; | |
eb7719ff JM |
919 | case WPA_CIPHER_GCMP: |
920 | return "GCMP"; | |
43fb5297 JM |
921 | default: |
922 | return "UNKNOWN"; | |
923 | } | |
924 | } | |
925 | ||
926 | ||
927 | /** | |
928 | * wpa_key_mgmt_txt - Convert key management suite to a text string | |
929 | * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) | |
930 | * @proto: WPA/WPA2 version (WPA_PROTO_*) | |
931 | * Returns: Pointer to a text string of the key management suite name | |
932 | */ | |
933 | const char * wpa_key_mgmt_txt(int key_mgmt, int proto) | |
934 | { | |
935 | switch (key_mgmt) { | |
936 | case WPA_KEY_MGMT_IEEE8021X: | |
937 | if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) | |
938 | return "WPA2+WPA/IEEE 802.1X/EAP"; | |
939 | return proto == WPA_PROTO_RSN ? | |
940 | "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; | |
941 | case WPA_KEY_MGMT_PSK: | |
942 | if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) | |
943 | return "WPA2-PSK+WPA-PSK"; | |
944 | return proto == WPA_PROTO_RSN ? | |
945 | "WPA2-PSK" : "WPA-PSK"; | |
946 | case WPA_KEY_MGMT_NONE: | |
947 | return "NONE"; | |
948 | case WPA_KEY_MGMT_IEEE8021X_NO_WPA: | |
949 | return "IEEE 802.1X (no WPA)"; | |
950 | #ifdef CONFIG_IEEE80211R | |
951 | case WPA_KEY_MGMT_FT_IEEE8021X: | |
952 | return "FT-EAP"; | |
953 | case WPA_KEY_MGMT_FT_PSK: | |
954 | return "FT-PSK"; | |
955 | #endif /* CONFIG_IEEE80211R */ | |
956 | #ifdef CONFIG_IEEE80211W | |
957 | case WPA_KEY_MGMT_IEEE8021X_SHA256: | |
958 | return "WPA2-EAP-SHA256"; | |
959 | case WPA_KEY_MGMT_PSK_SHA256: | |
960 | return "WPA2-PSK-SHA256"; | |
961 | #endif /* CONFIG_IEEE80211W */ | |
962 | default: | |
963 | return "UNKNOWN"; | |
964 | } | |
965 | } | |
26e23750 JM |
966 | |
967 | ||
968 | int wpa_compare_rsn_ie(int ft_initial_assoc, | |
969 | const u8 *ie1, size_t ie1len, | |
970 | const u8 *ie2, size_t ie2len) | |
971 | { | |
d3ccead3 JM |
972 | if (ie1 == NULL || ie2 == NULL) |
973 | return -1; | |
974 | ||
26e23750 JM |
975 | if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) |
976 | return 0; /* identical IEs */ | |
977 | ||
978 | #ifdef CONFIG_IEEE80211R | |
979 | if (ft_initial_assoc) { | |
980 | struct wpa_ie_data ie1d, ie2d; | |
981 | /* | |
982 | * The PMKID-List in RSN IE is different between Beacon/Probe | |
983 | * Response/(Re)Association Request frames and EAPOL-Key | |
984 | * messages in FT initial mobility domain association. Allow | |
985 | * for this, but verify that other parts of the RSN IEs are | |
986 | * identical. | |
987 | */ | |
988 | if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || | |
989 | wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) | |
990 | return -1; | |
991 | if (ie1d.proto == ie2d.proto && | |
992 | ie1d.pairwise_cipher == ie2d.pairwise_cipher && | |
993 | ie1d.group_cipher == ie2d.group_cipher && | |
994 | ie1d.key_mgmt == ie2d.key_mgmt && | |
995 | ie1d.capabilities == ie2d.capabilities && | |
996 | ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) | |
997 | return 0; | |
998 | } | |
999 | #endif /* CONFIG_IEEE80211R */ | |
1000 | ||
1001 | return -1; | |
1002 | } | |
1003 | ||
1004 | ||
1005 | #ifdef CONFIG_IEEE80211R | |
1006 | int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) | |
1007 | { | |
1008 | u8 *start, *end, *rpos, *rend; | |
1009 | int added = 0; | |
1010 | ||
1011 | start = ies; | |
1012 | end = ies + ies_len; | |
1013 | ||
1014 | while (start < end) { | |
1015 | if (*start == WLAN_EID_RSN) | |
1016 | break; | |
1017 | start += 2 + start[1]; | |
1018 | } | |
1019 | if (start >= end) { | |
1020 | wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " | |
1021 | "IEs data"); | |
1022 | return -1; | |
1023 | } | |
1024 | wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", | |
1025 | start, 2 + start[1]); | |
1026 | ||
1027 | /* Find start of PMKID-Count */ | |
1028 | rpos = start + 2; | |
1029 | rend = rpos + start[1]; | |
1030 | ||
1031 | /* Skip Version and Group Data Cipher Suite */ | |
1032 | rpos += 2 + 4; | |
1033 | /* Skip Pairwise Cipher Suite Count and List */ | |
1034 | rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; | |
1035 | /* Skip AKM Suite Count and List */ | |
1036 | rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; | |
1037 | ||
1038 | if (rpos == rend) { | |
1039 | /* Add RSN Capabilities */ | |
1040 | os_memmove(rpos + 2, rpos, end - rpos); | |
1041 | *rpos++ = 0; | |
1042 | *rpos++ = 0; | |
1043 | } else { | |
1044 | /* Skip RSN Capabilities */ | |
1045 | rpos += 2; | |
1046 | if (rpos > rend) { | |
1047 | wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " | |
1048 | "IEs data"); | |
1049 | return -1; | |
1050 | } | |
1051 | } | |
1052 | ||
1053 | if (rpos == rend) { | |
1054 | /* No PMKID-Count field included; add it */ | |
1055 | os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); | |
1056 | WPA_PUT_LE16(rpos, 1); | |
1057 | rpos += 2; | |
1058 | os_memcpy(rpos, pmkid, PMKID_LEN); | |
1059 | added += 2 + PMKID_LEN; | |
1060 | start[1] += 2 + PMKID_LEN; | |
1061 | } else { | |
1062 | /* PMKID-Count was included; use it */ | |
1063 | if (WPA_GET_LE16(rpos) != 0) { | |
1064 | wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " | |
1065 | "in RSN IE in EAPOL-Key data"); | |
1066 | return -1; | |
1067 | } | |
1068 | WPA_PUT_LE16(rpos, 1); | |
1069 | rpos += 2; | |
1070 | os_memmove(rpos + PMKID_LEN, rpos, end - rpos); | |
1071 | os_memcpy(rpos, pmkid, PMKID_LEN); | |
1072 | added += PMKID_LEN; | |
1073 | start[1] += PMKID_LEN; | |
1074 | } | |
1075 | ||
1076 | wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " | |
1077 | "(PMKID inserted)", start, 2 + start[1]); | |
1078 | ||
1079 | return added; | |
1080 | } | |
1081 | #endif /* CONFIG_IEEE80211R */ | |
c3550295 JM |
1082 | |
1083 | ||
1084 | int wpa_cipher_key_len(int cipher) | |
1085 | { | |
1086 | switch (cipher) { | |
1087 | case WPA_CIPHER_CCMP: | |
1088 | case WPA_CIPHER_GCMP: | |
1089 | return 16; | |
1090 | case WPA_CIPHER_TKIP: | |
1091 | return 32; | |
1092 | case WPA_CIPHER_WEP104: | |
1093 | return 13; | |
1094 | case WPA_CIPHER_WEP40: | |
1095 | return 5; | |
1096 | } | |
1097 | ||
1098 | return 0; | |
1099 | } | |
1100 | ||
1101 | ||
1102 | int wpa_cipher_rsc_len(int cipher) | |
1103 | { | |
1104 | switch (cipher) { | |
1105 | case WPA_CIPHER_CCMP: | |
1106 | case WPA_CIPHER_GCMP: | |
1107 | case WPA_CIPHER_TKIP: | |
1108 | return 6; | |
1109 | case WPA_CIPHER_WEP104: | |
1110 | case WPA_CIPHER_WEP40: | |
1111 | return 0; | |
1112 | } | |
1113 | ||
1114 | return 0; | |
1115 | } | |
1116 | ||
1117 | ||
1118 | int wpa_cipher_to_alg(int cipher) | |
1119 | { | |
1120 | switch (cipher) { | |
1121 | case WPA_CIPHER_CCMP: | |
1122 | return WPA_ALG_CCMP; | |
1123 | case WPA_CIPHER_GCMP: | |
1124 | return WPA_ALG_GCMP; | |
1125 | case WPA_CIPHER_TKIP: | |
1126 | return WPA_ALG_TKIP; | |
1127 | case WPA_CIPHER_WEP104: | |
1128 | case WPA_CIPHER_WEP40: | |
1129 | return WPA_ALG_WEP; | |
1130 | } | |
1131 | return WPA_ALG_NONE; | |
1132 | } | |
1133 | ||
1134 | ||
1135 | int wpa_cipher_valid_pairwise(int cipher) | |
1136 | { | |
1137 | return cipher == WPA_CIPHER_CCMP || | |
1138 | cipher == WPA_CIPHER_GCMP || | |
1139 | cipher == WPA_CIPHER_TKIP; | |
1140 | } | |
1141 | ||
1142 | ||
1143 | u32 wpa_cipher_to_suite(int proto, int cipher) | |
1144 | { | |
1145 | if (cipher & WPA_CIPHER_CCMP) | |
1146 | return (proto == WPA_PROTO_RSN ? | |
1147 | RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); | |
1148 | if (cipher & WPA_CIPHER_GCMP) | |
1149 | return RSN_CIPHER_SUITE_GCMP; | |
1150 | if (cipher & WPA_CIPHER_TKIP) | |
1151 | return (proto == WPA_PROTO_RSN ? | |
1152 | RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); | |
1153 | if (cipher & WPA_CIPHER_WEP104) | |
1154 | return (proto == WPA_PROTO_RSN ? | |
1155 | RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); | |
1156 | if (cipher & WPA_CIPHER_WEP40) | |
1157 | return (proto == WPA_PROTO_RSN ? | |
1158 | RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); | |
1159 | if (cipher & WPA_CIPHER_NONE) | |
1160 | return (proto == WPA_PROTO_RSN ? | |
1161 | RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); | |
1162 | return 0; | |
1163 | } | |
1164 | ||
1165 | ||
1166 | int rsn_cipher_put_suites(u8 *pos, int ciphers) | |
1167 | { | |
1168 | int num_suites = 0; | |
1169 | ||
1170 | if (ciphers & WPA_CIPHER_CCMP) { | |
1171 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); | |
1172 | pos += RSN_SELECTOR_LEN; | |
1173 | num_suites++; | |
1174 | } | |
1175 | if (ciphers & WPA_CIPHER_GCMP) { | |
1176 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); | |
1177 | pos += RSN_SELECTOR_LEN; | |
1178 | num_suites++; | |
1179 | } | |
1180 | if (ciphers & WPA_CIPHER_TKIP) { | |
1181 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); | |
1182 | pos += RSN_SELECTOR_LEN; | |
1183 | num_suites++; | |
1184 | } | |
1185 | if (ciphers & WPA_CIPHER_NONE) { | |
1186 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); | |
1187 | pos += RSN_SELECTOR_LEN; | |
1188 | num_suites++; | |
1189 | } | |
1190 | ||
1191 | return num_suites; | |
1192 | } | |
1193 | ||
1194 | ||
1195 | int wpa_cipher_put_suites(u8 *pos, int ciphers) | |
1196 | { | |
1197 | int num_suites = 0; | |
1198 | ||
1199 | if (ciphers & WPA_CIPHER_CCMP) { | |
1200 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); | |
1201 | pos += WPA_SELECTOR_LEN; | |
1202 | num_suites++; | |
1203 | } | |
1204 | if (ciphers & WPA_CIPHER_TKIP) { | |
1205 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); | |
1206 | pos += WPA_SELECTOR_LEN; | |
1207 | num_suites++; | |
1208 | } | |
1209 | if (ciphers & WPA_CIPHER_NONE) { | |
1210 | RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); | |
1211 | pos += WPA_SELECTOR_LEN; | |
1212 | num_suites++; | |
1213 | } | |
1214 | ||
1215 | return num_suites; | |
1216 | } | |
edbd2a19 JM |
1217 | |
1218 | ||
1219 | int wpa_pick_pairwise_cipher(int ciphers, int none_allowed) | |
1220 | { | |
1221 | if (ciphers & WPA_CIPHER_CCMP) | |
1222 | return WPA_CIPHER_CCMP; | |
1223 | if (ciphers & WPA_CIPHER_GCMP) | |
1224 | return WPA_CIPHER_GCMP; | |
1225 | if (ciphers & WPA_CIPHER_TKIP) | |
1226 | return WPA_CIPHER_TKIP; | |
1227 | if (none_allowed && (ciphers & WPA_CIPHER_NONE)) | |
1228 | return WPA_CIPHER_NONE; | |
1229 | return -1; | |
1230 | } | |
1231 | ||
1232 | ||
1233 | int wpa_pick_group_cipher(int ciphers) | |
1234 | { | |
1235 | if (ciphers & WPA_CIPHER_CCMP) | |
1236 | return WPA_CIPHER_CCMP; | |
1237 | if (ciphers & WPA_CIPHER_GCMP) | |
1238 | return WPA_CIPHER_GCMP; | |
1239 | if (ciphers & WPA_CIPHER_TKIP) | |
1240 | return WPA_CIPHER_TKIP; | |
1241 | if (ciphers & WPA_CIPHER_WEP104) | |
1242 | return WPA_CIPHER_WEP104; | |
1243 | if (ciphers & WPA_CIPHER_WEP40) | |
1244 | return WPA_CIPHER_WEP40; | |
1245 | return -1; | |
1246 | } |