2 * WPA/RSN - Shared functions for supplicant and authenticator
3 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
23 #include "ieee802_11_defs.h"
25 #include "wpa_common.h"
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
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.
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).
46 int wpa_eapol_key_mic(const u8
*key
, int ver
, const u8
*buf
, size_t len
,
49 u8 hash
[SHA1_MAC_LEN
];
52 case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4
:
53 hmac_md5(key
, 16, buf
, len
, mic
);
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
);
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 */
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
78 * @nonce1: ANonce or SNonce
79 * @nonce2: SNonce or ANonce
80 * @ptk: Buffer for pairwise transient key
81 * @ptk_len: Length of PTK
83 * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
84 * PTK = PRF-X(PMK, "Pairwise key expansion",
85 * Min(AA, SA) || Max(AA, SA) ||
86 * Min(ANonce, SNonce) || Max(ANonce, SNonce))
88 * STK = PRF-X(SMK, "Peer key expansion",
89 * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
90 * Min(INonce, PNonce) || Max(INonce, PNonce))
92 void wpa_pmk_to_ptk(const u8
*pmk
, size_t pmk_len
, const char *label
,
93 const u8
*addr1
, const u8
*addr2
,
94 const u8
*nonce1
, const u8
*nonce2
,
95 u8
*ptk
, size_t ptk_len
)
97 u8 data
[2 * ETH_ALEN
+ 2 * WPA_NONCE_LEN
];
99 if (os_memcmp(addr1
, addr2
, ETH_ALEN
) < 0) {
100 os_memcpy(data
, addr1
, ETH_ALEN
);
101 os_memcpy(data
+ ETH_ALEN
, addr2
, ETH_ALEN
);
103 os_memcpy(data
, addr2
, ETH_ALEN
);
104 os_memcpy(data
+ ETH_ALEN
, addr1
, ETH_ALEN
);
107 if (os_memcmp(nonce1
, nonce2
, WPA_NONCE_LEN
) < 0) {
108 os_memcpy(data
+ 2 * ETH_ALEN
, nonce1
, WPA_NONCE_LEN
);
109 os_memcpy(data
+ 2 * ETH_ALEN
+ WPA_NONCE_LEN
, nonce2
,
112 os_memcpy(data
+ 2 * ETH_ALEN
, nonce2
, WPA_NONCE_LEN
);
113 os_memcpy(data
+ 2 * ETH_ALEN
+ WPA_NONCE_LEN
, nonce1
,
117 sha1_prf(pmk
, pmk_len
, label
, data
, sizeof(data
), ptk
, ptk_len
);
119 wpa_printf(MSG_DEBUG
, "WPA: PTK derivation - A1=" MACSTR
" A2=" MACSTR
,
120 MAC2STR(addr1
), MAC2STR(addr2
));
121 wpa_hexdump_key(MSG_DEBUG
, "WPA: PMK", pmk
, pmk_len
);
122 wpa_hexdump_key(MSG_DEBUG
, "WPA: PTK", ptk
, ptk_len
);
126 #ifdef CONFIG_IEEE80211R
127 int wpa_ft_mic(const u8
*kck
, const u8
*sta_addr
, const u8
*ap_addr
,
128 u8 transaction_seqnum
, const u8
*mdie
, size_t mdie_len
,
129 const u8
*ftie
, size_t ftie_len
,
130 const u8
*rsnie
, size_t rsnie_len
,
131 const u8
*ric
, size_t ric_len
, u8
*mic
)
136 buf_len
= 2 * ETH_ALEN
+ 1 + mdie_len
+ ftie_len
+ rsnie_len
+ ric_len
;
137 buf
= os_malloc(buf_len
);
142 os_memcpy(pos
, sta_addr
, ETH_ALEN
);
144 os_memcpy(pos
, ap_addr
, ETH_ALEN
);
146 *pos
++ = transaction_seqnum
;
148 os_memcpy(pos
, rsnie
, rsnie_len
);
152 os_memcpy(pos
, mdie
, mdie_len
);
156 struct rsn_ftie
*_ftie
;
157 os_memcpy(pos
, ftie
, ftie_len
);
158 if (ftie_len
< 2 + sizeof(*_ftie
)) {
162 _ftie
= (struct rsn_ftie
*) (pos
+ 2);
163 os_memset(_ftie
->mic
, 0, sizeof(_ftie
->mic
));
167 os_memcpy(pos
, ric
, ric_len
);
171 wpa_hexdump(MSG_MSGDUMP
, "FT: MIC data", buf
, pos
- buf
);
172 if (omac1_aes_128(kck
, buf
, pos
- buf
, mic
)) {
181 #endif /* CONFIG_IEEE80211R */
184 #ifndef CONFIG_NO_WPA2
185 static int rsn_selector_to_bitfield(const u8
*s
)
187 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_NONE
)
188 return WPA_CIPHER_NONE
;
189 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_WEP40
)
190 return WPA_CIPHER_WEP40
;
191 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_TKIP
)
192 return WPA_CIPHER_TKIP
;
193 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_CCMP
)
194 return WPA_CIPHER_CCMP
;
195 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_WEP104
)
196 return WPA_CIPHER_WEP104
;
197 #ifdef CONFIG_IEEE80211W
198 if (RSN_SELECTOR_GET(s
) == RSN_CIPHER_SUITE_AES_128_CMAC
)
199 return WPA_CIPHER_AES_128_CMAC
;
200 #endif /* CONFIG_IEEE80211W */
205 static int rsn_key_mgmt_to_bitfield(const u8
*s
)
207 if (RSN_SELECTOR_GET(s
) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X
)
208 return WPA_KEY_MGMT_IEEE8021X
;
209 if (RSN_SELECTOR_GET(s
) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X
)
210 return WPA_KEY_MGMT_PSK
;
211 #ifdef CONFIG_IEEE80211R
212 if (RSN_SELECTOR_GET(s
) == RSN_AUTH_KEY_MGMT_FT_802_1X
)
213 return WPA_KEY_MGMT_FT_IEEE8021X
;
214 if (RSN_SELECTOR_GET(s
) == RSN_AUTH_KEY_MGMT_FT_PSK
)
215 return WPA_KEY_MGMT_FT_PSK
;
216 #endif /* CONFIG_IEEE80211R */
219 #endif /* CONFIG_NO_WPA2 */
223 * wpa_parse_wpa_ie_rsn - Parse RSN IE
224 * @rsn_ie: Buffer containing RSN IE
225 * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
226 * @data: Pointer to structure that will be filled in with parsed data
227 * Returns: 0 on success, <0 on failure
229 int wpa_parse_wpa_ie_rsn(const u8
*rsn_ie
, size_t rsn_ie_len
,
230 struct wpa_ie_data
*data
)
232 #ifndef CONFIG_NO_WPA2
233 const struct rsn_ie_hdr
*hdr
;
238 os_memset(data
, 0, sizeof(*data
));
239 data
->proto
= WPA_PROTO_RSN
;
240 data
->pairwise_cipher
= WPA_CIPHER_CCMP
;
241 data
->group_cipher
= WPA_CIPHER_CCMP
;
242 data
->key_mgmt
= WPA_KEY_MGMT_IEEE8021X
;
243 data
->capabilities
= 0;
246 #ifdef CONFIG_IEEE80211W
247 data
->mgmt_group_cipher
= WPA_CIPHER_AES_128_CMAC
;
248 #else /* CONFIG_IEEE80211W */
249 data
->mgmt_group_cipher
= 0;
250 #endif /* CONFIG_IEEE80211W */
252 if (rsn_ie_len
== 0) {
253 /* No RSN IE - fail silently */
257 if (rsn_ie_len
< sizeof(struct rsn_ie_hdr
)) {
258 wpa_printf(MSG_DEBUG
, "%s: ie len too short %lu",
259 __func__
, (unsigned long) rsn_ie_len
);
263 hdr
= (const struct rsn_ie_hdr
*) rsn_ie
;
265 if (hdr
->elem_id
!= WLAN_EID_RSN
||
266 hdr
->len
!= rsn_ie_len
- 2 ||
267 WPA_GET_LE16(hdr
->version
) != RSN_VERSION
) {
268 wpa_printf(MSG_DEBUG
, "%s: malformed ie or unknown version",
273 pos
= (const u8
*) (hdr
+ 1);
274 left
= rsn_ie_len
- sizeof(*hdr
);
276 if (left
>= RSN_SELECTOR_LEN
) {
277 data
->group_cipher
= rsn_selector_to_bitfield(pos
);
278 #ifdef CONFIG_IEEE80211W
279 if (data
->group_cipher
== WPA_CIPHER_AES_128_CMAC
) {
280 wpa_printf(MSG_DEBUG
, "%s: AES-128-CMAC used as group "
284 #endif /* CONFIG_IEEE80211W */
285 pos
+= RSN_SELECTOR_LEN
;
286 left
-= RSN_SELECTOR_LEN
;
287 } else if (left
> 0) {
288 wpa_printf(MSG_DEBUG
, "%s: ie length mismatch, %u too much",
294 data
->pairwise_cipher
= 0;
295 count
= WPA_GET_LE16(pos
);
298 if (count
== 0 || left
< count
* RSN_SELECTOR_LEN
) {
299 wpa_printf(MSG_DEBUG
, "%s: ie count botch (pairwise), "
300 "count %u left %u", __func__
, count
, left
);
303 for (i
= 0; i
< count
; i
++) {
304 data
->pairwise_cipher
|= rsn_selector_to_bitfield(pos
);
305 pos
+= RSN_SELECTOR_LEN
;
306 left
-= RSN_SELECTOR_LEN
;
308 #ifdef CONFIG_IEEE80211W
309 if (data
->pairwise_cipher
& WPA_CIPHER_AES_128_CMAC
) {
310 wpa_printf(MSG_DEBUG
, "%s: AES-128-CMAC used as "
311 "pairwise cipher", __func__
);
314 #endif /* CONFIG_IEEE80211W */
315 } else if (left
== 1) {
316 wpa_printf(MSG_DEBUG
, "%s: ie too short (for key mgmt)",
323 count
= WPA_GET_LE16(pos
);
326 if (count
== 0 || left
< count
* RSN_SELECTOR_LEN
) {
327 wpa_printf(MSG_DEBUG
, "%s: ie count botch (key mgmt), "
328 "count %u left %u", __func__
, count
, left
);
331 for (i
= 0; i
< count
; i
++) {
332 data
->key_mgmt
|= rsn_key_mgmt_to_bitfield(pos
);
333 pos
+= RSN_SELECTOR_LEN
;
334 left
-= RSN_SELECTOR_LEN
;
336 } else if (left
== 1) {
337 wpa_printf(MSG_DEBUG
, "%s: ie too short (for capabilities)",
343 data
->capabilities
= WPA_GET_LE16(pos
);
349 data
->num_pmkid
= WPA_GET_LE16(pos
);
352 if (left
< (int) data
->num_pmkid
* PMKID_LEN
) {
353 wpa_printf(MSG_DEBUG
, "%s: PMKID underflow "
354 "(num_pmkid=%lu left=%d)",
355 __func__
, (unsigned long) data
->num_pmkid
,
361 pos
+= data
->num_pmkid
* PMKID_LEN
;
362 left
-= data
->num_pmkid
* PMKID_LEN
;
366 #ifdef CONFIG_IEEE80211W
368 data
->mgmt_group_cipher
= rsn_selector_to_bitfield(pos
);
369 if (data
->mgmt_group_cipher
!= WPA_CIPHER_AES_128_CMAC
) {
370 wpa_printf(MSG_DEBUG
, "%s: Unsupported management "
371 "group cipher 0x%x", __func__
,
372 data
->mgmt_group_cipher
);
375 pos
+= RSN_SELECTOR_LEN
;
376 left
-= RSN_SELECTOR_LEN
;
378 #endif /* CONFIG_IEEE80211W */
381 wpa_printf(MSG_DEBUG
, "%s: ie has %u trailing bytes - ignored",
386 #else /* CONFIG_NO_WPA2 */
388 #endif /* CONFIG_NO_WPA2 */
392 #ifdef CONFIG_IEEE80211R
395 * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
397 * IEEE 802.11r/D9.0 - 8.5.1.5.3
399 void wpa_derive_pmk_r0(const u8
*xxkey
, size_t xxkey_len
,
400 const u8
*ssid
, size_t ssid_len
,
401 const u8
*mdid
, const u8
*r0kh_id
, size_t r0kh_id_len
,
402 const u8
*s0kh_id
, u8
*pmk_r0
, u8
*pmk_r0_name
)
404 u8 buf
[1 + WPA_MAX_SSID_LEN
+ MOBILITY_DOMAIN_ID_LEN
+ 1 +
405 FT_R0KH_ID_MAX_LEN
+ ETH_ALEN
];
406 u8
*pos
, r0_key_data
[48], hash
[32];
411 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
412 * SSIDlength || SSID || MDID || R0KHlength ||
413 * R0KH-ID || S0KH-ID)
414 * XXKey is either the second 256 bits of MSK or PSK.
415 * PMK-R0 = L(R0-Key-Data, 0, 256)
416 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
418 if (ssid_len
> WPA_MAX_SSID_LEN
|| r0kh_id_len
> FT_R0KH_ID_MAX_LEN
)
422 os_memcpy(pos
, ssid
, ssid_len
);
424 os_memcpy(pos
, mdid
, MOBILITY_DOMAIN_ID_LEN
);
425 pos
+= MOBILITY_DOMAIN_ID_LEN
;
426 *pos
++ = r0kh_id_len
;
427 os_memcpy(pos
, r0kh_id
, r0kh_id_len
);
429 os_memcpy(pos
, s0kh_id
, ETH_ALEN
);
432 sha256_prf(xxkey
, xxkey_len
, "FT-R0", buf
, pos
- buf
,
433 r0_key_data
, sizeof(r0_key_data
));
434 os_memcpy(pmk_r0
, r0_key_data
, PMK_LEN
);
437 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
439 addr
[0] = (const u8
*) "FT-R0N";
441 addr
[1] = r0_key_data
+ PMK_LEN
;
444 sha256_vector(2, addr
, len
, hash
);
445 os_memcpy(pmk_r0_name
, hash
, WPA_PMK_NAME_LEN
);
450 * wpa_derive_pmk_r1_name - Derive PMKR1Name
452 * IEEE 802.11r/D9.0 - 8.5.1.5.4
454 void wpa_derive_pmk_r1_name(const u8
*pmk_r0_name
, const u8
*r1kh_id
,
455 const u8
*s1kh_id
, u8
*pmk_r1_name
)
462 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
463 * R1KH-ID || S1KH-ID))
465 addr
[0] = (const u8
*) "FT-R1N";
467 addr
[1] = pmk_r0_name
;
468 len
[1] = WPA_PMK_NAME_LEN
;
470 len
[2] = FT_R1KH_ID_LEN
;
474 sha256_vector(4, addr
, len
, hash
);
475 os_memcpy(pmk_r1_name
, hash
, WPA_PMK_NAME_LEN
);
480 * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
482 * IEEE 802.11r/D9.0 - 8.5.1.5.4
484 void wpa_derive_pmk_r1(const u8
*pmk_r0
, const u8
*pmk_r0_name
,
485 const u8
*r1kh_id
, const u8
*s1kh_id
,
486 u8
*pmk_r1
, u8
*pmk_r1_name
)
488 u8 buf
[FT_R1KH_ID_LEN
+ ETH_ALEN
];
491 /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
493 os_memcpy(pos
, r1kh_id
, FT_R1KH_ID_LEN
);
494 pos
+= FT_R1KH_ID_LEN
;
495 os_memcpy(pos
, s1kh_id
, ETH_ALEN
);
498 sha256_prf(pmk_r0
, PMK_LEN
, "FT-R1", buf
, pos
- buf
, pmk_r1
, PMK_LEN
);
500 wpa_derive_pmk_r1_name(pmk_r0_name
, r1kh_id
, s1kh_id
, pmk_r1_name
);
505 * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
507 * IEEE 802.11r/D9.0 - 8.5.1.5.5
509 void wpa_pmk_r1_to_ptk(const u8
*pmk_r1
, const u8
*snonce
, const u8
*anonce
,
510 const u8
*sta_addr
, const u8
*bssid
,
511 const u8
*pmk_r1_name
,
512 u8
*ptk
, size_t ptk_len
, u8
*ptk_name
)
514 u8 buf
[2 * WPA_NONCE_LEN
+ 2 * ETH_ALEN
];
520 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
524 os_memcpy(pos
, snonce
, WPA_NONCE_LEN
);
525 pos
+= WPA_NONCE_LEN
;
526 os_memcpy(pos
, anonce
, WPA_NONCE_LEN
);
527 pos
+= WPA_NONCE_LEN
;
528 os_memcpy(pos
, bssid
, ETH_ALEN
);
530 os_memcpy(pos
, sta_addr
, ETH_ALEN
);
533 sha256_prf(pmk_r1
, PMK_LEN
, "FT-PTK", buf
, pos
- buf
, ptk
, ptk_len
);
536 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
537 * ANonce || BSSID || STA-ADDR))
539 addr
[0] = pmk_r1_name
;
540 len
[0] = WPA_PMK_NAME_LEN
;
541 addr
[1] = (const u8
*) "FT-PTKN";
544 len
[2] = WPA_NONCE_LEN
;
546 len
[3] = WPA_NONCE_LEN
;
552 sha256_vector(6, addr
, len
, hash
);
553 os_memcpy(ptk_name
, hash
, WPA_PMK_NAME_LEN
);
556 #endif /* CONFIG_IEEE80211R */