wpa_auth_ie.c revision 214501
1214501Srpaulo/*
2214501Srpaulo * hostapd - WPA/RSN IE and KDE definitions
3214501Srpaulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "utils/includes.h"
16214501Srpaulo
17214501Srpaulo#include "utils/common.h"
18214501Srpaulo#include "common/ieee802_11_defs.h"
19214501Srpaulo#include "eapol_auth/eapol_auth_sm.h"
20214501Srpaulo#include "ap_config.h"
21214501Srpaulo#include "ieee802_11.h"
22214501Srpaulo#include "wpa_auth.h"
23214501Srpaulo#include "pmksa_cache_auth.h"
24214501Srpaulo#include "wpa_auth_ie.h"
25214501Srpaulo#include "wpa_auth_i.h"
26214501Srpaulo
27214501Srpaulo
28214501Srpaulostatic int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
29214501Srpaulo{
30214501Srpaulo	struct wpa_ie_hdr *hdr;
31214501Srpaulo	int num_suites;
32214501Srpaulo	u8 *pos, *count;
33214501Srpaulo
34214501Srpaulo	hdr = (struct wpa_ie_hdr *) buf;
35214501Srpaulo	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
36214501Srpaulo	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
37214501Srpaulo	WPA_PUT_LE16(hdr->version, WPA_VERSION);
38214501Srpaulo	pos = (u8 *) (hdr + 1);
39214501Srpaulo
40214501Srpaulo	if (conf->wpa_group == WPA_CIPHER_CCMP) {
41214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
42214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
43214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
44214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
45214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
46214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
47214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
48214501Srpaulo	} else {
49214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
50214501Srpaulo			   conf->wpa_group);
51214501Srpaulo		return -1;
52214501Srpaulo	}
53214501Srpaulo	pos += WPA_SELECTOR_LEN;
54214501Srpaulo
55214501Srpaulo	num_suites = 0;
56214501Srpaulo	count = pos;
57214501Srpaulo	pos += 2;
58214501Srpaulo
59214501Srpaulo	if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
60214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
61214501Srpaulo		pos += WPA_SELECTOR_LEN;
62214501Srpaulo		num_suites++;
63214501Srpaulo	}
64214501Srpaulo	if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
65214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
66214501Srpaulo		pos += WPA_SELECTOR_LEN;
67214501Srpaulo		num_suites++;
68214501Srpaulo	}
69214501Srpaulo	if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
70214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
71214501Srpaulo		pos += WPA_SELECTOR_LEN;
72214501Srpaulo		num_suites++;
73214501Srpaulo	}
74214501Srpaulo
75214501Srpaulo	if (num_suites == 0) {
76214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
77214501Srpaulo			   conf->wpa_pairwise);
78214501Srpaulo		return -1;
79214501Srpaulo	}
80214501Srpaulo	WPA_PUT_LE16(count, num_suites);
81214501Srpaulo
82214501Srpaulo	num_suites = 0;
83214501Srpaulo	count = pos;
84214501Srpaulo	pos += 2;
85214501Srpaulo
86214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
87214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
88214501Srpaulo		pos += WPA_SELECTOR_LEN;
89214501Srpaulo		num_suites++;
90214501Srpaulo	}
91214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
92214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
93214501Srpaulo		pos += WPA_SELECTOR_LEN;
94214501Srpaulo		num_suites++;
95214501Srpaulo	}
96214501Srpaulo
97214501Srpaulo	if (num_suites == 0) {
98214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
99214501Srpaulo			   conf->wpa_key_mgmt);
100214501Srpaulo		return -1;
101214501Srpaulo	}
102214501Srpaulo	WPA_PUT_LE16(count, num_suites);
103214501Srpaulo
104214501Srpaulo	/* WPA Capabilities; use defaults, so no need to include it */
105214501Srpaulo
106214501Srpaulo	hdr->len = (pos - buf) - 2;
107214501Srpaulo
108214501Srpaulo	return pos - buf;
109214501Srpaulo}
110214501Srpaulo
111214501Srpaulo
112214501Srpauloint wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
113214501Srpaulo		     const u8 *pmkid)
114214501Srpaulo{
115214501Srpaulo	struct rsn_ie_hdr *hdr;
116214501Srpaulo	int num_suites;
117214501Srpaulo	u8 *pos, *count;
118214501Srpaulo	u16 capab;
119214501Srpaulo
120214501Srpaulo	hdr = (struct rsn_ie_hdr *) buf;
121214501Srpaulo	hdr->elem_id = WLAN_EID_RSN;
122214501Srpaulo	WPA_PUT_LE16(hdr->version, RSN_VERSION);
123214501Srpaulo	pos = (u8 *) (hdr + 1);
124214501Srpaulo
125214501Srpaulo	if (conf->wpa_group == WPA_CIPHER_CCMP) {
126214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
127214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
128214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
129214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
130214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
131214501Srpaulo	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
132214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
133214501Srpaulo	} else {
134214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
135214501Srpaulo			   conf->wpa_group);
136214501Srpaulo		return -1;
137214501Srpaulo	}
138214501Srpaulo	pos += RSN_SELECTOR_LEN;
139214501Srpaulo
140214501Srpaulo	num_suites = 0;
141214501Srpaulo	count = pos;
142214501Srpaulo	pos += 2;
143214501Srpaulo
144214501Srpaulo	if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
145214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
146214501Srpaulo		pos += RSN_SELECTOR_LEN;
147214501Srpaulo		num_suites++;
148214501Srpaulo	}
149214501Srpaulo	if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
150214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
151214501Srpaulo		pos += RSN_SELECTOR_LEN;
152214501Srpaulo		num_suites++;
153214501Srpaulo	}
154214501Srpaulo	if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
155214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
156214501Srpaulo		pos += RSN_SELECTOR_LEN;
157214501Srpaulo		num_suites++;
158214501Srpaulo	}
159214501Srpaulo
160214501Srpaulo	if (num_suites == 0) {
161214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
162214501Srpaulo			   conf->rsn_pairwise);
163214501Srpaulo		return -1;
164214501Srpaulo	}
165214501Srpaulo	WPA_PUT_LE16(count, num_suites);
166214501Srpaulo
167214501Srpaulo	num_suites = 0;
168214501Srpaulo	count = pos;
169214501Srpaulo	pos += 2;
170214501Srpaulo
171214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
172214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
173214501Srpaulo		pos += RSN_SELECTOR_LEN;
174214501Srpaulo		num_suites++;
175214501Srpaulo	}
176214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
177214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
178214501Srpaulo		pos += RSN_SELECTOR_LEN;
179214501Srpaulo		num_suites++;
180214501Srpaulo	}
181214501Srpaulo#ifdef CONFIG_IEEE80211R
182214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
183214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
184214501Srpaulo		pos += RSN_SELECTOR_LEN;
185214501Srpaulo		num_suites++;
186214501Srpaulo	}
187214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
188214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
189214501Srpaulo		pos += RSN_SELECTOR_LEN;
190214501Srpaulo		num_suites++;
191214501Srpaulo	}
192214501Srpaulo#endif /* CONFIG_IEEE80211R */
193214501Srpaulo#ifdef CONFIG_IEEE80211W
194214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
195214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
196214501Srpaulo		pos += RSN_SELECTOR_LEN;
197214501Srpaulo		num_suites++;
198214501Srpaulo	}
199214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
200214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
201214501Srpaulo		pos += RSN_SELECTOR_LEN;
202214501Srpaulo		num_suites++;
203214501Srpaulo	}
204214501Srpaulo#endif /* CONFIG_IEEE80211W */
205214501Srpaulo
206214501Srpaulo	if (num_suites == 0) {
207214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
208214501Srpaulo			   conf->wpa_key_mgmt);
209214501Srpaulo		return -1;
210214501Srpaulo	}
211214501Srpaulo	WPA_PUT_LE16(count, num_suites);
212214501Srpaulo
213214501Srpaulo	/* RSN Capabilities */
214214501Srpaulo	capab = 0;
215214501Srpaulo	if (conf->rsn_preauth)
216214501Srpaulo		capab |= WPA_CAPABILITY_PREAUTH;
217214501Srpaulo	if (conf->peerkey)
218214501Srpaulo		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
219214501Srpaulo	if (conf->wmm_enabled) {
220214501Srpaulo		/* 4 PTKSA replay counters when using WMM */
221214501Srpaulo		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
222214501Srpaulo	}
223214501Srpaulo#ifdef CONFIG_IEEE80211W
224214501Srpaulo	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
225214501Srpaulo		capab |= WPA_CAPABILITY_MFPC;
226214501Srpaulo		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
227214501Srpaulo			capab |= WPA_CAPABILITY_MFPR;
228214501Srpaulo	}
229214501Srpaulo#endif /* CONFIG_IEEE80211W */
230214501Srpaulo	WPA_PUT_LE16(pos, capab);
231214501Srpaulo	pos += 2;
232214501Srpaulo
233214501Srpaulo	if (pmkid) {
234214501Srpaulo		if (pos + 2 + PMKID_LEN > buf + len)
235214501Srpaulo			return -1;
236214501Srpaulo		/* PMKID Count */
237214501Srpaulo		WPA_PUT_LE16(pos, 1);
238214501Srpaulo		pos += 2;
239214501Srpaulo		os_memcpy(pos, pmkid, PMKID_LEN);
240214501Srpaulo		pos += PMKID_LEN;
241214501Srpaulo	}
242214501Srpaulo
243214501Srpaulo#ifdef CONFIG_IEEE80211W
244214501Srpaulo	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
245214501Srpaulo		if (pos + 2 + 4 > buf + len)
246214501Srpaulo			return -1;
247214501Srpaulo		if (pmkid == NULL) {
248214501Srpaulo			/* PMKID Count */
249214501Srpaulo			WPA_PUT_LE16(pos, 0);
250214501Srpaulo			pos += 2;
251214501Srpaulo		}
252214501Srpaulo
253214501Srpaulo		/* Management Group Cipher Suite */
254214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
255214501Srpaulo		pos += RSN_SELECTOR_LEN;
256214501Srpaulo	}
257214501Srpaulo#endif /* CONFIG_IEEE80211W */
258214501Srpaulo
259214501Srpaulo	hdr->len = (pos - buf) - 2;
260214501Srpaulo
261214501Srpaulo	return pos - buf;
262214501Srpaulo}
263214501Srpaulo
264214501Srpaulo
265214501Srpauloint wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
266214501Srpaulo{
267214501Srpaulo	u8 *pos, buf[128];
268214501Srpaulo	int res;
269214501Srpaulo
270214501Srpaulo	pos = buf;
271214501Srpaulo
272214501Srpaulo	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
273214501Srpaulo		res = wpa_write_rsn_ie(&wpa_auth->conf,
274214501Srpaulo				       pos, buf + sizeof(buf) - pos, NULL);
275214501Srpaulo		if (res < 0)
276214501Srpaulo			return res;
277214501Srpaulo		pos += res;
278214501Srpaulo	}
279214501Srpaulo#ifdef CONFIG_IEEE80211R
280214501Srpaulo	if (wpa_auth->conf.wpa_key_mgmt &
281214501Srpaulo	    (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
282214501Srpaulo		res = wpa_write_mdie(&wpa_auth->conf, pos,
283214501Srpaulo				     buf + sizeof(buf) - pos);
284214501Srpaulo		if (res < 0)
285214501Srpaulo			return res;
286214501Srpaulo		pos += res;
287214501Srpaulo	}
288214501Srpaulo#endif /* CONFIG_IEEE80211R */
289214501Srpaulo	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
290214501Srpaulo		res = wpa_write_wpa_ie(&wpa_auth->conf,
291214501Srpaulo				       pos, buf + sizeof(buf) - pos);
292214501Srpaulo		if (res < 0)
293214501Srpaulo			return res;
294214501Srpaulo		pos += res;
295214501Srpaulo	}
296214501Srpaulo
297214501Srpaulo	os_free(wpa_auth->wpa_ie);
298214501Srpaulo	wpa_auth->wpa_ie = os_malloc(pos - buf);
299214501Srpaulo	if (wpa_auth->wpa_ie == NULL)
300214501Srpaulo		return -1;
301214501Srpaulo	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
302214501Srpaulo	wpa_auth->wpa_ie_len = pos - buf;
303214501Srpaulo
304214501Srpaulo	return 0;
305214501Srpaulo}
306214501Srpaulo
307214501Srpaulo
308214501Srpaulou8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
309214501Srpaulo		 const u8 *data2, size_t data2_len)
310214501Srpaulo{
311214501Srpaulo	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
312214501Srpaulo	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
313214501Srpaulo	RSN_SELECTOR_PUT(pos, kde);
314214501Srpaulo	pos += RSN_SELECTOR_LEN;
315214501Srpaulo	os_memcpy(pos, data, data_len);
316214501Srpaulo	pos += data_len;
317214501Srpaulo	if (data2) {
318214501Srpaulo		os_memcpy(pos, data2, data2_len);
319214501Srpaulo		pos += data2_len;
320214501Srpaulo	}
321214501Srpaulo	return pos;
322214501Srpaulo}
323214501Srpaulo
324214501Srpaulo
325214501Srpaulostatic int wpa_selector_to_bitfield(const u8 *s)
326214501Srpaulo{
327214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
328214501Srpaulo		return WPA_CIPHER_NONE;
329214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
330214501Srpaulo		return WPA_CIPHER_WEP40;
331214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
332214501Srpaulo		return WPA_CIPHER_TKIP;
333214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
334214501Srpaulo		return WPA_CIPHER_CCMP;
335214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
336214501Srpaulo		return WPA_CIPHER_WEP104;
337214501Srpaulo	return 0;
338214501Srpaulo}
339214501Srpaulo
340214501Srpaulo
341214501Srpaulostatic int wpa_key_mgmt_to_bitfield(const u8 *s)
342214501Srpaulo{
343214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
344214501Srpaulo		return WPA_KEY_MGMT_IEEE8021X;
345214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
346214501Srpaulo		return WPA_KEY_MGMT_PSK;
347214501Srpaulo	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
348214501Srpaulo		return WPA_KEY_MGMT_WPA_NONE;
349214501Srpaulo	return 0;
350214501Srpaulo}
351214501Srpaulo
352214501Srpaulo
353214501Srpaulostatic int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
354214501Srpaulo				struct wpa_ie_data *data)
355214501Srpaulo{
356214501Srpaulo	const struct wpa_ie_hdr *hdr;
357214501Srpaulo	const u8 *pos;
358214501Srpaulo	int left;
359214501Srpaulo	int i, count;
360214501Srpaulo
361214501Srpaulo	os_memset(data, 0, sizeof(*data));
362214501Srpaulo	data->pairwise_cipher = WPA_CIPHER_TKIP;
363214501Srpaulo	data->group_cipher = WPA_CIPHER_TKIP;
364214501Srpaulo	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
365214501Srpaulo	data->mgmt_group_cipher = 0;
366214501Srpaulo
367214501Srpaulo	if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
368214501Srpaulo		return -1;
369214501Srpaulo
370214501Srpaulo	hdr = (const struct wpa_ie_hdr *) wpa_ie;
371214501Srpaulo
372214501Srpaulo	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
373214501Srpaulo	    hdr->len != wpa_ie_len - 2 ||
374214501Srpaulo	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
375214501Srpaulo	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
376214501Srpaulo		return -2;
377214501Srpaulo	}
378214501Srpaulo
379214501Srpaulo	pos = (const u8 *) (hdr + 1);
380214501Srpaulo	left = wpa_ie_len - sizeof(*hdr);
381214501Srpaulo
382214501Srpaulo	if (left >= WPA_SELECTOR_LEN) {
383214501Srpaulo		data->group_cipher = wpa_selector_to_bitfield(pos);
384214501Srpaulo		pos += WPA_SELECTOR_LEN;
385214501Srpaulo		left -= WPA_SELECTOR_LEN;
386214501Srpaulo	} else if (left > 0)
387214501Srpaulo		  return -3;
388214501Srpaulo
389214501Srpaulo	if (left >= 2) {
390214501Srpaulo		data->pairwise_cipher = 0;
391214501Srpaulo		count = WPA_GET_LE16(pos);
392214501Srpaulo		pos += 2;
393214501Srpaulo		left -= 2;
394214501Srpaulo		if (count == 0 || left < count * WPA_SELECTOR_LEN)
395214501Srpaulo			return -4;
396214501Srpaulo		for (i = 0; i < count; i++) {
397214501Srpaulo			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
398214501Srpaulo			pos += WPA_SELECTOR_LEN;
399214501Srpaulo			left -= WPA_SELECTOR_LEN;
400214501Srpaulo		}
401214501Srpaulo	} else if (left == 1)
402214501Srpaulo		return -5;
403214501Srpaulo
404214501Srpaulo	if (left >= 2) {
405214501Srpaulo		data->key_mgmt = 0;
406214501Srpaulo		count = WPA_GET_LE16(pos);
407214501Srpaulo		pos += 2;
408214501Srpaulo		left -= 2;
409214501Srpaulo		if (count == 0 || left < count * WPA_SELECTOR_LEN)
410214501Srpaulo			return -6;
411214501Srpaulo		for (i = 0; i < count; i++) {
412214501Srpaulo			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
413214501Srpaulo			pos += WPA_SELECTOR_LEN;
414214501Srpaulo			left -= WPA_SELECTOR_LEN;
415214501Srpaulo		}
416214501Srpaulo	} else if (left == 1)
417214501Srpaulo		return -7;
418214501Srpaulo
419214501Srpaulo	if (left >= 2) {
420214501Srpaulo		data->capabilities = WPA_GET_LE16(pos);
421214501Srpaulo		pos += 2;
422214501Srpaulo		left -= 2;
423214501Srpaulo	}
424214501Srpaulo
425214501Srpaulo	if (left > 0) {
426214501Srpaulo		return -8;
427214501Srpaulo	}
428214501Srpaulo
429214501Srpaulo	return 0;
430214501Srpaulo}
431214501Srpaulo
432214501Srpaulo
433214501Srpaulostruct wpa_auth_okc_iter_data {
434214501Srpaulo	struct rsn_pmksa_cache_entry *pmksa;
435214501Srpaulo	const u8 *aa;
436214501Srpaulo	const u8 *spa;
437214501Srpaulo	const u8 *pmkid;
438214501Srpaulo};
439214501Srpaulo
440214501Srpaulo
441214501Srpaulostatic int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
442214501Srpaulo{
443214501Srpaulo	struct wpa_auth_okc_iter_data *data = ctx;
444214501Srpaulo	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
445214501Srpaulo					  data->pmkid);
446214501Srpaulo	if (data->pmksa)
447214501Srpaulo		return 1;
448214501Srpaulo	return 0;
449214501Srpaulo}
450214501Srpaulo
451214501Srpaulo
452214501Srpauloint wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
453214501Srpaulo			struct wpa_state_machine *sm,
454214501Srpaulo			const u8 *wpa_ie, size_t wpa_ie_len,
455214501Srpaulo			const u8 *mdie, size_t mdie_len)
456214501Srpaulo{
457214501Srpaulo	struct wpa_ie_data data;
458214501Srpaulo	int ciphers, key_mgmt, res, version;
459214501Srpaulo	u32 selector;
460214501Srpaulo	size_t i;
461214501Srpaulo	const u8 *pmkid = NULL;
462214501Srpaulo
463214501Srpaulo	if (wpa_auth == NULL || sm == NULL)
464214501Srpaulo		return WPA_NOT_ENABLED;
465214501Srpaulo
466214501Srpaulo	if (wpa_ie == NULL || wpa_ie_len < 1)
467214501Srpaulo		return WPA_INVALID_IE;
468214501Srpaulo
469214501Srpaulo	if (wpa_ie[0] == WLAN_EID_RSN)
470214501Srpaulo		version = WPA_PROTO_RSN;
471214501Srpaulo	else
472214501Srpaulo		version = WPA_PROTO_WPA;
473214501Srpaulo
474214501Srpaulo	if (!(wpa_auth->conf.wpa & version)) {
475214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
476214501Srpaulo			   version, MAC2STR(sm->addr));
477214501Srpaulo		return WPA_INVALID_PROTO;
478214501Srpaulo	}
479214501Srpaulo
480214501Srpaulo	if (version == WPA_PROTO_RSN) {
481214501Srpaulo		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
482214501Srpaulo
483214501Srpaulo		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
484214501Srpaulo		if (0) {
485214501Srpaulo		}
486214501Srpaulo#ifdef CONFIG_IEEE80211R
487214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
488214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
489214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
490214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
491214501Srpaulo#endif /* CONFIG_IEEE80211R */
492214501Srpaulo#ifdef CONFIG_IEEE80211W
493214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
494214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
495214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
496214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
497214501Srpaulo#endif /* CONFIG_IEEE80211W */
498214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
499214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
500214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
501214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
502214501Srpaulo		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
503214501Srpaulo
504214501Srpaulo		selector = RSN_CIPHER_SUITE_CCMP;
505214501Srpaulo		if (data.pairwise_cipher & WPA_CIPHER_CCMP)
506214501Srpaulo			selector = RSN_CIPHER_SUITE_CCMP;
507214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
508214501Srpaulo			selector = RSN_CIPHER_SUITE_TKIP;
509214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
510214501Srpaulo			selector = RSN_CIPHER_SUITE_WEP104;
511214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
512214501Srpaulo			selector = RSN_CIPHER_SUITE_WEP40;
513214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
514214501Srpaulo			selector = RSN_CIPHER_SUITE_NONE;
515214501Srpaulo		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
516214501Srpaulo
517214501Srpaulo		selector = RSN_CIPHER_SUITE_CCMP;
518214501Srpaulo		if (data.group_cipher & WPA_CIPHER_CCMP)
519214501Srpaulo			selector = RSN_CIPHER_SUITE_CCMP;
520214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_TKIP)
521214501Srpaulo			selector = RSN_CIPHER_SUITE_TKIP;
522214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_WEP104)
523214501Srpaulo			selector = RSN_CIPHER_SUITE_WEP104;
524214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_WEP40)
525214501Srpaulo			selector = RSN_CIPHER_SUITE_WEP40;
526214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_NONE)
527214501Srpaulo			selector = RSN_CIPHER_SUITE_NONE;
528214501Srpaulo		wpa_auth->dot11RSNAGroupCipherSelected = selector;
529214501Srpaulo	} else {
530214501Srpaulo		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
531214501Srpaulo
532214501Srpaulo		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
533214501Srpaulo		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
534214501Srpaulo			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
535214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
536214501Srpaulo			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
537214501Srpaulo		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
538214501Srpaulo
539214501Srpaulo		selector = WPA_CIPHER_SUITE_TKIP;
540214501Srpaulo		if (data.pairwise_cipher & WPA_CIPHER_CCMP)
541214501Srpaulo			selector = WPA_CIPHER_SUITE_CCMP;
542214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
543214501Srpaulo			selector = WPA_CIPHER_SUITE_TKIP;
544214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
545214501Srpaulo			selector = WPA_CIPHER_SUITE_WEP104;
546214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
547214501Srpaulo			selector = WPA_CIPHER_SUITE_WEP40;
548214501Srpaulo		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
549214501Srpaulo			selector = WPA_CIPHER_SUITE_NONE;
550214501Srpaulo		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
551214501Srpaulo
552214501Srpaulo		selector = WPA_CIPHER_SUITE_TKIP;
553214501Srpaulo		if (data.group_cipher & WPA_CIPHER_CCMP)
554214501Srpaulo			selector = WPA_CIPHER_SUITE_CCMP;
555214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_TKIP)
556214501Srpaulo			selector = WPA_CIPHER_SUITE_TKIP;
557214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_WEP104)
558214501Srpaulo			selector = WPA_CIPHER_SUITE_WEP104;
559214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_WEP40)
560214501Srpaulo			selector = WPA_CIPHER_SUITE_WEP40;
561214501Srpaulo		else if (data.group_cipher & WPA_CIPHER_NONE)
562214501Srpaulo			selector = WPA_CIPHER_SUITE_NONE;
563214501Srpaulo		wpa_auth->dot11RSNAGroupCipherSelected = selector;
564214501Srpaulo	}
565214501Srpaulo	if (res) {
566214501Srpaulo		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
567214501Srpaulo			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
568214501Srpaulo		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
569214501Srpaulo		return WPA_INVALID_IE;
570214501Srpaulo	}
571214501Srpaulo
572214501Srpaulo	if (data.group_cipher != wpa_auth->conf.wpa_group) {
573214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
574214501Srpaulo			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
575214501Srpaulo		return WPA_INVALID_GROUP;
576214501Srpaulo	}
577214501Srpaulo
578214501Srpaulo	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
579214501Srpaulo	if (!key_mgmt) {
580214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
581214501Srpaulo			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
582214501Srpaulo		return WPA_INVALID_AKMP;
583214501Srpaulo	}
584214501Srpaulo	if (0) {
585214501Srpaulo	}
586214501Srpaulo#ifdef CONFIG_IEEE80211R
587214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
588214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
589214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
590214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
591214501Srpaulo#endif /* CONFIG_IEEE80211R */
592214501Srpaulo#ifdef CONFIG_IEEE80211W
593214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
594214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
595214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
596214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
597214501Srpaulo#endif /* CONFIG_IEEE80211W */
598214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
599214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
600214501Srpaulo	else
601214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
602214501Srpaulo
603214501Srpaulo	if (version == WPA_PROTO_RSN)
604214501Srpaulo		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
605214501Srpaulo	else
606214501Srpaulo		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
607214501Srpaulo	if (!ciphers) {
608214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
609214501Srpaulo			   "from " MACSTR,
610214501Srpaulo			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
611214501Srpaulo			   data.pairwise_cipher, MAC2STR(sm->addr));
612214501Srpaulo		return WPA_INVALID_PAIRWISE;
613214501Srpaulo	}
614214501Srpaulo
615214501Srpaulo#ifdef CONFIG_IEEE80211W
616214501Srpaulo	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
617214501Srpaulo		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
618214501Srpaulo			wpa_printf(MSG_DEBUG, "Management frame protection "
619214501Srpaulo				   "required, but client did not enable it");
620214501Srpaulo			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
621214501Srpaulo		}
622214501Srpaulo
623214501Srpaulo		if (ciphers & WPA_CIPHER_TKIP) {
624214501Srpaulo			wpa_printf(MSG_DEBUG, "Management frame protection "
625214501Srpaulo				   "cannot use TKIP");
626214501Srpaulo			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
627214501Srpaulo		}
628214501Srpaulo
629214501Srpaulo		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
630214501Srpaulo			wpa_printf(MSG_DEBUG, "Unsupported management group "
631214501Srpaulo				   "cipher %d", data.mgmt_group_cipher);
632214501Srpaulo			return WPA_INVALID_MGMT_GROUP_CIPHER;
633214501Srpaulo		}
634214501Srpaulo	}
635214501Srpaulo
636214501Srpaulo	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
637214501Srpaulo	    !(data.capabilities & WPA_CAPABILITY_MFPC))
638214501Srpaulo		sm->mgmt_frame_prot = 0;
639214501Srpaulo	else
640214501Srpaulo		sm->mgmt_frame_prot = 1;
641214501Srpaulo#endif /* CONFIG_IEEE80211W */
642214501Srpaulo
643214501Srpaulo#ifdef CONFIG_IEEE80211R
644214501Srpaulo	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
645214501Srpaulo		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
646214501Srpaulo			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
647214501Srpaulo				   "MDIE not included");
648214501Srpaulo			return WPA_INVALID_MDIE;
649214501Srpaulo		}
650214501Srpaulo		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
651214501Srpaulo			      MOBILITY_DOMAIN_ID_LEN) != 0) {
652214501Srpaulo			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
653214501Srpaulo				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
654214501Srpaulo			return WPA_INVALID_MDIE;
655214501Srpaulo		}
656214501Srpaulo	}
657214501Srpaulo#endif /* CONFIG_IEEE80211R */
658214501Srpaulo
659214501Srpaulo	if (ciphers & WPA_CIPHER_CCMP)
660214501Srpaulo		sm->pairwise = WPA_CIPHER_CCMP;
661214501Srpaulo	else
662214501Srpaulo		sm->pairwise = WPA_CIPHER_TKIP;
663214501Srpaulo
664214501Srpaulo	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
665214501Srpaulo	if (wpa_ie[0] == WLAN_EID_RSN)
666214501Srpaulo		sm->wpa = WPA_VERSION_WPA2;
667214501Srpaulo	else
668214501Srpaulo		sm->wpa = WPA_VERSION_WPA;
669214501Srpaulo
670214501Srpaulo	sm->pmksa = NULL;
671214501Srpaulo	for (i = 0; i < data.num_pmkid; i++) {
672214501Srpaulo		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
673214501Srpaulo			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
674214501Srpaulo		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
675214501Srpaulo						 &data.pmkid[i * PMKID_LEN]);
676214501Srpaulo		if (sm->pmksa) {
677214501Srpaulo			pmkid = sm->pmksa->pmkid;
678214501Srpaulo			break;
679214501Srpaulo		}
680214501Srpaulo	}
681214501Srpaulo	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
682214501Srpaulo		     i < data.num_pmkid; i++) {
683214501Srpaulo		struct wpa_auth_okc_iter_data idata;
684214501Srpaulo		idata.pmksa = NULL;
685214501Srpaulo		idata.aa = wpa_auth->addr;
686214501Srpaulo		idata.spa = sm->addr;
687214501Srpaulo		idata.pmkid = &data.pmkid[i * PMKID_LEN];
688214501Srpaulo		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
689214501Srpaulo		if (idata.pmksa) {
690214501Srpaulo			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
691214501Srpaulo					 "OKC match for PMKID");
692214501Srpaulo			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
693214501Srpaulo							idata.pmksa,
694214501Srpaulo							wpa_auth->addr,
695214501Srpaulo							idata.pmkid);
696214501Srpaulo			pmkid = idata.pmkid;
697214501Srpaulo			break;
698214501Srpaulo		}
699214501Srpaulo	}
700214501Srpaulo	if (sm->pmksa) {
701214501Srpaulo		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
702214501Srpaulo				 "PMKID found from PMKSA cache "
703214501Srpaulo				 "eap_type=%d vlan_id=%d",
704214501Srpaulo				 sm->pmksa->eap_type_authsrv,
705214501Srpaulo				 sm->pmksa->vlan_id);
706214501Srpaulo		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
707214501Srpaulo	}
708214501Srpaulo
709214501Srpaulo	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
710214501Srpaulo		os_free(sm->wpa_ie);
711214501Srpaulo		sm->wpa_ie = os_malloc(wpa_ie_len);
712214501Srpaulo		if (sm->wpa_ie == NULL)
713214501Srpaulo			return WPA_ALLOC_FAIL;
714214501Srpaulo	}
715214501Srpaulo	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
716214501Srpaulo	sm->wpa_ie_len = wpa_ie_len;
717214501Srpaulo
718214501Srpaulo	return WPA_IE_OK;
719214501Srpaulo}
720214501Srpaulo
721214501Srpaulo
722214501Srpaulo/**
723214501Srpaulo * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
724214501Srpaulo * @pos: Pointer to the IE header
725214501Srpaulo * @end: Pointer to the end of the Key Data buffer
726214501Srpaulo * @ie: Pointer to parsed IE data
727214501Srpaulo * Returns: 0 on success, 1 if end mark is found, -1 on failure
728214501Srpaulo */
729214501Srpaulostatic int wpa_parse_generic(const u8 *pos, const u8 *end,
730214501Srpaulo			     struct wpa_eapol_ie_parse *ie)
731214501Srpaulo{
732214501Srpaulo	if (pos[1] == 0)
733214501Srpaulo		return 1;
734214501Srpaulo
735214501Srpaulo	if (pos[1] >= 6 &&
736214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
737214501Srpaulo	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
738214501Srpaulo	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
739214501Srpaulo		ie->wpa_ie = pos;
740214501Srpaulo		ie->wpa_ie_len = pos[1] + 2;
741214501Srpaulo		return 0;
742214501Srpaulo	}
743214501Srpaulo
744214501Srpaulo	if (pos + 1 + RSN_SELECTOR_LEN < end &&
745214501Srpaulo	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
746214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
747214501Srpaulo		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
748214501Srpaulo		return 0;
749214501Srpaulo	}
750214501Srpaulo
751214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
752214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
753214501Srpaulo		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
754214501Srpaulo		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
755214501Srpaulo		return 0;
756214501Srpaulo	}
757214501Srpaulo
758214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
759214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
760214501Srpaulo		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
761214501Srpaulo		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
762214501Srpaulo		return 0;
763214501Srpaulo	}
764214501Srpaulo
765214501Srpaulo#ifdef CONFIG_PEERKEY
766214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
767214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
768214501Srpaulo		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
769214501Srpaulo		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
770214501Srpaulo		return 0;
771214501Srpaulo	}
772214501Srpaulo
773214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
774214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
775214501Srpaulo		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
776214501Srpaulo		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
777214501Srpaulo		return 0;
778214501Srpaulo	}
779214501Srpaulo
780214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
781214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
782214501Srpaulo		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
783214501Srpaulo		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
784214501Srpaulo		return 0;
785214501Srpaulo	}
786214501Srpaulo
787214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
788214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
789214501Srpaulo		ie->error = pos + 2 + RSN_SELECTOR_LEN;
790214501Srpaulo		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
791214501Srpaulo		return 0;
792214501Srpaulo	}
793214501Srpaulo#endif /* CONFIG_PEERKEY */
794214501Srpaulo
795214501Srpaulo#ifdef CONFIG_IEEE80211W
796214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
797214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
798214501Srpaulo		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
799214501Srpaulo		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
800214501Srpaulo		return 0;
801214501Srpaulo	}
802214501Srpaulo#endif /* CONFIG_IEEE80211W */
803214501Srpaulo
804214501Srpaulo	return 0;
805214501Srpaulo}
806214501Srpaulo
807214501Srpaulo
808214501Srpaulo/**
809214501Srpaulo * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
810214501Srpaulo * @buf: Pointer to the Key Data buffer
811214501Srpaulo * @len: Key Data Length
812214501Srpaulo * @ie: Pointer to parsed IE data
813214501Srpaulo * Returns: 0 on success, -1 on failure
814214501Srpaulo */
815214501Srpauloint wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
816214501Srpaulo{
817214501Srpaulo	const u8 *pos, *end;
818214501Srpaulo	int ret = 0;
819214501Srpaulo
820214501Srpaulo	os_memset(ie, 0, sizeof(*ie));
821214501Srpaulo	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
822214501Srpaulo		if (pos[0] == 0xdd &&
823214501Srpaulo		    ((pos == buf + len - 1) || pos[1] == 0)) {
824214501Srpaulo			/* Ignore padding */
825214501Srpaulo			break;
826214501Srpaulo		}
827214501Srpaulo		if (pos + 2 + pos[1] > end) {
828214501Srpaulo			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
829214501Srpaulo				   "underflow (ie=%d len=%d pos=%d)",
830214501Srpaulo				   pos[0], pos[1], (int) (pos - buf));
831214501Srpaulo			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
832214501Srpaulo					buf, len);
833214501Srpaulo			ret = -1;
834214501Srpaulo			break;
835214501Srpaulo		}
836214501Srpaulo		if (*pos == WLAN_EID_RSN) {
837214501Srpaulo			ie->rsn_ie = pos;
838214501Srpaulo			ie->rsn_ie_len = pos[1] + 2;
839214501Srpaulo#ifdef CONFIG_IEEE80211R
840214501Srpaulo		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
841214501Srpaulo			ie->mdie = pos;
842214501Srpaulo			ie->mdie_len = pos[1] + 2;
843214501Srpaulo		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
844214501Srpaulo			ie->ftie = pos;
845214501Srpaulo			ie->ftie_len = pos[1] + 2;
846214501Srpaulo#endif /* CONFIG_IEEE80211R */
847214501Srpaulo		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
848214501Srpaulo			ret = wpa_parse_generic(pos, end, ie);
849214501Srpaulo			if (ret < 0)
850214501Srpaulo				break;
851214501Srpaulo			if (ret > 0) {
852214501Srpaulo				ret = 0;
853214501Srpaulo				break;
854214501Srpaulo			}
855214501Srpaulo		} else {
856214501Srpaulo			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
857214501Srpaulo				    "Key Data IE", pos, 2 + pos[1]);
858214501Srpaulo		}
859214501Srpaulo	}
860214501Srpaulo
861214501Srpaulo	return ret;
862214501Srpaulo}
863214501Srpaulo
864214501Srpaulo
865214501Srpauloint wpa_auth_uses_mfp(struct wpa_state_machine *sm)
866214501Srpaulo{
867214501Srpaulo	return sm ? sm->mgmt_frame_prot : 0;
868214501Srpaulo}
869