]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA/RSN - Shared functions for supplicant and authenticator | |
3 | * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "common.h" | |
18 | #include "md5.h" | |
19 | #include "sha1.h" | |
20 | #include "sha256.h" | |
21 | #include "aes_wrap.h" | |
22 | #include "crypto.h" | |
23 | #include "ieee802_11_defs.h" | |
24 | #include "defs.h" | |
25 | #include "wpa_common.h" | |
26 | ||
27 | ||
28 | /** | |
29 | * wpa_eapol_key_mic - Calculate EAPOL-Key MIC | |
30 | * @key: EAPOL-Key Key Confirmation Key (KCK) | |
31 | * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) | |
32 | * @buf: Pointer to the beginning of the EAPOL header (version field) | |
33 | * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) | |
34 | * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written | |
35 | * Returns: 0 on success, -1 on failure | |
36 | * | |
37 | * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has | |
38 | * to be cleared (all zeroes) when calling this function. | |
39 | * | |
40 | * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the | |
41 | * description of the Key MIC calculation. It includes packet data from the | |
42 | * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change | |
43 | * happened during final editing of the standard and the correct behavior is | |
44 | * defined in the last draft (IEEE 802.11i/D10). | |
45 | */ | |
46 | int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, | |
47 | u8 *mic) | |
48 | { | |
49 | u8 hash[SHA1_MAC_LEN]; | |
50 | ||
51 | switch (ver) { | |
52 | case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: | |
53 | hmac_md5(key, 16, buf, len, mic); | |
54 | break; | |
55 | case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: | |
56 | hmac_sha1(key, 16, buf, len, hash); | |
57 | os_memcpy(mic, hash, MD5_MAC_LEN); | |
58 | break; | |
59 | #ifdef CONFIG_IEEE80211R | |
60 | case WPA_KEY_INFO_TYPE_AES_128_CMAC: | |
61 | return omac1_aes_128(key, buf, len, mic); | |
62 | #endif /* CONFIG_IEEE80211R */ | |
63 | default: | |
64 | return -1; | |
65 | } | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | ||
71 | /** | |
72 | * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces | |
73 | * @pmk: Pairwise master key | |
74 | * @pmk_len: Length of PMK | |
75 | * @label: Label to use in derivation | |
76 | * @addr1: AA or SA | |
77 | * @addr2: SA or AA | |
78 | * @nonce1: ANonce or SNonce | |
79 | * @nonce2: SNonce or ANonce | |
80 | * @ptk: Buffer for pairwise transient key | |
81 | * @ptk_len: Length of PTK | |
56586197 | 82 | * @use_sha256: Whether to use SHA256-based KDF |
6fc6879b JM |
83 | * |
84 | * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy | |
85 | * PTK = PRF-X(PMK, "Pairwise key expansion", | |
86 | * Min(AA, SA) || Max(AA, SA) || | |
87 | * Min(ANonce, SNonce) || Max(ANonce, SNonce)) | |
88 | * | |
89 | * STK = PRF-X(SMK, "Peer key expansion", | |
90 | * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || | |
91 | * Min(INonce, PNonce) || Max(INonce, PNonce)) | |
92 | */ | |
93 | void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, | |
94 | const u8 *addr1, const u8 *addr2, | |
95 | const u8 *nonce1, const u8 *nonce2, | |
56586197 | 96 | u8 *ptk, size_t ptk_len, int use_sha256) |
6fc6879b JM |
97 | { |
98 | u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; | |
99 | ||
100 | if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { | |
101 | os_memcpy(data, addr1, ETH_ALEN); | |
102 | os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); | |
103 | } else { | |
104 | os_memcpy(data, addr2, ETH_ALEN); | |
105 | os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); | |
106 | } | |
107 | ||
108 | if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { | |
109 | os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); | |
110 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, | |
111 | WPA_NONCE_LEN); | |
112 | } else { | |
113 | os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); | |
114 | os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, | |
115 | WPA_NONCE_LEN); | |
116 | } | |
117 | ||
56586197 JM |
118 | #ifdef CONFIG_IEEE80211W |
119 | if (use_sha256) | |
120 | sha256_prf(pmk, pmk_len, label, data, sizeof(data), | |
121 | ptk, ptk_len); | |
122 | else | |
123 | #endif /* CONFIG_IEEE80211W */ | |
124 | sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, | |
125 | ptk_len); | |
6fc6879b JM |
126 | |
127 | wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, | |
128 | MAC2STR(addr1), MAC2STR(addr2)); | |
129 | wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); | |
130 | wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); | |
131 | } | |
132 | ||
133 | ||
134 | #ifdef CONFIG_IEEE80211R | |
135 | int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, | |
136 | u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, | |
137 | const u8 *ftie, size_t ftie_len, | |
138 | const u8 *rsnie, size_t rsnie_len, | |
139 | const u8 *ric, size_t ric_len, u8 *mic) | |
140 | { | |
141 | u8 *buf, *pos; | |
142 | size_t buf_len; | |
143 | ||
144 | buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; | |
145 | buf = os_malloc(buf_len); | |
146 | if (buf == NULL) | |
147 | return -1; | |
148 | ||
149 | pos = buf; | |
150 | os_memcpy(pos, sta_addr, ETH_ALEN); | |
151 | pos += ETH_ALEN; | |
152 | os_memcpy(pos, ap_addr, ETH_ALEN); | |
153 | pos += ETH_ALEN; | |
154 | *pos++ = transaction_seqnum; | |
155 | if (rsnie) { | |
156 | os_memcpy(pos, rsnie, rsnie_len); | |
157 | pos += rsnie_len; | |
158 | } | |
159 | if (mdie) { | |
160 | os_memcpy(pos, mdie, mdie_len); | |
161 | pos += mdie_len; | |
162 | } | |
163 | if (ftie) { | |
164 | struct rsn_ftie *_ftie; | |
165 | os_memcpy(pos, ftie, ftie_len); | |
166 | if (ftie_len < 2 + sizeof(*_ftie)) { | |
167 | os_free(buf); | |
168 | return -1; | |
169 | } | |
170 | _ftie = (struct rsn_ftie *) (pos + 2); | |
171 | os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); | |
172 | pos += ftie_len; | |
173 | } | |
174 | if (ric) { | |
175 | os_memcpy(pos, ric, ric_len); | |
176 | pos += ric_len; | |
177 | } | |
178 | ||
179 | wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); | |
180 | if (omac1_aes_128(kck, buf, pos - buf, mic)) { | |
181 | os_free(buf); | |
182 | return -1; | |
183 | } | |
184 | ||
185 | os_free(buf); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | #endif /* CONFIG_IEEE80211R */ | |
190 | ||
191 | ||
192 | #ifndef CONFIG_NO_WPA2 | |
193 | static int rsn_selector_to_bitfield(const u8 *s) | |
194 | { | |
195 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) | |
196 | return WPA_CIPHER_NONE; | |
197 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) | |
198 | return WPA_CIPHER_WEP40; | |
199 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) | |
200 | return WPA_CIPHER_TKIP; | |
201 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) | |
202 | return WPA_CIPHER_CCMP; | |
203 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) | |
204 | return WPA_CIPHER_WEP104; | |
205 | #ifdef CONFIG_IEEE80211W | |
206 | if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) | |
207 | return WPA_CIPHER_AES_128_CMAC; | |
208 | #endif /* CONFIG_IEEE80211W */ | |
209 | return 0; | |
210 | } | |
211 | ||
212 | ||
213 | static int rsn_key_mgmt_to_bitfield(const u8 *s) | |
214 | { | |
215 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) | |
216 | return WPA_KEY_MGMT_IEEE8021X; | |
217 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) | |
218 | return WPA_KEY_MGMT_PSK; | |
219 | #ifdef CONFIG_IEEE80211R | |
220 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) | |
221 | return WPA_KEY_MGMT_FT_IEEE8021X; | |
222 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) | |
223 | return WPA_KEY_MGMT_FT_PSK; | |
224 | #endif /* CONFIG_IEEE80211R */ | |
56586197 JM |
225 | #ifdef CONFIG_IEEE80211W |
226 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) | |
227 | return WPA_KEY_MGMT_IEEE8021X_SHA256; | |
228 | if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) | |
229 | return WPA_KEY_MGMT_PSK_SHA256; | |
230 | #endif /* CONFIG_IEEE80211W */ | |
6fc6879b JM |
231 | return 0; |
232 | } | |
233 | #endif /* CONFIG_NO_WPA2 */ | |
234 | ||
235 | ||
236 | /** | |
237 | * wpa_parse_wpa_ie_rsn - Parse RSN IE | |
238 | * @rsn_ie: Buffer containing RSN IE | |
239 | * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) | |
240 | * @data: Pointer to structure that will be filled in with parsed data | |
241 | * Returns: 0 on success, <0 on failure | |
242 | */ | |
243 | int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, | |
244 | struct wpa_ie_data *data) | |
245 | { | |
246 | #ifndef CONFIG_NO_WPA2 | |
247 | const struct rsn_ie_hdr *hdr; | |
248 | const u8 *pos; | |
249 | int left; | |
250 | int i, count; | |
251 | ||
252 | os_memset(data, 0, sizeof(*data)); | |
253 | data->proto = WPA_PROTO_RSN; | |
254 | data->pairwise_cipher = WPA_CIPHER_CCMP; | |
255 | data->group_cipher = WPA_CIPHER_CCMP; | |
256 | data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
257 | data->capabilities = 0; | |
258 | data->pmkid = NULL; | |
259 | data->num_pmkid = 0; | |
260 | #ifdef CONFIG_IEEE80211W | |
261 | data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; | |
262 | #else /* CONFIG_IEEE80211W */ | |
263 | data->mgmt_group_cipher = 0; | |
264 | #endif /* CONFIG_IEEE80211W */ | |
265 | ||
266 | if (rsn_ie_len == 0) { | |
267 | /* No RSN IE - fail silently */ | |
268 | return -1; | |
269 | } | |
270 | ||
271 | if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { | |
272 | wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", | |
273 | __func__, (unsigned long) rsn_ie_len); | |
274 | return -1; | |
275 | } | |
276 | ||
277 | hdr = (const struct rsn_ie_hdr *) rsn_ie; | |
278 | ||
279 | if (hdr->elem_id != WLAN_EID_RSN || | |
280 | hdr->len != rsn_ie_len - 2 || | |
281 | WPA_GET_LE16(hdr->version) != RSN_VERSION) { | |
282 | wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", | |
283 | __func__); | |
284 | return -2; | |
285 | } | |
286 | ||
287 | pos = (const u8 *) (hdr + 1); | |
288 | left = rsn_ie_len - sizeof(*hdr); | |
289 | ||
290 | if (left >= RSN_SELECTOR_LEN) { | |
291 | data->group_cipher = rsn_selector_to_bitfield(pos); | |
292 | #ifdef CONFIG_IEEE80211W | |
293 | if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { | |
294 | wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " | |
295 | "cipher", __func__); | |
296 | return -1; | |
297 | } | |
298 | #endif /* CONFIG_IEEE80211W */ | |
299 | pos += RSN_SELECTOR_LEN; | |
300 | left -= RSN_SELECTOR_LEN; | |
301 | } else if (left > 0) { | |
302 | wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", | |
303 | __func__, left); | |
304 | return -3; | |
305 | } | |
306 | ||
307 | if (left >= 2) { | |
308 | data->pairwise_cipher = 0; | |
309 | count = WPA_GET_LE16(pos); | |
310 | pos += 2; | |
311 | left -= 2; | |
312 | if (count == 0 || left < count * RSN_SELECTOR_LEN) { | |
313 | wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " | |
314 | "count %u left %u", __func__, count, left); | |
315 | return -4; | |
316 | } | |
317 | for (i = 0; i < count; i++) { | |
318 | data->pairwise_cipher |= rsn_selector_to_bitfield(pos); | |
319 | pos += RSN_SELECTOR_LEN; | |
320 | left -= RSN_SELECTOR_LEN; | |
321 | } | |
322 | #ifdef CONFIG_IEEE80211W | |
323 | if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { | |
324 | wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " | |
325 | "pairwise cipher", __func__); | |
326 | return -1; | |
327 | } | |
328 | #endif /* CONFIG_IEEE80211W */ | |
329 | } else if (left == 1) { | |
330 | wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", | |
331 | __func__); | |
332 | return -5; | |
333 | } | |
334 | ||
335 | if (left >= 2) { | |
336 | data->key_mgmt = 0; | |
337 | count = WPA_GET_LE16(pos); | |
338 | pos += 2; | |
339 | left -= 2; | |
340 | if (count == 0 || left < count * RSN_SELECTOR_LEN) { | |
341 | wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " | |
342 | "count %u left %u", __func__, count, left); | |
343 | return -6; | |
344 | } | |
345 | for (i = 0; i < count; i++) { | |
346 | data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); | |
347 | pos += RSN_SELECTOR_LEN; | |
348 | left -= RSN_SELECTOR_LEN; | |
349 | } | |
350 | } else if (left == 1) { | |
351 | wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", | |
352 | __func__); | |
353 | return -7; | |
354 | } | |
355 | ||
356 | if (left >= 2) { | |
357 | data->capabilities = WPA_GET_LE16(pos); | |
358 | pos += 2; | |
359 | left -= 2; | |
360 | } | |
361 | ||
362 | if (left >= 2) { | |
363 | data->num_pmkid = WPA_GET_LE16(pos); | |
364 | pos += 2; | |
365 | left -= 2; | |
366 | if (left < (int) data->num_pmkid * PMKID_LEN) { | |
367 | wpa_printf(MSG_DEBUG, "%s: PMKID underflow " | |
368 | "(num_pmkid=%lu left=%d)", | |
369 | __func__, (unsigned long) data->num_pmkid, | |
370 | left); | |
371 | data->num_pmkid = 0; | |
372 | return -9; | |
373 | } else { | |
374 | data->pmkid = pos; | |
375 | pos += data->num_pmkid * PMKID_LEN; | |
376 | left -= data->num_pmkid * PMKID_LEN; | |
377 | } | |
378 | } | |
379 | ||
380 | #ifdef CONFIG_IEEE80211W | |
381 | if (left >= 4) { | |
382 | data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); | |
383 | if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { | |
384 | wpa_printf(MSG_DEBUG, "%s: Unsupported management " | |
385 | "group cipher 0x%x", __func__, | |
386 | data->mgmt_group_cipher); | |
387 | return -10; | |
388 | } | |
389 | pos += RSN_SELECTOR_LEN; | |
390 | left -= RSN_SELECTOR_LEN; | |
391 | } | |
392 | #endif /* CONFIG_IEEE80211W */ | |
393 | ||
394 | if (left > 0) { | |
395 | wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", | |
396 | __func__, left); | |
397 | } | |
398 | ||
399 | return 0; | |
400 | #else /* CONFIG_NO_WPA2 */ | |
401 | return -1; | |
402 | #endif /* CONFIG_NO_WPA2 */ | |
403 | } | |
404 | ||
405 | ||
406 | #ifdef CONFIG_IEEE80211R | |
407 | ||
408 | /** | |
409 | * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name | |
410 | * | |
c1e033b0 | 411 | * IEEE Std 802.11r-2008 - 8.5.1.5.3 |
6fc6879b JM |
412 | */ |
413 | void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, | |
414 | const u8 *ssid, size_t ssid_len, | |
415 | const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, | |
416 | const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) | |
417 | { | |
418 | u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + | |
419 | FT_R0KH_ID_MAX_LEN + ETH_ALEN]; | |
420 | u8 *pos, r0_key_data[48], hash[32]; | |
421 | const u8 *addr[2]; | |
422 | size_t len[2]; | |
423 | ||
424 | /* | |
425 | * R0-Key-Data = KDF-384(XXKey, "FT-R0", | |
426 | * SSIDlength || SSID || MDID || R0KHlength || | |
427 | * R0KH-ID || S0KH-ID) | |
428 | * XXKey is either the second 256 bits of MSK or PSK. | |
429 | * PMK-R0 = L(R0-Key-Data, 0, 256) | |
430 | * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) | |
431 | */ | |
432 | if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) | |
433 | return; | |
434 | pos = buf; | |
435 | *pos++ = ssid_len; | |
436 | os_memcpy(pos, ssid, ssid_len); | |
437 | pos += ssid_len; | |
438 | os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); | |
439 | pos += MOBILITY_DOMAIN_ID_LEN; | |
440 | *pos++ = r0kh_id_len; | |
441 | os_memcpy(pos, r0kh_id, r0kh_id_len); | |
442 | pos += r0kh_id_len; | |
443 | os_memcpy(pos, s0kh_id, ETH_ALEN); | |
444 | pos += ETH_ALEN; | |
445 | ||
446 | sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, | |
447 | r0_key_data, sizeof(r0_key_data)); | |
448 | os_memcpy(pmk_r0, r0_key_data, PMK_LEN); | |
449 | ||
450 | /* | |
451 | * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) | |
452 | */ | |
453 | addr[0] = (const u8 *) "FT-R0N"; | |
454 | len[0] = 6; | |
455 | addr[1] = r0_key_data + PMK_LEN; | |
456 | len[1] = 16; | |
457 | ||
458 | sha256_vector(2, addr, len, hash); | |
459 | os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); | |
460 | } | |
461 | ||
462 | ||
463 | /** | |
464 | * wpa_derive_pmk_r1_name - Derive PMKR1Name | |
465 | * | |
c1e033b0 | 466 | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
6fc6879b JM |
467 | */ |
468 | void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, | |
469 | const u8 *s1kh_id, u8 *pmk_r1_name) | |
470 | { | |
471 | u8 hash[32]; | |
472 | const u8 *addr[4]; | |
473 | size_t len[4]; | |
474 | ||
475 | /* | |
476 | * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || | |
477 | * R1KH-ID || S1KH-ID)) | |
478 | */ | |
479 | addr[0] = (const u8 *) "FT-R1N"; | |
480 | len[0] = 6; | |
481 | addr[1] = pmk_r0_name; | |
482 | len[1] = WPA_PMK_NAME_LEN; | |
483 | addr[2] = r1kh_id; | |
484 | len[2] = FT_R1KH_ID_LEN; | |
485 | addr[3] = s1kh_id; | |
486 | len[3] = ETH_ALEN; | |
487 | ||
488 | sha256_vector(4, addr, len, hash); | |
489 | os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); | |
490 | } | |
491 | ||
492 | ||
493 | /** | |
494 | * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 | |
495 | * | |
c1e033b0 | 496 | * IEEE Std 802.11r-2008 - 8.5.1.5.4 |
6fc6879b JM |
497 | */ |
498 | void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, | |
499 | const u8 *r1kh_id, const u8 *s1kh_id, | |
500 | u8 *pmk_r1, u8 *pmk_r1_name) | |
501 | { | |
502 | u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; | |
503 | u8 *pos; | |
504 | ||
505 | /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ | |
506 | pos = buf; | |
507 | os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); | |
508 | pos += FT_R1KH_ID_LEN; | |
509 | os_memcpy(pos, s1kh_id, ETH_ALEN); | |
510 | pos += ETH_ALEN; | |
511 | ||
512 | sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); | |
513 | ||
514 | wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); | |
515 | } | |
516 | ||
517 | ||
518 | /** | |
519 | * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 | |
520 | * | |
c1e033b0 | 521 | * IEEE Std 802.11r-2008 - 8.5.1.5.5 |
6fc6879b JM |
522 | */ |
523 | void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, | |
524 | const u8 *sta_addr, const u8 *bssid, | |
525 | const u8 *pmk_r1_name, | |
526 | u8 *ptk, size_t ptk_len, u8 *ptk_name) | |
527 | { | |
528 | u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; | |
529 | u8 *pos, hash[32]; | |
530 | const u8 *addr[6]; | |
531 | size_t len[6]; | |
532 | ||
533 | /* | |
534 | * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || | |
535 | * BSSID || STA-ADDR) | |
536 | */ | |
537 | pos = buf; | |
538 | os_memcpy(pos, snonce, WPA_NONCE_LEN); | |
539 | pos += WPA_NONCE_LEN; | |
540 | os_memcpy(pos, anonce, WPA_NONCE_LEN); | |
541 | pos += WPA_NONCE_LEN; | |
542 | os_memcpy(pos, bssid, ETH_ALEN); | |
543 | pos += ETH_ALEN; | |
544 | os_memcpy(pos, sta_addr, ETH_ALEN); | |
545 | pos += ETH_ALEN; | |
546 | ||
547 | sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); | |
548 | ||
549 | /* | |
550 | * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || | |
551 | * ANonce || BSSID || STA-ADDR)) | |
552 | */ | |
553 | addr[0] = pmk_r1_name; | |
554 | len[0] = WPA_PMK_NAME_LEN; | |
555 | addr[1] = (const u8 *) "FT-PTKN"; | |
556 | len[1] = 7; | |
557 | addr[2] = snonce; | |
558 | len[2] = WPA_NONCE_LEN; | |
559 | addr[3] = anonce; | |
560 | len[3] = WPA_NONCE_LEN; | |
561 | addr[4] = bssid; | |
562 | len[4] = ETH_ALEN; | |
563 | addr[5] = sta_addr; | |
564 | len[5] = ETH_ALEN; | |
565 | ||
566 | sha256_vector(6, addr, len, hash); | |
567 | os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); | |
568 | } | |
569 | ||
570 | #endif /* CONFIG_IEEE80211R */ |