wpa_common.c revision 252726
1189251Ssam/*
2189251Ssam * WPA/RSN - Shared functions for supplicant and authenticator
3189251Ssam * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/md5.h"
13214734Srpaulo#include "crypto/sha1.h"
14214734Srpaulo#include "crypto/sha256.h"
15214734Srpaulo#include "crypto/aes_wrap.h"
16214734Srpaulo#include "crypto/crypto.h"
17189251Ssam#include "ieee802_11_defs.h"
18189251Ssam#include "defs.h"
19189251Ssam#include "wpa_common.h"
20189251Ssam
21189251Ssam
22189251Ssam/**
23189251Ssam * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
24189251Ssam * @key: EAPOL-Key Key Confirmation Key (KCK)
25189251Ssam * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
26189251Ssam * @buf: Pointer to the beginning of the EAPOL header (version field)
27189251Ssam * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
28189251Ssam * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
29189251Ssam * Returns: 0 on success, -1 on failure
30189251Ssam *
31189251Ssam * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
32189251Ssam * to be cleared (all zeroes) when calling this function.
33189251Ssam *
34189251Ssam * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
35189251Ssam * description of the Key MIC calculation. It includes packet data from the
36189251Ssam * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
37189251Ssam * happened during final editing of the standard and the correct behavior is
38189251Ssam * defined in the last draft (IEEE 802.11i/D10).
39189251Ssam */
40189251Ssamint wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
41189251Ssam		      u8 *mic)
42189251Ssam{
43189251Ssam	u8 hash[SHA1_MAC_LEN];
44189251Ssam
45189251Ssam	switch (ver) {
46252726Srpaulo#ifndef CONFIG_FIPS
47189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
48214734Srpaulo		return hmac_md5(key, 16, buf, len, mic);
49252726Srpaulo#endif /* CONFIG_FIPS */
50189251Ssam	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
51214734Srpaulo		if (hmac_sha1(key, 16, buf, len, hash))
52214734Srpaulo			return -1;
53189251Ssam		os_memcpy(mic, hash, MD5_MAC_LEN);
54189251Ssam		break;
55209158Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
56189251Ssam	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
57189251Ssam		return omac1_aes_128(key, buf, len, mic);
58209158Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
59189251Ssam	default:
60189251Ssam		return -1;
61189251Ssam	}
62189251Ssam
63189251Ssam	return 0;
64189251Ssam}
65189251Ssam
66189251Ssam
67189251Ssam/**
68189251Ssam * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
69189251Ssam * @pmk: Pairwise master key
70189251Ssam * @pmk_len: Length of PMK
71189251Ssam * @label: Label to use in derivation
72189251Ssam * @addr1: AA or SA
73189251Ssam * @addr2: SA or AA
74189251Ssam * @nonce1: ANonce or SNonce
75189251Ssam * @nonce2: SNonce or ANonce
76189251Ssam * @ptk: Buffer for pairwise transient key
77189251Ssam * @ptk_len: Length of PTK
78189251Ssam * @use_sha256: Whether to use SHA256-based KDF
79189251Ssam *
80189251Ssam * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
81189251Ssam * PTK = PRF-X(PMK, "Pairwise key expansion",
82189251Ssam *             Min(AA, SA) || Max(AA, SA) ||
83189251Ssam *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
84189251Ssam *
85189251Ssam * STK = PRF-X(SMK, "Peer key expansion",
86189251Ssam *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
87189251Ssam *             Min(INonce, PNonce) || Max(INonce, PNonce))
88189251Ssam */
89189251Ssamvoid wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
90189251Ssam		    const u8 *addr1, const u8 *addr2,
91189251Ssam		    const u8 *nonce1, const u8 *nonce2,
92189251Ssam		    u8 *ptk, size_t ptk_len, int use_sha256)
93189251Ssam{
94189251Ssam	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
95189251Ssam
96189251Ssam	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
97189251Ssam		os_memcpy(data, addr1, ETH_ALEN);
98189251Ssam		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
99189251Ssam	} else {
100189251Ssam		os_memcpy(data, addr2, ETH_ALEN);
101189251Ssam		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
102189251Ssam	}
103189251Ssam
104189251Ssam	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
105189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
106189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
107189251Ssam			  WPA_NONCE_LEN);
108189251Ssam	} else {
109189251Ssam		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
110189251Ssam		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
111189251Ssam			  WPA_NONCE_LEN);
112189251Ssam	}
113189251Ssam
114189251Ssam#ifdef CONFIG_IEEE80211W
115189251Ssam	if (use_sha256)
116189251Ssam		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
117189251Ssam			   ptk, ptk_len);
118189251Ssam	else
119189251Ssam#endif /* CONFIG_IEEE80211W */
120189251Ssam		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
121189251Ssam			 ptk_len);
122189251Ssam
123189251Ssam	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
124189251Ssam		   MAC2STR(addr1), MAC2STR(addr2));
125252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
126252726Srpaulo	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
127189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
128189251Ssam	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
129189251Ssam}
130189251Ssam
131189251Ssam
132189251Ssam#ifdef CONFIG_IEEE80211R
133189251Ssamint wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
134189251Ssam	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
135189251Ssam	       const u8 *ftie, size_t ftie_len,
136189251Ssam	       const u8 *rsnie, size_t rsnie_len,
137189251Ssam	       const u8 *ric, size_t ric_len, u8 *mic)
138189251Ssam{
139189251Ssam	u8 *buf, *pos;
140189251Ssam	size_t buf_len;
141189251Ssam
142189251Ssam	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
143189251Ssam	buf = os_malloc(buf_len);
144189251Ssam	if (buf == NULL)
145189251Ssam		return -1;
146189251Ssam
147189251Ssam	pos = buf;
148189251Ssam	os_memcpy(pos, sta_addr, ETH_ALEN);
149189251Ssam	pos += ETH_ALEN;
150189251Ssam	os_memcpy(pos, ap_addr, ETH_ALEN);
151189251Ssam	pos += ETH_ALEN;
152189251Ssam	*pos++ = transaction_seqnum;
153189251Ssam	if (rsnie) {
154189251Ssam		os_memcpy(pos, rsnie, rsnie_len);
155189251Ssam		pos += rsnie_len;
156189251Ssam	}
157189251Ssam	if (mdie) {
158189251Ssam		os_memcpy(pos, mdie, mdie_len);
159189251Ssam		pos += mdie_len;
160189251Ssam	}
161189251Ssam	if (ftie) {
162189251Ssam		struct rsn_ftie *_ftie;
163189251Ssam		os_memcpy(pos, ftie, ftie_len);
164189251Ssam		if (ftie_len < 2 + sizeof(*_ftie)) {
165189251Ssam			os_free(buf);
166189251Ssam			return -1;
167189251Ssam		}
168189251Ssam		_ftie = (struct rsn_ftie *) (pos + 2);
169189251Ssam		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
170189251Ssam		pos += ftie_len;
171189251Ssam	}
172189251Ssam	if (ric) {
173189251Ssam		os_memcpy(pos, ric, ric_len);
174189251Ssam		pos += ric_len;
175189251Ssam	}
176189251Ssam
177189251Ssam	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
178189251Ssam	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
179189251Ssam		os_free(buf);
180189251Ssam		return -1;
181189251Ssam	}
182189251Ssam
183189251Ssam	os_free(buf);
184189251Ssam
185189251Ssam	return 0;
186189251Ssam}
187252726Srpaulo
188252726Srpaulo
189252726Srpaulostatic int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
190252726Srpaulo			     struct wpa_ft_ies *parse)
191252726Srpaulo{
192252726Srpaulo	const u8 *end, *pos;
193252726Srpaulo
194252726Srpaulo	parse->ftie = ie;
195252726Srpaulo	parse->ftie_len = ie_len;
196252726Srpaulo
197252726Srpaulo	pos = ie + sizeof(struct rsn_ftie);
198252726Srpaulo	end = ie + ie_len;
199252726Srpaulo
200252726Srpaulo	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
201252726Srpaulo		switch (pos[0]) {
202252726Srpaulo		case FTIE_SUBELEM_R1KH_ID:
203252726Srpaulo			if (pos[1] != FT_R1KH_ID_LEN) {
204252726Srpaulo				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
205252726Srpaulo					   "length in FTIE: %d", pos[1]);
206252726Srpaulo				return -1;
207252726Srpaulo			}
208252726Srpaulo			parse->r1kh_id = pos + 2;
209252726Srpaulo			break;
210252726Srpaulo		case FTIE_SUBELEM_GTK:
211252726Srpaulo			parse->gtk = pos + 2;
212252726Srpaulo			parse->gtk_len = pos[1];
213252726Srpaulo			break;
214252726Srpaulo		case FTIE_SUBELEM_R0KH_ID:
215252726Srpaulo			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
216252726Srpaulo				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
217252726Srpaulo					   "length in FTIE: %d", pos[1]);
218252726Srpaulo				return -1;
219252726Srpaulo			}
220252726Srpaulo			parse->r0kh_id = pos + 2;
221252726Srpaulo			parse->r0kh_id_len = pos[1];
222252726Srpaulo			break;
223252726Srpaulo#ifdef CONFIG_IEEE80211W
224252726Srpaulo		case FTIE_SUBELEM_IGTK:
225252726Srpaulo			parse->igtk = pos + 2;
226252726Srpaulo			parse->igtk_len = pos[1];
227252726Srpaulo			break;
228252726Srpaulo#endif /* CONFIG_IEEE80211W */
229252726Srpaulo		}
230252726Srpaulo
231252726Srpaulo		pos += 2 + pos[1];
232252726Srpaulo	}
233252726Srpaulo
234252726Srpaulo	return 0;
235252726Srpaulo}
236252726Srpaulo
237252726Srpaulo
238252726Srpauloint wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
239252726Srpaulo		     struct wpa_ft_ies *parse)
240252726Srpaulo{
241252726Srpaulo	const u8 *end, *pos;
242252726Srpaulo	struct wpa_ie_data data;
243252726Srpaulo	int ret;
244252726Srpaulo	const struct rsn_ftie *ftie;
245252726Srpaulo	int prot_ie_count = 0;
246252726Srpaulo
247252726Srpaulo	os_memset(parse, 0, sizeof(*parse));
248252726Srpaulo	if (ies == NULL)
249252726Srpaulo		return 0;
250252726Srpaulo
251252726Srpaulo	pos = ies;
252252726Srpaulo	end = ies + ies_len;
253252726Srpaulo	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
254252726Srpaulo		switch (pos[0]) {
255252726Srpaulo		case WLAN_EID_RSN:
256252726Srpaulo			parse->rsn = pos + 2;
257252726Srpaulo			parse->rsn_len = pos[1];
258252726Srpaulo			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
259252726Srpaulo						   parse->rsn_len + 2,
260252726Srpaulo						   &data);
261252726Srpaulo			if (ret < 0) {
262252726Srpaulo				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
263252726Srpaulo					   "RSN IE: %d", ret);
264252726Srpaulo				return -1;
265252726Srpaulo			}
266252726Srpaulo			if (data.num_pmkid == 1 && data.pmkid)
267252726Srpaulo				parse->rsn_pmkid = data.pmkid;
268252726Srpaulo			break;
269252726Srpaulo		case WLAN_EID_MOBILITY_DOMAIN:
270252726Srpaulo			parse->mdie = pos + 2;
271252726Srpaulo			parse->mdie_len = pos[1];
272252726Srpaulo			break;
273252726Srpaulo		case WLAN_EID_FAST_BSS_TRANSITION:
274252726Srpaulo			if (pos[1] < sizeof(*ftie))
275252726Srpaulo				return -1;
276252726Srpaulo			ftie = (const struct rsn_ftie *) (pos + 2);
277252726Srpaulo			prot_ie_count = ftie->mic_control[1];
278252726Srpaulo			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
279252726Srpaulo				return -1;
280252726Srpaulo			break;
281252726Srpaulo		case WLAN_EID_TIMEOUT_INTERVAL:
282252726Srpaulo			parse->tie = pos + 2;
283252726Srpaulo			parse->tie_len = pos[1];
284252726Srpaulo			break;
285252726Srpaulo		case WLAN_EID_RIC_DATA:
286252726Srpaulo			if (parse->ric == NULL)
287252726Srpaulo				parse->ric = pos;
288252726Srpaulo			break;
289252726Srpaulo		}
290252726Srpaulo
291252726Srpaulo		pos += 2 + pos[1];
292252726Srpaulo	}
293252726Srpaulo
294252726Srpaulo	if (prot_ie_count == 0)
295252726Srpaulo		return 0; /* no MIC */
296252726Srpaulo
297252726Srpaulo	/*
298252726Srpaulo	 * Check that the protected IE count matches with IEs included in the
299252726Srpaulo	 * frame.
300252726Srpaulo	 */
301252726Srpaulo	if (parse->rsn)
302252726Srpaulo		prot_ie_count--;
303252726Srpaulo	if (parse->mdie)
304252726Srpaulo		prot_ie_count--;
305252726Srpaulo	if (parse->ftie)
306252726Srpaulo		prot_ie_count--;
307252726Srpaulo	if (prot_ie_count < 0) {
308252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
309252726Srpaulo			   "the protected IE count");
310252726Srpaulo		return -1;
311252726Srpaulo	}
312252726Srpaulo
313252726Srpaulo	if (prot_ie_count == 0 && parse->ric) {
314252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
315252726Srpaulo			   "included in protected IE count");
316252726Srpaulo		return -1;
317252726Srpaulo	}
318252726Srpaulo
319252726Srpaulo	/* Determine the end of the RIC IE(s) */
320252726Srpaulo	pos = parse->ric;
321252726Srpaulo	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
322252726Srpaulo	       prot_ie_count) {
323252726Srpaulo		prot_ie_count--;
324252726Srpaulo		pos += 2 + pos[1];
325252726Srpaulo	}
326252726Srpaulo	parse->ric_len = pos - parse->ric;
327252726Srpaulo	if (prot_ie_count) {
328252726Srpaulo		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
329252726Srpaulo			   "frame", (int) prot_ie_count);
330252726Srpaulo		return -1;
331252726Srpaulo	}
332252726Srpaulo
333252726Srpaulo	return 0;
334252726Srpaulo}
335189251Ssam#endif /* CONFIG_IEEE80211R */
336189251Ssam
337189251Ssam
338189251Ssam#ifndef CONFIG_NO_WPA2
339189251Ssamstatic int rsn_selector_to_bitfield(const u8 *s)
340189251Ssam{
341189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
342189251Ssam		return WPA_CIPHER_NONE;
343189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
344189251Ssam		return WPA_CIPHER_WEP40;
345189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
346189251Ssam		return WPA_CIPHER_TKIP;
347189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
348189251Ssam		return WPA_CIPHER_CCMP;
349189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
350189251Ssam		return WPA_CIPHER_WEP104;
351189251Ssam#ifdef CONFIG_IEEE80211W
352189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
353189251Ssam		return WPA_CIPHER_AES_128_CMAC;
354189251Ssam#endif /* CONFIG_IEEE80211W */
355252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
356252726Srpaulo		return WPA_CIPHER_GCMP;
357189251Ssam	return 0;
358189251Ssam}
359189251Ssam
360189251Ssam
361189251Ssamstatic int rsn_key_mgmt_to_bitfield(const u8 *s)
362189251Ssam{
363189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
364189251Ssam		return WPA_KEY_MGMT_IEEE8021X;
365189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
366189251Ssam		return WPA_KEY_MGMT_PSK;
367189251Ssam#ifdef CONFIG_IEEE80211R
368189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
369189251Ssam		return WPA_KEY_MGMT_FT_IEEE8021X;
370189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
371189251Ssam		return WPA_KEY_MGMT_FT_PSK;
372189251Ssam#endif /* CONFIG_IEEE80211R */
373189251Ssam#ifdef CONFIG_IEEE80211W
374189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
375189251Ssam		return WPA_KEY_MGMT_IEEE8021X_SHA256;
376189251Ssam	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
377189251Ssam		return WPA_KEY_MGMT_PSK_SHA256;
378189251Ssam#endif /* CONFIG_IEEE80211W */
379252726Srpaulo#ifdef CONFIG_SAE
380252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
381252726Srpaulo		return WPA_KEY_MGMT_SAE;
382252726Srpaulo	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
383252726Srpaulo		return WPA_KEY_MGMT_FT_SAE;
384252726Srpaulo#endif /* CONFIG_SAE */
385189251Ssam	return 0;
386189251Ssam}
387189251Ssam#endif /* CONFIG_NO_WPA2 */
388189251Ssam
389189251Ssam
390189251Ssam/**
391189251Ssam * wpa_parse_wpa_ie_rsn - Parse RSN IE
392189251Ssam * @rsn_ie: Buffer containing RSN IE
393189251Ssam * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
394189251Ssam * @data: Pointer to structure that will be filled in with parsed data
395189251Ssam * Returns: 0 on success, <0 on failure
396189251Ssam */
397189251Ssamint wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
398189251Ssam			 struct wpa_ie_data *data)
399189251Ssam{
400189251Ssam#ifndef CONFIG_NO_WPA2
401189251Ssam	const struct rsn_ie_hdr *hdr;
402189251Ssam	const u8 *pos;
403189251Ssam	int left;
404189251Ssam	int i, count;
405189251Ssam
406189251Ssam	os_memset(data, 0, sizeof(*data));
407189251Ssam	data->proto = WPA_PROTO_RSN;
408189251Ssam	data->pairwise_cipher = WPA_CIPHER_CCMP;
409189251Ssam	data->group_cipher = WPA_CIPHER_CCMP;
410189251Ssam	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
411189251Ssam	data->capabilities = 0;
412189251Ssam	data->pmkid = NULL;
413189251Ssam	data->num_pmkid = 0;
414189251Ssam#ifdef CONFIG_IEEE80211W
415189251Ssam	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
416189251Ssam#else /* CONFIG_IEEE80211W */
417189251Ssam	data->mgmt_group_cipher = 0;
418189251Ssam#endif /* CONFIG_IEEE80211W */
419189251Ssam
420189251Ssam	if (rsn_ie_len == 0) {
421189251Ssam		/* No RSN IE - fail silently */
422189251Ssam		return -1;
423189251Ssam	}
424189251Ssam
425189251Ssam	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
426189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
427189251Ssam			   __func__, (unsigned long) rsn_ie_len);
428189251Ssam		return -1;
429189251Ssam	}
430189251Ssam
431189251Ssam	hdr = (const struct rsn_ie_hdr *) rsn_ie;
432189251Ssam
433189251Ssam	if (hdr->elem_id != WLAN_EID_RSN ||
434189251Ssam	    hdr->len != rsn_ie_len - 2 ||
435189251Ssam	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
436189251Ssam		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
437189251Ssam			   __func__);
438189251Ssam		return -2;
439189251Ssam	}
440189251Ssam
441189251Ssam	pos = (const u8 *) (hdr + 1);
442189251Ssam	left = rsn_ie_len - sizeof(*hdr);
443189251Ssam
444189251Ssam	if (left >= RSN_SELECTOR_LEN) {
445189251Ssam		data->group_cipher = rsn_selector_to_bitfield(pos);
446189251Ssam#ifdef CONFIG_IEEE80211W
447189251Ssam		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
448189251Ssam			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
449189251Ssam				   "cipher", __func__);
450189251Ssam			return -1;
451189251Ssam		}
452189251Ssam#endif /* CONFIG_IEEE80211W */
453189251Ssam		pos += RSN_SELECTOR_LEN;
454189251Ssam		left -= RSN_SELECTOR_LEN;
455189251Ssam	} else if (left > 0) {
456189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
457189251Ssam			   __func__, left);
458189251Ssam		return -3;
459189251Ssam	}
460189251Ssam
461189251Ssam	if (left >= 2) {
462189251Ssam		data->pairwise_cipher = 0;
463189251Ssam		count = WPA_GET_LE16(pos);
464189251Ssam		pos += 2;
465189251Ssam		left -= 2;
466189251Ssam		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
467189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
468189251Ssam				   "count %u left %u", __func__, count, left);
469189251Ssam			return -4;
470189251Ssam		}
471189251Ssam		for (i = 0; i < count; i++) {
472189251Ssam			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
473189251Ssam			pos += RSN_SELECTOR_LEN;
474189251Ssam			left -= RSN_SELECTOR_LEN;
475189251Ssam		}
476189251Ssam#ifdef CONFIG_IEEE80211W
477189251Ssam		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
478189251Ssam			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
479189251Ssam				   "pairwise cipher", __func__);
480189251Ssam			return -1;
481189251Ssam		}
482189251Ssam#endif /* CONFIG_IEEE80211W */
483189251Ssam	} else if (left == 1) {
484189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
485189251Ssam			   __func__);
486189251Ssam		return -5;
487189251Ssam	}
488189251Ssam
489189251Ssam	if (left >= 2) {
490189251Ssam		data->key_mgmt = 0;
491189251Ssam		count = WPA_GET_LE16(pos);
492189251Ssam		pos += 2;
493189251Ssam		left -= 2;
494189251Ssam		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
495189251Ssam			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
496189251Ssam				   "count %u left %u", __func__, count, left);
497189251Ssam			return -6;
498189251Ssam		}
499189251Ssam		for (i = 0; i < count; i++) {
500189251Ssam			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
501189251Ssam			pos += RSN_SELECTOR_LEN;
502189251Ssam			left -= RSN_SELECTOR_LEN;
503189251Ssam		}
504189251Ssam	} else if (left == 1) {
505189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
506189251Ssam			   __func__);
507189251Ssam		return -7;
508189251Ssam	}
509189251Ssam
510189251Ssam	if (left >= 2) {
511189251Ssam		data->capabilities = WPA_GET_LE16(pos);
512189251Ssam		pos += 2;
513189251Ssam		left -= 2;
514189251Ssam	}
515189251Ssam
516189251Ssam	if (left >= 2) {
517189251Ssam		data->num_pmkid = WPA_GET_LE16(pos);
518189251Ssam		pos += 2;
519189251Ssam		left -= 2;
520189251Ssam		if (left < (int) data->num_pmkid * PMKID_LEN) {
521189251Ssam			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
522189251Ssam				   "(num_pmkid=%lu left=%d)",
523189251Ssam				   __func__, (unsigned long) data->num_pmkid,
524189251Ssam				   left);
525189251Ssam			data->num_pmkid = 0;
526189251Ssam			return -9;
527189251Ssam		} else {
528189251Ssam			data->pmkid = pos;
529189251Ssam			pos += data->num_pmkid * PMKID_LEN;
530189251Ssam			left -= data->num_pmkid * PMKID_LEN;
531189251Ssam		}
532189251Ssam	}
533189251Ssam
534189251Ssam#ifdef CONFIG_IEEE80211W
535189251Ssam	if (left >= 4) {
536189251Ssam		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
537189251Ssam		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
538189251Ssam			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
539189251Ssam				   "group cipher 0x%x", __func__,
540189251Ssam				   data->mgmt_group_cipher);
541189251Ssam			return -10;
542189251Ssam		}
543189251Ssam		pos += RSN_SELECTOR_LEN;
544189251Ssam		left -= RSN_SELECTOR_LEN;
545189251Ssam	}
546189251Ssam#endif /* CONFIG_IEEE80211W */
547189251Ssam
548189251Ssam	if (left > 0) {
549189251Ssam		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
550189251Ssam			   __func__, left);
551189251Ssam	}
552189251Ssam
553189251Ssam	return 0;
554189251Ssam#else /* CONFIG_NO_WPA2 */
555189251Ssam	return -1;
556189251Ssam#endif /* CONFIG_NO_WPA2 */
557189251Ssam}
558189251Ssam
559189251Ssam
560252726Srpaulostatic int wpa_selector_to_bitfield(const u8 *s)
561252726Srpaulo{
562252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
563252726Srpaulo		return WPA_CIPHER_NONE;
564252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
565252726Srpaulo		return WPA_CIPHER_WEP40;
566252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
567252726Srpaulo		return WPA_CIPHER_TKIP;
568252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
569252726Srpaulo		return WPA_CIPHER_CCMP;
570252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
571252726Srpaulo		return WPA_CIPHER_WEP104;
572252726Srpaulo	return 0;
573252726Srpaulo}
574252726Srpaulo
575252726Srpaulo
576252726Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s)
577252726Srpaulo{
578252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
579252726Srpaulo		return WPA_KEY_MGMT_IEEE8021X;
580252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
581252726Srpaulo		return WPA_KEY_MGMT_PSK;
582252726Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
583252726Srpaulo		return WPA_KEY_MGMT_WPA_NONE;
584252726Srpaulo	return 0;
585252726Srpaulo}
586252726Srpaulo
587252726Srpaulo
588252726Srpauloint wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
589252726Srpaulo			 struct wpa_ie_data *data)
590252726Srpaulo{
591252726Srpaulo	const struct wpa_ie_hdr *hdr;
592252726Srpaulo	const u8 *pos;
593252726Srpaulo	int left;
594252726Srpaulo	int i, count;
595252726Srpaulo
596252726Srpaulo	os_memset(data, 0, sizeof(*data));
597252726Srpaulo	data->proto = WPA_PROTO_WPA;
598252726Srpaulo	data->pairwise_cipher = WPA_CIPHER_TKIP;
599252726Srpaulo	data->group_cipher = WPA_CIPHER_TKIP;
600252726Srpaulo	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
601252726Srpaulo	data->capabilities = 0;
602252726Srpaulo	data->pmkid = NULL;
603252726Srpaulo	data->num_pmkid = 0;
604252726Srpaulo	data->mgmt_group_cipher = 0;
605252726Srpaulo
606252726Srpaulo	if (wpa_ie_len == 0) {
607252726Srpaulo		/* No WPA IE - fail silently */
608252726Srpaulo		return -1;
609252726Srpaulo	}
610252726Srpaulo
611252726Srpaulo	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
612252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
613252726Srpaulo			   __func__, (unsigned long) wpa_ie_len);
614252726Srpaulo		return -1;
615252726Srpaulo	}
616252726Srpaulo
617252726Srpaulo	hdr = (const struct wpa_ie_hdr *) wpa_ie;
618252726Srpaulo
619252726Srpaulo	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
620252726Srpaulo	    hdr->len != wpa_ie_len - 2 ||
621252726Srpaulo	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
622252726Srpaulo	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
623252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
624252726Srpaulo			   __func__);
625252726Srpaulo		return -2;
626252726Srpaulo	}
627252726Srpaulo
628252726Srpaulo	pos = (const u8 *) (hdr + 1);
629252726Srpaulo	left = wpa_ie_len - sizeof(*hdr);
630252726Srpaulo
631252726Srpaulo	if (left >= WPA_SELECTOR_LEN) {
632252726Srpaulo		data->group_cipher = wpa_selector_to_bitfield(pos);
633252726Srpaulo		pos += WPA_SELECTOR_LEN;
634252726Srpaulo		left -= WPA_SELECTOR_LEN;
635252726Srpaulo	} else if (left > 0) {
636252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
637252726Srpaulo			   __func__, left);
638252726Srpaulo		return -3;
639252726Srpaulo	}
640252726Srpaulo
641252726Srpaulo	if (left >= 2) {
642252726Srpaulo		data->pairwise_cipher = 0;
643252726Srpaulo		count = WPA_GET_LE16(pos);
644252726Srpaulo		pos += 2;
645252726Srpaulo		left -= 2;
646252726Srpaulo		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
647252726Srpaulo			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
648252726Srpaulo				   "count %u left %u", __func__, count, left);
649252726Srpaulo			return -4;
650252726Srpaulo		}
651252726Srpaulo		for (i = 0; i < count; i++) {
652252726Srpaulo			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
653252726Srpaulo			pos += WPA_SELECTOR_LEN;
654252726Srpaulo			left -= WPA_SELECTOR_LEN;
655252726Srpaulo		}
656252726Srpaulo	} else if (left == 1) {
657252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
658252726Srpaulo			   __func__);
659252726Srpaulo		return -5;
660252726Srpaulo	}
661252726Srpaulo
662252726Srpaulo	if (left >= 2) {
663252726Srpaulo		data->key_mgmt = 0;
664252726Srpaulo		count = WPA_GET_LE16(pos);
665252726Srpaulo		pos += 2;
666252726Srpaulo		left -= 2;
667252726Srpaulo		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
668252726Srpaulo			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
669252726Srpaulo				   "count %u left %u", __func__, count, left);
670252726Srpaulo			return -6;
671252726Srpaulo		}
672252726Srpaulo		for (i = 0; i < count; i++) {
673252726Srpaulo			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
674252726Srpaulo			pos += WPA_SELECTOR_LEN;
675252726Srpaulo			left -= WPA_SELECTOR_LEN;
676252726Srpaulo		}
677252726Srpaulo	} else if (left == 1) {
678252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
679252726Srpaulo			   __func__);
680252726Srpaulo		return -7;
681252726Srpaulo	}
682252726Srpaulo
683252726Srpaulo	if (left >= 2) {
684252726Srpaulo		data->capabilities = WPA_GET_LE16(pos);
685252726Srpaulo		pos += 2;
686252726Srpaulo		left -= 2;
687252726Srpaulo	}
688252726Srpaulo
689252726Srpaulo	if (left > 0) {
690252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
691252726Srpaulo			   __func__, left);
692252726Srpaulo	}
693252726Srpaulo
694252726Srpaulo	return 0;
695252726Srpaulo}
696252726Srpaulo
697252726Srpaulo
698189251Ssam#ifdef CONFIG_IEEE80211R
699189251Ssam
700189251Ssam/**
701189251Ssam * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
702189251Ssam *
703189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.3
704189251Ssam */
705189251Ssamvoid wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
706189251Ssam		       const u8 *ssid, size_t ssid_len,
707189251Ssam		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
708189251Ssam		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
709189251Ssam{
710189251Ssam	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
711189251Ssam	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
712189251Ssam	u8 *pos, r0_key_data[48], hash[32];
713189251Ssam	const u8 *addr[2];
714189251Ssam	size_t len[2];
715189251Ssam
716189251Ssam	/*
717189251Ssam	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
718189251Ssam	 *                       SSIDlength || SSID || MDID || R0KHlength ||
719189251Ssam	 *                       R0KH-ID || S0KH-ID)
720189251Ssam	 * XXKey is either the second 256 bits of MSK or PSK.
721189251Ssam	 * PMK-R0 = L(R0-Key-Data, 0, 256)
722189251Ssam	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
723189251Ssam	 */
724189251Ssam	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
725189251Ssam		return;
726189251Ssam	pos = buf;
727189251Ssam	*pos++ = ssid_len;
728189251Ssam	os_memcpy(pos, ssid, ssid_len);
729189251Ssam	pos += ssid_len;
730189251Ssam	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
731189251Ssam	pos += MOBILITY_DOMAIN_ID_LEN;
732189251Ssam	*pos++ = r0kh_id_len;
733189251Ssam	os_memcpy(pos, r0kh_id, r0kh_id_len);
734189251Ssam	pos += r0kh_id_len;
735189251Ssam	os_memcpy(pos, s0kh_id, ETH_ALEN);
736189251Ssam	pos += ETH_ALEN;
737189251Ssam
738189251Ssam	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
739189251Ssam		   r0_key_data, sizeof(r0_key_data));
740189251Ssam	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
741189251Ssam
742189251Ssam	/*
743189251Ssam	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
744189251Ssam	 */
745189251Ssam	addr[0] = (const u8 *) "FT-R0N";
746189251Ssam	len[0] = 6;
747189251Ssam	addr[1] = r0_key_data + PMK_LEN;
748189251Ssam	len[1] = 16;
749189251Ssam
750189251Ssam	sha256_vector(2, addr, len, hash);
751189251Ssam	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
752189251Ssam}
753189251Ssam
754189251Ssam
755189251Ssam/**
756189251Ssam * wpa_derive_pmk_r1_name - Derive PMKR1Name
757189251Ssam *
758189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
759189251Ssam */
760189251Ssamvoid wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
761189251Ssam			    const u8 *s1kh_id, u8 *pmk_r1_name)
762189251Ssam{
763189251Ssam	u8 hash[32];
764189251Ssam	const u8 *addr[4];
765189251Ssam	size_t len[4];
766189251Ssam
767189251Ssam	/*
768189251Ssam	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
769189251Ssam	 *                                  R1KH-ID || S1KH-ID))
770189251Ssam	 */
771189251Ssam	addr[0] = (const u8 *) "FT-R1N";
772189251Ssam	len[0] = 6;
773189251Ssam	addr[1] = pmk_r0_name;
774189251Ssam	len[1] = WPA_PMK_NAME_LEN;
775189251Ssam	addr[2] = r1kh_id;
776189251Ssam	len[2] = FT_R1KH_ID_LEN;
777189251Ssam	addr[3] = s1kh_id;
778189251Ssam	len[3] = ETH_ALEN;
779189251Ssam
780189251Ssam	sha256_vector(4, addr, len, hash);
781189251Ssam	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
782189251Ssam}
783189251Ssam
784189251Ssam
785189251Ssam/**
786189251Ssam * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
787189251Ssam *
788189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.4
789189251Ssam */
790189251Ssamvoid wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
791189251Ssam		       const u8 *r1kh_id, const u8 *s1kh_id,
792189251Ssam		       u8 *pmk_r1, u8 *pmk_r1_name)
793189251Ssam{
794189251Ssam	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
795189251Ssam	u8 *pos;
796189251Ssam
797189251Ssam	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
798189251Ssam	pos = buf;
799189251Ssam	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
800189251Ssam	pos += FT_R1KH_ID_LEN;
801189251Ssam	os_memcpy(pos, s1kh_id, ETH_ALEN);
802189251Ssam	pos += ETH_ALEN;
803189251Ssam
804189251Ssam	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
805189251Ssam
806189251Ssam	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
807189251Ssam}
808189251Ssam
809189251Ssam
810189251Ssam/**
811189251Ssam * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
812189251Ssam *
813189251Ssam * IEEE Std 802.11r-2008 - 8.5.1.5.5
814189251Ssam */
815189251Ssamvoid wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
816189251Ssam		       const u8 *sta_addr, const u8 *bssid,
817189251Ssam		       const u8 *pmk_r1_name,
818189251Ssam		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
819189251Ssam{
820189251Ssam	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
821189251Ssam	u8 *pos, hash[32];
822189251Ssam	const u8 *addr[6];
823189251Ssam	size_t len[6];
824189251Ssam
825189251Ssam	/*
826189251Ssam	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
827189251Ssam	 *                  BSSID || STA-ADDR)
828189251Ssam	 */
829189251Ssam	pos = buf;
830189251Ssam	os_memcpy(pos, snonce, WPA_NONCE_LEN);
831189251Ssam	pos += WPA_NONCE_LEN;
832189251Ssam	os_memcpy(pos, anonce, WPA_NONCE_LEN);
833189251Ssam	pos += WPA_NONCE_LEN;
834189251Ssam	os_memcpy(pos, bssid, ETH_ALEN);
835189251Ssam	pos += ETH_ALEN;
836189251Ssam	os_memcpy(pos, sta_addr, ETH_ALEN);
837189251Ssam	pos += ETH_ALEN;
838189251Ssam
839189251Ssam	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
840189251Ssam
841189251Ssam	/*
842189251Ssam	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
843189251Ssam	 *                                ANonce || BSSID || STA-ADDR))
844189251Ssam	 */
845189251Ssam	addr[0] = pmk_r1_name;
846189251Ssam	len[0] = WPA_PMK_NAME_LEN;
847189251Ssam	addr[1] = (const u8 *) "FT-PTKN";
848189251Ssam	len[1] = 7;
849189251Ssam	addr[2] = snonce;
850189251Ssam	len[2] = WPA_NONCE_LEN;
851189251Ssam	addr[3] = anonce;
852189251Ssam	len[3] = WPA_NONCE_LEN;
853189251Ssam	addr[4] = bssid;
854189251Ssam	len[4] = ETH_ALEN;
855189251Ssam	addr[5] = sta_addr;
856189251Ssam	len[5] = ETH_ALEN;
857189251Ssam
858189251Ssam	sha256_vector(6, addr, len, hash);
859189251Ssam	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
860189251Ssam}
861189251Ssam
862189251Ssam#endif /* CONFIG_IEEE80211R */
863214734Srpaulo
864214734Srpaulo
865214734Srpaulo/**
866214734Srpaulo * rsn_pmkid - Calculate PMK identifier
867214734Srpaulo * @pmk: Pairwise master key
868214734Srpaulo * @pmk_len: Length of pmk in bytes
869214734Srpaulo * @aa: Authenticator address
870214734Srpaulo * @spa: Supplicant address
871214734Srpaulo * @pmkid: Buffer for PMKID
872214734Srpaulo * @use_sha256: Whether to use SHA256-based KDF
873214734Srpaulo *
874214734Srpaulo * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
875214734Srpaulo * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
876214734Srpaulo */
877214734Srpaulovoid rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
878214734Srpaulo	       u8 *pmkid, int use_sha256)
879214734Srpaulo{
880214734Srpaulo	char *title = "PMK Name";
881214734Srpaulo	const u8 *addr[3];
882214734Srpaulo	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
883214734Srpaulo	unsigned char hash[SHA256_MAC_LEN];
884214734Srpaulo
885214734Srpaulo	addr[0] = (u8 *) title;
886214734Srpaulo	addr[1] = aa;
887214734Srpaulo	addr[2] = spa;
888214734Srpaulo
889214734Srpaulo#ifdef CONFIG_IEEE80211W
890214734Srpaulo	if (use_sha256)
891214734Srpaulo		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
892214734Srpaulo	else
893214734Srpaulo#endif /* CONFIG_IEEE80211W */
894214734Srpaulo		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
895214734Srpaulo	os_memcpy(pmkid, hash, PMKID_LEN);
896214734Srpaulo}
897214734Srpaulo
898214734Srpaulo
899214734Srpaulo/**
900214734Srpaulo * wpa_cipher_txt - Convert cipher suite to a text string
901214734Srpaulo * @cipher: Cipher suite (WPA_CIPHER_* enum)
902214734Srpaulo * Returns: Pointer to a text string of the cipher suite name
903214734Srpaulo */
904214734Srpauloconst char * wpa_cipher_txt(int cipher)
905214734Srpaulo{
906214734Srpaulo	switch (cipher) {
907214734Srpaulo	case WPA_CIPHER_NONE:
908214734Srpaulo		return "NONE";
909214734Srpaulo	case WPA_CIPHER_WEP40:
910214734Srpaulo		return "WEP-40";
911214734Srpaulo	case WPA_CIPHER_WEP104:
912214734Srpaulo		return "WEP-104";
913214734Srpaulo	case WPA_CIPHER_TKIP:
914214734Srpaulo		return "TKIP";
915214734Srpaulo	case WPA_CIPHER_CCMP:
916214734Srpaulo		return "CCMP";
917214734Srpaulo	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
918214734Srpaulo		return "CCMP+TKIP";
919252726Srpaulo	case WPA_CIPHER_GCMP:
920252726Srpaulo		return "GCMP";
921214734Srpaulo	default:
922214734Srpaulo		return "UNKNOWN";
923214734Srpaulo	}
924214734Srpaulo}
925214734Srpaulo
926214734Srpaulo
927214734Srpaulo/**
928214734Srpaulo * wpa_key_mgmt_txt - Convert key management suite to a text string
929214734Srpaulo * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
930214734Srpaulo * @proto: WPA/WPA2 version (WPA_PROTO_*)
931214734Srpaulo * Returns: Pointer to a text string of the key management suite name
932214734Srpaulo */
933214734Srpauloconst char * wpa_key_mgmt_txt(int key_mgmt, int proto)
934214734Srpaulo{
935214734Srpaulo	switch (key_mgmt) {
936214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X:
937214734Srpaulo		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
938214734Srpaulo			return "WPA2+WPA/IEEE 802.1X/EAP";
939214734Srpaulo		return proto == WPA_PROTO_RSN ?
940214734Srpaulo			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
941214734Srpaulo	case WPA_KEY_MGMT_PSK:
942214734Srpaulo		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
943214734Srpaulo			return "WPA2-PSK+WPA-PSK";
944214734Srpaulo		return proto == WPA_PROTO_RSN ?
945214734Srpaulo			"WPA2-PSK" : "WPA-PSK";
946214734Srpaulo	case WPA_KEY_MGMT_NONE:
947214734Srpaulo		return "NONE";
948214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
949214734Srpaulo		return "IEEE 802.1X (no WPA)";
950214734Srpaulo#ifdef CONFIG_IEEE80211R
951214734Srpaulo	case WPA_KEY_MGMT_FT_IEEE8021X:
952214734Srpaulo		return "FT-EAP";
953214734Srpaulo	case WPA_KEY_MGMT_FT_PSK:
954214734Srpaulo		return "FT-PSK";
955214734Srpaulo#endif /* CONFIG_IEEE80211R */
956214734Srpaulo#ifdef CONFIG_IEEE80211W
957214734Srpaulo	case WPA_KEY_MGMT_IEEE8021X_SHA256:
958214734Srpaulo		return "WPA2-EAP-SHA256";
959214734Srpaulo	case WPA_KEY_MGMT_PSK_SHA256:
960214734Srpaulo		return "WPA2-PSK-SHA256";
961214734Srpaulo#endif /* CONFIG_IEEE80211W */
962214734Srpaulo	default:
963214734Srpaulo		return "UNKNOWN";
964214734Srpaulo	}
965214734Srpaulo}
966214734Srpaulo
967214734Srpaulo
968214734Srpauloint wpa_compare_rsn_ie(int ft_initial_assoc,
969214734Srpaulo		       const u8 *ie1, size_t ie1len,
970214734Srpaulo		       const u8 *ie2, size_t ie2len)
971214734Srpaulo{
972214734Srpaulo	if (ie1 == NULL || ie2 == NULL)
973214734Srpaulo		return -1;
974214734Srpaulo
975214734Srpaulo	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
976214734Srpaulo		return 0; /* identical IEs */
977214734Srpaulo
978214734Srpaulo#ifdef CONFIG_IEEE80211R
979214734Srpaulo	if (ft_initial_assoc) {
980214734Srpaulo		struct wpa_ie_data ie1d, ie2d;
981214734Srpaulo		/*
982214734Srpaulo		 * The PMKID-List in RSN IE is different between Beacon/Probe
983214734Srpaulo		 * Response/(Re)Association Request frames and EAPOL-Key
984214734Srpaulo		 * messages in FT initial mobility domain association. Allow
985214734Srpaulo		 * for this, but verify that other parts of the RSN IEs are
986214734Srpaulo		 * identical.
987214734Srpaulo		 */
988214734Srpaulo		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
989214734Srpaulo		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
990214734Srpaulo			return -1;
991214734Srpaulo		if (ie1d.proto == ie2d.proto &&
992214734Srpaulo		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
993214734Srpaulo		    ie1d.group_cipher == ie2d.group_cipher &&
994214734Srpaulo		    ie1d.key_mgmt == ie2d.key_mgmt &&
995214734Srpaulo		    ie1d.capabilities == ie2d.capabilities &&
996214734Srpaulo		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
997214734Srpaulo			return 0;
998214734Srpaulo	}
999214734Srpaulo#endif /* CONFIG_IEEE80211R */
1000214734Srpaulo
1001214734Srpaulo	return -1;
1002214734Srpaulo}
1003214734Srpaulo
1004214734Srpaulo
1005214734Srpaulo#ifdef CONFIG_IEEE80211R
1006214734Srpauloint wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
1007214734Srpaulo{
1008214734Srpaulo	u8 *start, *end, *rpos, *rend;
1009214734Srpaulo	int added = 0;
1010214734Srpaulo
1011214734Srpaulo	start = ies;
1012214734Srpaulo	end = ies + ies_len;
1013214734Srpaulo
1014214734Srpaulo	while (start < end) {
1015214734Srpaulo		if (*start == WLAN_EID_RSN)
1016214734Srpaulo			break;
1017214734Srpaulo		start += 2 + start[1];
1018214734Srpaulo	}
1019214734Srpaulo	if (start >= end) {
1020214734Srpaulo		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
1021214734Srpaulo			   "IEs data");
1022214734Srpaulo		return -1;
1023214734Srpaulo	}
1024214734Srpaulo	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
1025214734Srpaulo		    start, 2 + start[1]);
1026214734Srpaulo
1027214734Srpaulo	/* Find start of PMKID-Count */
1028214734Srpaulo	rpos = start + 2;
1029214734Srpaulo	rend = rpos + start[1];
1030214734Srpaulo
1031214734Srpaulo	/* Skip Version and Group Data Cipher Suite */
1032214734Srpaulo	rpos += 2 + 4;
1033214734Srpaulo	/* Skip Pairwise Cipher Suite Count and List */
1034214734Srpaulo	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
1035214734Srpaulo	/* Skip AKM Suite Count and List */
1036214734Srpaulo	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
1037214734Srpaulo
1038214734Srpaulo	if (rpos == rend) {
1039214734Srpaulo		/* Add RSN Capabilities */
1040214734Srpaulo		os_memmove(rpos + 2, rpos, end - rpos);
1041214734Srpaulo		*rpos++ = 0;
1042214734Srpaulo		*rpos++ = 0;
1043214734Srpaulo	} else {
1044214734Srpaulo		/* Skip RSN Capabilities */
1045214734Srpaulo		rpos += 2;
1046214734Srpaulo		if (rpos > rend) {
1047214734Srpaulo			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
1048214734Srpaulo				   "IEs data");
1049214734Srpaulo			return -1;
1050214734Srpaulo		}
1051214734Srpaulo	}
1052214734Srpaulo
1053214734Srpaulo	if (rpos == rend) {
1054214734Srpaulo		/* No PMKID-Count field included; add it */
1055214734Srpaulo		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
1056214734Srpaulo		WPA_PUT_LE16(rpos, 1);
1057214734Srpaulo		rpos += 2;
1058214734Srpaulo		os_memcpy(rpos, pmkid, PMKID_LEN);
1059214734Srpaulo		added += 2 + PMKID_LEN;
1060214734Srpaulo		start[1] += 2 + PMKID_LEN;
1061214734Srpaulo	} else {
1062214734Srpaulo		/* PMKID-Count was included; use it */
1063214734Srpaulo		if (WPA_GET_LE16(rpos) != 0) {
1064214734Srpaulo			wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
1065214734Srpaulo				   "in RSN IE in EAPOL-Key data");
1066214734Srpaulo			return -1;
1067214734Srpaulo		}
1068214734Srpaulo		WPA_PUT_LE16(rpos, 1);
1069214734Srpaulo		rpos += 2;
1070214734Srpaulo		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
1071214734Srpaulo		os_memcpy(rpos, pmkid, PMKID_LEN);
1072214734Srpaulo		added += PMKID_LEN;
1073214734Srpaulo		start[1] += PMKID_LEN;
1074214734Srpaulo	}
1075214734Srpaulo
1076214734Srpaulo	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
1077214734Srpaulo		    "(PMKID inserted)", start, 2 + start[1]);
1078214734Srpaulo
1079214734Srpaulo	return added;
1080214734Srpaulo}
1081214734Srpaulo#endif /* CONFIG_IEEE80211R */
1082252726Srpaulo
1083252726Srpaulo
1084252726Srpauloint wpa_cipher_key_len(int cipher)
1085252726Srpaulo{
1086252726Srpaulo	switch (cipher) {
1087252726Srpaulo	case WPA_CIPHER_CCMP:
1088252726Srpaulo	case WPA_CIPHER_GCMP:
1089252726Srpaulo		return 16;
1090252726Srpaulo	case WPA_CIPHER_TKIP:
1091252726Srpaulo		return 32;
1092252726Srpaulo	case WPA_CIPHER_WEP104:
1093252726Srpaulo		return 13;
1094252726Srpaulo	case WPA_CIPHER_WEP40:
1095252726Srpaulo		return 5;
1096252726Srpaulo	}
1097252726Srpaulo
1098252726Srpaulo	return 0;
1099252726Srpaulo}
1100252726Srpaulo
1101252726Srpaulo
1102252726Srpauloint wpa_cipher_rsc_len(int cipher)
1103252726Srpaulo{
1104252726Srpaulo	switch (cipher) {
1105252726Srpaulo	case WPA_CIPHER_CCMP:
1106252726Srpaulo	case WPA_CIPHER_GCMP:
1107252726Srpaulo	case WPA_CIPHER_TKIP:
1108252726Srpaulo		return 6;
1109252726Srpaulo	case WPA_CIPHER_WEP104:
1110252726Srpaulo	case WPA_CIPHER_WEP40:
1111252726Srpaulo		return 0;
1112252726Srpaulo	}
1113252726Srpaulo
1114252726Srpaulo	return 0;
1115252726Srpaulo}
1116252726Srpaulo
1117252726Srpaulo
1118252726Srpauloint wpa_cipher_to_alg(int cipher)
1119252726Srpaulo{
1120252726Srpaulo	switch (cipher) {
1121252726Srpaulo	case WPA_CIPHER_CCMP:
1122252726Srpaulo		return WPA_ALG_CCMP;
1123252726Srpaulo	case WPA_CIPHER_GCMP:
1124252726Srpaulo		return WPA_ALG_GCMP;
1125252726Srpaulo	case WPA_CIPHER_TKIP:
1126252726Srpaulo		return WPA_ALG_TKIP;
1127252726Srpaulo	case WPA_CIPHER_WEP104:
1128252726Srpaulo	case WPA_CIPHER_WEP40:
1129252726Srpaulo		return WPA_ALG_WEP;
1130252726Srpaulo	}
1131252726Srpaulo	return WPA_ALG_NONE;
1132252726Srpaulo}
1133252726Srpaulo
1134252726Srpaulo
1135252726Srpauloint wpa_cipher_valid_pairwise(int cipher)
1136252726Srpaulo{
1137252726Srpaulo	return cipher == WPA_CIPHER_CCMP ||
1138252726Srpaulo		cipher == WPA_CIPHER_GCMP ||
1139252726Srpaulo		cipher == WPA_CIPHER_TKIP;
1140252726Srpaulo}
1141252726Srpaulo
1142252726Srpaulo
1143252726Srpaulou32 wpa_cipher_to_suite(int proto, int cipher)
1144252726Srpaulo{
1145252726Srpaulo	if (cipher & WPA_CIPHER_CCMP)
1146252726Srpaulo		return (proto == WPA_PROTO_RSN ?
1147252726Srpaulo			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
1148252726Srpaulo	if (cipher & WPA_CIPHER_GCMP)
1149252726Srpaulo		return RSN_CIPHER_SUITE_GCMP;
1150252726Srpaulo	if (cipher & WPA_CIPHER_TKIP)
1151252726Srpaulo		return (proto == WPA_PROTO_RSN ?
1152252726Srpaulo			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
1153252726Srpaulo	if (cipher & WPA_CIPHER_WEP104)
1154252726Srpaulo		return (proto == WPA_PROTO_RSN ?
1155252726Srpaulo			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
1156252726Srpaulo	if (cipher & WPA_CIPHER_WEP40)
1157252726Srpaulo		return (proto == WPA_PROTO_RSN ?
1158252726Srpaulo			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
1159252726Srpaulo	if (cipher & WPA_CIPHER_NONE)
1160252726Srpaulo		return (proto == WPA_PROTO_RSN ?
1161252726Srpaulo			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
1162252726Srpaulo	return 0;
1163252726Srpaulo}
1164252726Srpaulo
1165252726Srpaulo
1166252726Srpauloint rsn_cipher_put_suites(u8 *pos, int ciphers)
1167252726Srpaulo{
1168252726Srpaulo	int num_suites = 0;
1169252726Srpaulo
1170252726Srpaulo	if (ciphers & WPA_CIPHER_CCMP) {
1171252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
1172252726Srpaulo		pos += RSN_SELECTOR_LEN;
1173252726Srpaulo		num_suites++;
1174252726Srpaulo	}
1175252726Srpaulo	if (ciphers & WPA_CIPHER_GCMP) {
1176252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
1177252726Srpaulo		pos += RSN_SELECTOR_LEN;
1178252726Srpaulo		num_suites++;
1179252726Srpaulo	}
1180252726Srpaulo	if (ciphers & WPA_CIPHER_TKIP) {
1181252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
1182252726Srpaulo		pos += RSN_SELECTOR_LEN;
1183252726Srpaulo		num_suites++;
1184252726Srpaulo	}
1185252726Srpaulo	if (ciphers & WPA_CIPHER_NONE) {
1186252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
1187252726Srpaulo		pos += RSN_SELECTOR_LEN;
1188252726Srpaulo		num_suites++;
1189252726Srpaulo	}
1190252726Srpaulo
1191252726Srpaulo	return num_suites;
1192252726Srpaulo}
1193252726Srpaulo
1194252726Srpaulo
1195252726Srpauloint wpa_cipher_put_suites(u8 *pos, int ciphers)
1196252726Srpaulo{
1197252726Srpaulo	int num_suites = 0;
1198252726Srpaulo
1199252726Srpaulo	if (ciphers & WPA_CIPHER_CCMP) {
1200252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
1201252726Srpaulo		pos += WPA_SELECTOR_LEN;
1202252726Srpaulo		num_suites++;
1203252726Srpaulo	}
1204252726Srpaulo	if (ciphers & WPA_CIPHER_TKIP) {
1205252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
1206252726Srpaulo		pos += WPA_SELECTOR_LEN;
1207252726Srpaulo		num_suites++;
1208252726Srpaulo	}
1209252726Srpaulo	if (ciphers & WPA_CIPHER_NONE) {
1210252726Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
1211252726Srpaulo		pos += WPA_SELECTOR_LEN;
1212252726Srpaulo		num_suites++;
1213252726Srpaulo	}
1214252726Srpaulo
1215252726Srpaulo	return num_suites;
1216252726Srpaulo}
1217