wpa_common.c revision 209158
1189251Ssam/*
2189251Ssam * WPA/RSN - Shared functions for supplicant and authenticator
3189251Ssam * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "common.h"
18189251Ssam#include "md5.h"
19189251Ssam#include "sha1.h"
20189251Ssam#include "sha256.h"
21189251Ssam#include "aes_wrap.h"
22189251Ssam#include "crypto.h"
23189251Ssam#include "ieee802_11_defs.h"
24189251Ssam#include "defs.h"
25189251Ssam#include "wpa_common.h"
26189251Ssam
27189251Ssam
28189251Ssam/**
29189251Ssam * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
30189251Ssam * @key: EAPOL-Key Key Confirmation Key (KCK)
31189251Ssam * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
32189251Ssam * @buf: Pointer to the beginning of the EAPOL header (version field)
33189251Ssam * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
34189251Ssam * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
35189251Ssam * Returns: 0 on success, -1 on failure
36189251Ssam *
37189251Ssam * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
38189251Ssam * to be cleared (all zeroes) when calling this function.
39189251Ssam *
40189251Ssam * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
41189251Ssam * description of the Key MIC calculation. It includes packet data from the
42189251Ssam * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
43189251Ssam * happened during final editing of the standard and the correct behavior is
44189251Ssam * defined in the last draft (IEEE 802.11i/D10).
45189251Ssam */
46189251Ssamint wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
47189251Ssam		      u8 *mic)
48189251Ssam{
49189251Ssam	u8 hash[SHA1_MAC_LEN];
50189251Ssam
51189251Ssam	switch (ver) {
52189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
53189251Ssam		hmac_md5(key, 16, buf, len, mic);
54189251Ssam		break;
55189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
56189251Ssam		hmac_sha1(key, 16, buf, len, hash);
57189251Ssam		os_memcpy(mic, hash, MD5_MAC_LEN);
58189251Ssam		break;
59209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
60189251Ssam	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
61189251Ssam		return omac1_aes_128(key, buf, len, mic);
62209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
63189251Ssam	default:
64189251Ssam		return -1;
65189251Ssam	}
66189251Ssam
67189251Ssam	return 0;
68189251Ssam}
69189251Ssam
70189251Ssam
71189251Ssam/**
72189251Ssam * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
73189251Ssam * @pmk: Pairwise master key
74189251Ssam * @pmk_len: Length of PMK
75189251Ssam * @label: Label to use in derivation
76189251Ssam * @addr1: AA or SA
77189251Ssam * @addr2: SA or AA
78189251Ssam * @nonce1: ANonce or SNonce
79189251Ssam * @nonce2: SNonce or ANonce
80189251Ssam * @ptk: Buffer for pairwise transient key
81189251Ssam * @ptk_len: Length of PTK
82189251Ssam * @use_sha256: Whether to use SHA256-based KDF
83189251Ssam *
84189251Ssam * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
85189251Ssam * PTK = PRF-X(PMK, "Pairwise key expansion",
86189251Ssam *             Min(AA, SA) || Max(AA, SA) ||
87189251Ssam *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
88189251Ssam *
89189251Ssam * STK = PRF-X(SMK, "Peer key expansion",
90189251Ssam *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
91189251Ssam *             Min(INonce, PNonce) || Max(INonce, PNonce))
92189251Ssam */
93189251Ssamvoid wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
94189251Ssam		    const u8 *addr1, const u8 *addr2,
95189251Ssam		    const u8 *nonce1, const u8 *nonce2,
96189251Ssam		    u8 *ptk, size_t ptk_len, int use_sha256)
97189251Ssam{
98189251Ssam	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
99189251Ssam
100189251Ssam	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
101189251Ssam		os_memcpy(data, addr1, ETH_ALEN);
102189251Ssam		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
103189251Ssam	} else {
104189251Ssam		os_memcpy(data, addr2, ETH_ALEN);
105189251Ssam		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
106189251Ssam	}
107189251Ssam
108189251Ssam	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
109189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
110189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
111189251Ssam			  WPA_NONCE_LEN);
112189251Ssam	} else {
113189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
114189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
115189251Ssam			  WPA_NONCE_LEN);
116189251Ssam	}
117189251Ssam
118189251Ssam#ifdef CONFIG_IEEE80211W
119189251Ssam	if (use_sha256)
120189251Ssam		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
121189251Ssam			   ptk, ptk_len);
122189251Ssam	else
123189251Ssam#endif /* CONFIG_IEEE80211W */
124189251Ssam		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
125189251Ssam			 ptk_len);
126189251Ssam
127189251Ssam	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
128189251Ssam		   MAC2STR(addr1), MAC2STR(addr2));
129189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
130189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
131189251Ssam}
132189251Ssam
133189251Ssam
134189251Ssam#ifdef CONFIG_IEEE80211R
135189251Ssamint wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
136189251Ssam	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
137189251Ssam	       const u8 *ftie, size_t ftie_len,
138189251Ssam	       const u8 *rsnie, size_t rsnie_len,
139189251Ssam	       const u8 *ric, size_t ric_len, u8 *mic)
140189251Ssam{
141189251Ssam	u8 *buf, *pos;
142189251Ssam	size_t buf_len;
143189251Ssam
144189251Ssam	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
145189251Ssam	buf = os_malloc(buf_len);
146189251Ssam	if (buf == NULL)
147189251Ssam		return -1;
148189251Ssam
149189251Ssam	pos = buf;
150189251Ssam	os_memcpy(pos, sta_addr, ETH_ALEN);
151189251Ssam	pos += ETH_ALEN;
152189251Ssam	os_memcpy(pos, ap_addr, ETH_ALEN);
153189251Ssam	pos += ETH_ALEN;
154189251Ssam	*pos++ = transaction_seqnum;
155189251Ssam	if (rsnie) {
156189251Ssam		os_memcpy(pos, rsnie, rsnie_len);
157189251Ssam		pos += rsnie_len;
158189251Ssam	}
159189251Ssam	if (mdie) {
160189251Ssam		os_memcpy(pos, mdie, mdie_len);
161189251Ssam		pos += mdie_len;
162189251Ssam	}
163189251Ssam	if (ftie) {
164189251Ssam		struct rsn_ftie *_ftie;
165189251Ssam		os_memcpy(pos, ftie, ftie_len);
166189251Ssam		if (ftie_len < 2 + sizeof(*_ftie)) {
167189251Ssam			os_free(buf);
168189251Ssam			return -1;
169189251Ssam		}
170189251Ssam		_ftie = (struct rsn_ftie *) (pos + 2);
171189251Ssam		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
172189251Ssam		pos += ftie_len;
173189251Ssam	}
174189251Ssam	if (ric) {
175189251Ssam		os_memcpy(pos, ric, ric_len);
176189251Ssam		pos += ric_len;
177189251Ssam	}
178189251Ssam
179189251Ssam	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
180189251Ssam	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
181189251Ssam		os_free(buf);
182189251Ssam		return -1;
183189251Ssam	}
184189251Ssam
185189251Ssam	os_free(buf);
186189251Ssam
187189251Ssam	return 0;
188189251Ssam}
189189251Ssam#endif /* CONFIG_IEEE80211R */
190189251Ssam
191189251Ssam
192189251Ssam#ifndef CONFIG_NO_WPA2
193189251Ssamstatic int rsn_selector_to_bitfield(const u8 *s)
194189251Ssam{
195189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
196189251Ssam		return WPA_CIPHER_NONE;
197189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
198189251Ssam		return WPA_CIPHER_WEP40;
199189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
200189251Ssam		return WPA_CIPHER_TKIP;
201189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
202189251Ssam		return WPA_CIPHER_CCMP;
203189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
204189251Ssam		return WPA_CIPHER_WEP104;
205189251Ssam#ifdef CONFIG_IEEE80211W
206189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
207189251Ssam		return WPA_CIPHER_AES_128_CMAC;
208189251Ssam#endif /* CONFIG_IEEE80211W */
209189251Ssam	return 0;
210189251Ssam}
211189251Ssam
212189251Ssam
213189251Ssamstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
214189251Ssam{
215189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
216189251Ssam		return WPA_KEY_MGMT_IEEE8021X;
217189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
218189251Ssam		return WPA_KEY_MGMT_PSK;
219189251Ssam#ifdef CONFIG_IEEE80211R
220189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
221189251Ssam		return WPA_KEY_MGMT_FT_IEEE8021X;
222189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
223189251Ssam		return WPA_KEY_MGMT_FT_PSK;
224189251Ssam#endif /* CONFIG_IEEE80211R */
225189251Ssam#ifdef CONFIG_IEEE80211W
226189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
227189251Ssam		return WPA_KEY_MGMT_IEEE8021X_SHA256;
228189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
229189251Ssam		return WPA_KEY_MGMT_PSK_SHA256;
230189251Ssam#endif /* CONFIG_IEEE80211W */
231189251Ssam	return 0;
232189251Ssam}
233189251Ssam#endif /* CONFIG_NO_WPA2 */
234189251Ssam
235189251Ssam
236189251Ssam/**
237189251Ssam * wpa_parse_wpa_ie_rsn - Parse RSN IE
238189251Ssam * @rsn_ie: Buffer containing RSN IE
239189251Ssam * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
240189251Ssam * @data: Pointer to structure that will be filled in with parsed data
241189251Ssam * Returns: 0 on success, <0 on failure
242189251Ssam */
243189251Ssamint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
244189251Ssam			 struct wpa_ie_data *data)
245189251Ssam{
246189251Ssam#ifndef CONFIG_NO_WPA2
247189251Ssam	const struct rsn_ie_hdr *hdr;
248189251Ssam	const u8 *pos;
249189251Ssam	int left;
250189251Ssam	int i, count;
251189251Ssam
252189251Ssam	os_memset(data, 0, sizeof(*data));
253189251Ssam	data->proto = WPA_PROTO_RSN;
254189251Ssam	data->pairwise_cipher = WPA_CIPHER_CCMP;
255189251Ssam	data->group_cipher = WPA_CIPHER_CCMP;
256189251Ssam	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
257189251Ssam	data->capabilities = 0;
258189251Ssam	data->pmkid = NULL;
259189251Ssam	data->num_pmkid = 0;
260189251Ssam#ifdef CONFIG_IEEE80211W
261189251Ssam	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
262189251Ssam#else /* CONFIG_IEEE80211W */
263189251Ssam	data->mgmt_group_cipher = 0;
264189251Ssam#endif /* CONFIG_IEEE80211W */
265189251Ssam
266189251Ssam	if (rsn_ie_len == 0) {
267189251Ssam		/* No RSN IE - fail silently */
268189251Ssam		return -1;
269189251Ssam	}
270189251Ssam
271189251Ssam	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
272189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
273189251Ssam			   __func__, (unsigned long) rsn_ie_len);
274189251Ssam		return -1;
275189251Ssam	}
276189251Ssam
277189251Ssam	hdr = (const struct rsn_ie_hdr *) rsn_ie;
278189251Ssam
279189251Ssam	if (hdr->elem_id != WLAN_EID_RSN ||
280189251Ssam	    hdr->len != rsn_ie_len - 2 ||
281189251Ssam	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
282189251Ssam		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
283189251Ssam			   __func__);
284189251Ssam		return -2;
285189251Ssam	}
286189251Ssam
287189251Ssam	pos = (const u8 *) (hdr + 1);
288189251Ssam	left = rsn_ie_len - sizeof(*hdr);
289189251Ssam
290189251Ssam	if (left >= RSN_SELECTOR_LEN) {
291189251Ssam		data->group_cipher = rsn_selector_to_bitfield(pos);
292189251Ssam#ifdef CONFIG_IEEE80211W
293189251Ssam		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
294189251Ssam			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
295189251Ssam				   "cipher", __func__);
296189251Ssam			return -1;
297189251Ssam		}
298189251Ssam#endif /* CONFIG_IEEE80211W */
299189251Ssam		pos += RSN_SELECTOR_LEN;
300189251Ssam		left -= RSN_SELECTOR_LEN;
301189251Ssam	} else if (left > 0) {
302189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
303189251Ssam			   __func__, left);
304189251Ssam		return -3;
305189251Ssam	}
306189251Ssam
307189251Ssam	if (left >= 2) {
308189251Ssam		data->pairwise_cipher = 0;
309189251Ssam		count = WPA_GET_LE16(pos);
310189251Ssam		pos += 2;
311189251Ssam		left -= 2;
312189251Ssam		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
313189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
314189251Ssam				   "count %u left %u", __func__, count, left);
315189251Ssam			return -4;
316189251Ssam		}
317189251Ssam		for (i = 0; i < count; i++) {
318189251Ssam			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
319189251Ssam			pos += RSN_SELECTOR_LEN;
320189251Ssam			left -= RSN_SELECTOR_LEN;
321189251Ssam		}
322189251Ssam#ifdef CONFIG_IEEE80211W
323189251Ssam		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
324189251Ssam			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
325189251Ssam				   "pairwise cipher", __func__);
326189251Ssam			return -1;
327189251Ssam		}
328189251Ssam#endif /* CONFIG_IEEE80211W */
329189251Ssam	} else if (left == 1) {
330189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
331189251Ssam			   __func__);
332189251Ssam		return -5;
333189251Ssam	}
334189251Ssam
335189251Ssam	if (left >= 2) {
336189251Ssam		data->key_mgmt = 0;
337189251Ssam		count = WPA_GET_LE16(pos);
338189251Ssam		pos += 2;
339189251Ssam		left -= 2;
340189251Ssam		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
341189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
342189251Ssam				   "count %u left %u", __func__, count, left);
343189251Ssam			return -6;
344189251Ssam		}
345189251Ssam		for (i = 0; i < count; i++) {
346189251Ssam			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
347189251Ssam			pos += RSN_SELECTOR_LEN;
348189251Ssam			left -= RSN_SELECTOR_LEN;
349189251Ssam		}
350189251Ssam	} else if (left == 1) {
351189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
352189251Ssam			   __func__);
353189251Ssam		return -7;
354189251Ssam	}
355189251Ssam
356189251Ssam	if (left >= 2) {
357189251Ssam		data->capabilities = WPA_GET_LE16(pos);
358189251Ssam		pos += 2;
359189251Ssam		left -= 2;
360189251Ssam	}
361189251Ssam
362189251Ssam	if (left >= 2) {
363189251Ssam		data->num_pmkid = WPA_GET_LE16(pos);
364189251Ssam		pos += 2;
365189251Ssam		left -= 2;
366189251Ssam		if (left < (int) data->num_pmkid * PMKID_LEN) {
367189251Ssam			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
368189251Ssam				   "(num_pmkid=%lu left=%d)",
369189251Ssam				   __func__, (unsigned long) data->num_pmkid,
370189251Ssam				   left);
371189251Ssam			data->num_pmkid = 0;
372189251Ssam			return -9;
373189251Ssam		} else {
374189251Ssam			data->pmkid = pos;
375189251Ssam			pos += data->num_pmkid * PMKID_LEN;
376189251Ssam			left -= data->num_pmkid * PMKID_LEN;
377189251Ssam		}
378189251Ssam	}
379189251Ssam
380189251Ssam#ifdef CONFIG_IEEE80211W
381189251Ssam	if (left >= 4) {
382189251Ssam		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
383189251Ssam		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
384189251Ssam			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
385189251Ssam				   "group cipher 0x%x", __func__,
386189251Ssam				   data->mgmt_group_cipher);
387189251Ssam			return -10;
388189251Ssam		}
389189251Ssam		pos += RSN_SELECTOR_LEN;
390189251Ssam		left -= RSN_SELECTOR_LEN;
391189251Ssam	}
392189251Ssam#endif /* CONFIG_IEEE80211W */
393189251Ssam
394189251Ssam	if (left > 0) {
395189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
396189251Ssam			   __func__, left);
397189251Ssam	}
398189251Ssam
399189251Ssam	return 0;
400189251Ssam#else /* CONFIG_NO_WPA2 */
401189251Ssam	return -1;
402189251Ssam#endif /* CONFIG_NO_WPA2 */
403189251Ssam}
404189251Ssam
405189251Ssam
406189251Ssam#ifdef CONFIG_IEEE80211R
407189251Ssam
408189251Ssam/**
409189251Ssam * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
410189251Ssam *
411189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.3
412189251Ssam */
413189251Ssamvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
414189251Ssam		       const u8 *ssid, size_t ssid_len,
415189251Ssam		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
416189251Ssam		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
417189251Ssam{
418189251Ssam	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
419189251Ssam	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
420189251Ssam	u8 *pos, r0_key_data[48], hash[32];
421189251Ssam	const u8 *addr[2];
422189251Ssam	size_t len[2];
423189251Ssam
424189251Ssam	/*
425189251Ssam	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
426189251Ssam	 *                       SSIDlength || SSID || MDID || R0KHlength ||
427189251Ssam	 *                       R0KH-ID || S0KH-ID)
428189251Ssam	 * XXKey is either the second 256 bits of MSK or PSK.
429189251Ssam	 * PMK-R0 = L(R0-Key-Data, 0, 256)
430189251Ssam	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
431189251Ssam	 */
432189251Ssam	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
433189251Ssam		return;
434189251Ssam	pos = buf;
435189251Ssam	*pos++ = ssid_len;
436189251Ssam	os_memcpy(pos, ssid, ssid_len);
437189251Ssam	pos += ssid_len;
438189251Ssam	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
439189251Ssam	pos += MOBILITY_DOMAIN_ID_LEN;
440189251Ssam	*pos++ = r0kh_id_len;
441189251Ssam	os_memcpy(pos, r0kh_id, r0kh_id_len);
442189251Ssam	pos += r0kh_id_len;
443189251Ssam	os_memcpy(pos, s0kh_id, ETH_ALEN);
444189251Ssam	pos += ETH_ALEN;
445189251Ssam
446189251Ssam	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
447189251Ssam		   r0_key_data, sizeof(r0_key_data));
448189251Ssam	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
449189251Ssam
450189251Ssam	/*
451189251Ssam	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
452189251Ssam	 */
453189251Ssam	addr[0] = (const u8 *) "FT-R0N";
454189251Ssam	len[0] = 6;
455189251Ssam	addr[1] = r0_key_data + PMK_LEN;
456189251Ssam	len[1] = 16;
457189251Ssam
458189251Ssam	sha256_vector(2, addr, len, hash);
459189251Ssam	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
460189251Ssam}
461189251Ssam
462189251Ssam
463189251Ssam/**
464189251Ssam * wpa_derive_pmk_r1_name - Derive PMKR1Name
465189251Ssam *
466189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
467189251Ssam */
468189251Ssamvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
469189251Ssam			    const u8 *s1kh_id, u8 *pmk_r1_name)
470189251Ssam{
471189251Ssam	u8 hash[32];
472189251Ssam	const u8 *addr[4];
473189251Ssam	size_t len[4];
474189251Ssam
475189251Ssam	/*
476189251Ssam	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
477189251Ssam	 *                                  R1KH-ID || S1KH-ID))
478189251Ssam	 */
479189251Ssam	addr[0] = (const u8 *) "FT-R1N";
480189251Ssam	len[0] = 6;
481189251Ssam	addr[1] = pmk_r0_name;
482189251Ssam	len[1] = WPA_PMK_NAME_LEN;
483189251Ssam	addr[2] = r1kh_id;
484189251Ssam	len[2] = FT_R1KH_ID_LEN;
485189251Ssam	addr[3] = s1kh_id;
486189251Ssam	len[3] = ETH_ALEN;
487189251Ssam
488189251Ssam	sha256_vector(4, addr, len, hash);
489189251Ssam	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
490189251Ssam}
491189251Ssam
492189251Ssam
493189251Ssam/**
494189251Ssam * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
495189251Ssam *
496189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
497189251Ssam */
498189251Ssamvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
499189251Ssam		       const u8 *r1kh_id, const u8 *s1kh_id,
500189251Ssam		       u8 *pmk_r1, u8 *pmk_r1_name)
501189251Ssam{
502189251Ssam	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
503189251Ssam	u8 *pos;
504189251Ssam
505189251Ssam	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
506189251Ssam	pos = buf;
507189251Ssam	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
508189251Ssam	pos += FT_R1KH_ID_LEN;
509189251Ssam	os_memcpy(pos, s1kh_id, ETH_ALEN);
510189251Ssam	pos += ETH_ALEN;
511189251Ssam
512189251Ssam	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
513189251Ssam
514189251Ssam	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
515189251Ssam}
516189251Ssam
517189251Ssam
518189251Ssam/**
519189251Ssam * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
520189251Ssam *
521189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.5
522189251Ssam */
523189251Ssamvoid wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
524189251Ssam		       const u8 *sta_addr, const u8 *bssid,
525189251Ssam		       const u8 *pmk_r1_name,
526189251Ssam		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
527189251Ssam{
528189251Ssam	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
529189251Ssam	u8 *pos, hash[32];
530189251Ssam	const u8 *addr[6];
531189251Ssam	size_t len[6];
532189251Ssam
533189251Ssam	/*
534189251Ssam	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
535189251Ssam	 *                  BSSID || STA-ADDR)
536189251Ssam	 */
537189251Ssam	pos = buf;
538189251Ssam	os_memcpy(pos, snonce, WPA_NONCE_LEN);
539189251Ssam	pos += WPA_NONCE_LEN;
540189251Ssam	os_memcpy(pos, anonce, WPA_NONCE_LEN);
541189251Ssam	pos += WPA_NONCE_LEN;
542189251Ssam	os_memcpy(pos, bssid, ETH_ALEN);
543189251Ssam	pos += ETH_ALEN;
544189251Ssam	os_memcpy(pos, sta_addr, ETH_ALEN);
545189251Ssam	pos += ETH_ALEN;
546189251Ssam
547189251Ssam	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
548189251Ssam
549189251Ssam	/*
550189251Ssam	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
551189251Ssam	 *                                ANonce || BSSID || STA-ADDR))
552189251Ssam	 */
553189251Ssam	addr[0] = pmk_r1_name;
554189251Ssam	len[0] = WPA_PMK_NAME_LEN;
555189251Ssam	addr[1] = (const u8 *) "FT-PTKN";
556189251Ssam	len[1] = 7;
557189251Ssam	addr[2] = snonce;
558189251Ssam	len[2] = WPA_NONCE_LEN;
559189251Ssam	addr[3] = anonce;
560189251Ssam	len[3] = WPA_NONCE_LEN;
561189251Ssam	addr[4] = bssid;
562189251Ssam	len[4] = ETH_ALEN;
563189251Ssam	addr[5] = sta_addr;
564189251Ssam	len[5] = ETH_ALEN;
565189251Ssam
566189251Ssam	sha256_vector(6, addr, len, hash);
567189251Ssam	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
568189251Ssam}
569189251Ssam
570189251Ssam#endif /* CONFIG_IEEE80211R */
571