wpa_auth_ie.c revision 289549
1214501Srpaulo/*
2214501Srpaulo * hostapd - WPA/RSN IE and KDE definitions
3281806Srpaulo * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#include "utils/common.h"
12214501Srpaulo#include "common/ieee802_11_defs.h"
13214501Srpaulo#include "eapol_auth/eapol_auth_sm.h"
14214501Srpaulo#include "ap_config.h"
15214501Srpaulo#include "ieee802_11.h"
16214501Srpaulo#include "wpa_auth.h"
17214501Srpaulo#include "pmksa_cache_auth.h"
18214501Srpaulo#include "wpa_auth_ie.h"
19214501Srpaulo#include "wpa_auth_i.h"
20214501Srpaulo
21214501Srpaulo
22252726Srpaulo#ifdef CONFIG_RSN_TESTING
23252726Srpauloint rsn_testing = 0;
24252726Srpaulo#endif /* CONFIG_RSN_TESTING */
25252726Srpaulo
26252726Srpaulo
27214501Srpaulostatic int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
28214501Srpaulo{
29214501Srpaulo	struct wpa_ie_hdr *hdr;
30214501Srpaulo	int num_suites;
31214501Srpaulo	u8 *pos, *count;
32252726Srpaulo	u32 suite;
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
40252726Srpaulo	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
41252726Srpaulo	if (suite == 0) {
42214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
43214501Srpaulo			   conf->wpa_group);
44214501Srpaulo		return -1;
45214501Srpaulo	}
46252726Srpaulo	RSN_SELECTOR_PUT(pos, suite);
47214501Srpaulo	pos += WPA_SELECTOR_LEN;
48214501Srpaulo
49214501Srpaulo	count = pos;
50214501Srpaulo	pos += 2;
51214501Srpaulo
52252726Srpaulo	num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
53214501Srpaulo	if (num_suites == 0) {
54214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
55214501Srpaulo			   conf->wpa_pairwise);
56214501Srpaulo		return -1;
57214501Srpaulo	}
58252726Srpaulo	pos += num_suites * WPA_SELECTOR_LEN;
59214501Srpaulo	WPA_PUT_LE16(count, num_suites);
60214501Srpaulo
61214501Srpaulo	num_suites = 0;
62214501Srpaulo	count = pos;
63214501Srpaulo	pos += 2;
64214501Srpaulo
65214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
66214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
67214501Srpaulo		pos += WPA_SELECTOR_LEN;
68214501Srpaulo		num_suites++;
69214501Srpaulo	}
70214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
71214501Srpaulo		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
72214501Srpaulo		pos += WPA_SELECTOR_LEN;
73214501Srpaulo		num_suites++;
74214501Srpaulo	}
75214501Srpaulo
76214501Srpaulo	if (num_suites == 0) {
77214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
78214501Srpaulo			   conf->wpa_key_mgmt);
79214501Srpaulo		return -1;
80214501Srpaulo	}
81214501Srpaulo	WPA_PUT_LE16(count, num_suites);
82214501Srpaulo
83214501Srpaulo	/* WPA Capabilities; use defaults, so no need to include it */
84214501Srpaulo
85214501Srpaulo	hdr->len = (pos - buf) - 2;
86214501Srpaulo
87214501Srpaulo	return pos - buf;
88214501Srpaulo}
89214501Srpaulo
90214501Srpaulo
91214501Srpauloint wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
92214501Srpaulo		     const u8 *pmkid)
93214501Srpaulo{
94214501Srpaulo	struct rsn_ie_hdr *hdr;
95252726Srpaulo	int num_suites, res;
96214501Srpaulo	u8 *pos, *count;
97214501Srpaulo	u16 capab;
98252726Srpaulo	u32 suite;
99214501Srpaulo
100214501Srpaulo	hdr = (struct rsn_ie_hdr *) buf;
101214501Srpaulo	hdr->elem_id = WLAN_EID_RSN;
102214501Srpaulo	WPA_PUT_LE16(hdr->version, RSN_VERSION);
103214501Srpaulo	pos = (u8 *) (hdr + 1);
104214501Srpaulo
105252726Srpaulo	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
106252726Srpaulo	if (suite == 0) {
107214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
108214501Srpaulo			   conf->wpa_group);
109214501Srpaulo		return -1;
110214501Srpaulo	}
111252726Srpaulo	RSN_SELECTOR_PUT(pos, suite);
112214501Srpaulo	pos += RSN_SELECTOR_LEN;
113214501Srpaulo
114214501Srpaulo	num_suites = 0;
115214501Srpaulo	count = pos;
116214501Srpaulo	pos += 2;
117214501Srpaulo
118252726Srpaulo#ifdef CONFIG_RSN_TESTING
119252726Srpaulo	if (rsn_testing) {
120252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
121214501Srpaulo		pos += RSN_SELECTOR_LEN;
122214501Srpaulo		num_suites++;
123214501Srpaulo	}
124252726Srpaulo#endif /* CONFIG_RSN_TESTING */
125252726Srpaulo
126252726Srpaulo	res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
127252726Srpaulo	num_suites += res;
128252726Srpaulo	pos += res * RSN_SELECTOR_LEN;
129252726Srpaulo
130252726Srpaulo#ifdef CONFIG_RSN_TESTING
131252726Srpaulo	if (rsn_testing) {
132252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
133214501Srpaulo		pos += RSN_SELECTOR_LEN;
134214501Srpaulo		num_suites++;
135214501Srpaulo	}
136252726Srpaulo#endif /* CONFIG_RSN_TESTING */
137214501Srpaulo
138214501Srpaulo	if (num_suites == 0) {
139214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
140214501Srpaulo			   conf->rsn_pairwise);
141214501Srpaulo		return -1;
142214501Srpaulo	}
143214501Srpaulo	WPA_PUT_LE16(count, num_suites);
144214501Srpaulo
145214501Srpaulo	num_suites = 0;
146214501Srpaulo	count = pos;
147214501Srpaulo	pos += 2;
148214501Srpaulo
149252726Srpaulo#ifdef CONFIG_RSN_TESTING
150252726Srpaulo	if (rsn_testing) {
151252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
152252726Srpaulo		pos += RSN_SELECTOR_LEN;
153252726Srpaulo		num_suites++;
154252726Srpaulo	}
155252726Srpaulo#endif /* CONFIG_RSN_TESTING */
156252726Srpaulo
157214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
158214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
159214501Srpaulo		pos += RSN_SELECTOR_LEN;
160214501Srpaulo		num_suites++;
161214501Srpaulo	}
162214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
163214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
164214501Srpaulo		pos += RSN_SELECTOR_LEN;
165214501Srpaulo		num_suites++;
166214501Srpaulo	}
167214501Srpaulo#ifdef CONFIG_IEEE80211R
168214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
169214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
170214501Srpaulo		pos += RSN_SELECTOR_LEN;
171214501Srpaulo		num_suites++;
172214501Srpaulo	}
173214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
174214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
175214501Srpaulo		pos += RSN_SELECTOR_LEN;
176214501Srpaulo		num_suites++;
177214501Srpaulo	}
178214501Srpaulo#endif /* CONFIG_IEEE80211R */
179214501Srpaulo#ifdef CONFIG_IEEE80211W
180214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
181214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
182214501Srpaulo		pos += RSN_SELECTOR_LEN;
183214501Srpaulo		num_suites++;
184214501Srpaulo	}
185214501Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
186214501Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
187214501Srpaulo		pos += RSN_SELECTOR_LEN;
188214501Srpaulo		num_suites++;
189214501Srpaulo	}
190214501Srpaulo#endif /* CONFIG_IEEE80211W */
191252726Srpaulo#ifdef CONFIG_SAE
192252726Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
193252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
194252726Srpaulo		pos += RSN_SELECTOR_LEN;
195252726Srpaulo		num_suites++;
196252726Srpaulo	}
197252726Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
198252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
199252726Srpaulo		pos += RSN_SELECTOR_LEN;
200252726Srpaulo		num_suites++;
201252726Srpaulo	}
202252726Srpaulo#endif /* CONFIG_SAE */
203281806Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
204281806Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
205281806Srpaulo		pos += RSN_SELECTOR_LEN;
206281806Srpaulo		num_suites++;
207281806Srpaulo	}
208281806Srpaulo	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
209281806Srpaulo		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
210281806Srpaulo		pos += RSN_SELECTOR_LEN;
211281806Srpaulo		num_suites++;
212281806Srpaulo	}
213214501Srpaulo
214252726Srpaulo#ifdef CONFIG_RSN_TESTING
215252726Srpaulo	if (rsn_testing) {
216252726Srpaulo		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
217252726Srpaulo		pos += RSN_SELECTOR_LEN;
218252726Srpaulo		num_suites++;
219252726Srpaulo	}
220252726Srpaulo#endif /* CONFIG_RSN_TESTING */
221252726Srpaulo
222214501Srpaulo	if (num_suites == 0) {
223214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
224214501Srpaulo			   conf->wpa_key_mgmt);
225214501Srpaulo		return -1;
226214501Srpaulo	}
227214501Srpaulo	WPA_PUT_LE16(count, num_suites);
228214501Srpaulo
229214501Srpaulo	/* RSN Capabilities */
230214501Srpaulo	capab = 0;
231214501Srpaulo	if (conf->rsn_preauth)
232214501Srpaulo		capab |= WPA_CAPABILITY_PREAUTH;
233214501Srpaulo	if (conf->peerkey)
234214501Srpaulo		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
235214501Srpaulo	if (conf->wmm_enabled) {
236214501Srpaulo		/* 4 PTKSA replay counters when using WMM */
237214501Srpaulo		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
238214501Srpaulo	}
239214501Srpaulo#ifdef CONFIG_IEEE80211W
240214501Srpaulo	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
241214501Srpaulo		capab |= WPA_CAPABILITY_MFPC;
242214501Srpaulo		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
243214501Srpaulo			capab |= WPA_CAPABILITY_MFPR;
244214501Srpaulo	}
245214501Srpaulo#endif /* CONFIG_IEEE80211W */
246252726Srpaulo#ifdef CONFIG_RSN_TESTING
247252726Srpaulo	if (rsn_testing)
248252726Srpaulo		capab |= BIT(8) | BIT(14) | BIT(15);
249252726Srpaulo#endif /* CONFIG_RSN_TESTING */
250214501Srpaulo	WPA_PUT_LE16(pos, capab);
251214501Srpaulo	pos += 2;
252214501Srpaulo
253214501Srpaulo	if (pmkid) {
254214501Srpaulo		if (pos + 2 + PMKID_LEN > buf + len)
255214501Srpaulo			return -1;
256214501Srpaulo		/* PMKID Count */
257214501Srpaulo		WPA_PUT_LE16(pos, 1);
258214501Srpaulo		pos += 2;
259214501Srpaulo		os_memcpy(pos, pmkid, PMKID_LEN);
260214501Srpaulo		pos += PMKID_LEN;
261214501Srpaulo	}
262214501Srpaulo
263214501Srpaulo#ifdef CONFIG_IEEE80211W
264289549Srpaulo	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
265289549Srpaulo	    conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
266214501Srpaulo		if (pos + 2 + 4 > buf + len)
267214501Srpaulo			return -1;
268214501Srpaulo		if (pmkid == NULL) {
269214501Srpaulo			/* PMKID Count */
270214501Srpaulo			WPA_PUT_LE16(pos, 0);
271214501Srpaulo			pos += 2;
272214501Srpaulo		}
273214501Srpaulo
274214501Srpaulo		/* Management Group Cipher Suite */
275281806Srpaulo		switch (conf->group_mgmt_cipher) {
276281806Srpaulo		case WPA_CIPHER_AES_128_CMAC:
277281806Srpaulo			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
278281806Srpaulo			break;
279281806Srpaulo		case WPA_CIPHER_BIP_GMAC_128:
280281806Srpaulo			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
281281806Srpaulo			break;
282281806Srpaulo		case WPA_CIPHER_BIP_GMAC_256:
283281806Srpaulo			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
284281806Srpaulo			break;
285281806Srpaulo		case WPA_CIPHER_BIP_CMAC_256:
286281806Srpaulo			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
287281806Srpaulo			break;
288281806Srpaulo		default:
289281806Srpaulo			wpa_printf(MSG_DEBUG,
290281806Srpaulo				   "Invalid group management cipher (0x%x)",
291281806Srpaulo				   conf->group_mgmt_cipher);
292281806Srpaulo			return -1;
293281806Srpaulo		}
294214501Srpaulo		pos += RSN_SELECTOR_LEN;
295214501Srpaulo	}
296214501Srpaulo#endif /* CONFIG_IEEE80211W */
297214501Srpaulo
298252726Srpaulo#ifdef CONFIG_RSN_TESTING
299252726Srpaulo	if (rsn_testing) {
300252726Srpaulo		/*
301252726Srpaulo		 * Fill in any defined fields and add extra data to the end of
302252726Srpaulo		 * the element.
303252726Srpaulo		 */
304252726Srpaulo		int pmkid_count_set = pmkid != NULL;
305252726Srpaulo		if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
306252726Srpaulo			pmkid_count_set = 1;
307252726Srpaulo		/* PMKID Count */
308252726Srpaulo		WPA_PUT_LE16(pos, 0);
309252726Srpaulo		pos += 2;
310252726Srpaulo		if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
311252726Srpaulo			/* Management Group Cipher Suite */
312252726Srpaulo			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
313252726Srpaulo			pos += RSN_SELECTOR_LEN;
314252726Srpaulo		}
315252726Srpaulo
316252726Srpaulo		os_memset(pos, 0x12, 17);
317252726Srpaulo		pos += 17;
318252726Srpaulo	}
319252726Srpaulo#endif /* CONFIG_RSN_TESTING */
320252726Srpaulo
321214501Srpaulo	hdr->len = (pos - buf) - 2;
322214501Srpaulo
323214501Srpaulo	return pos - buf;
324214501Srpaulo}
325214501Srpaulo
326214501Srpaulo
327281806Srpaulostatic u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
328281806Srpaulo{
329281806Srpaulo	u8 *len;
330281806Srpaulo	u16 capab;
331281806Srpaulo
332281806Srpaulo	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
333281806Srpaulo	len = eid++; /* to be filled */
334281806Srpaulo	WPA_PUT_BE24(eid, OUI_WFA);
335281806Srpaulo	eid += 3;
336281806Srpaulo	*eid++ = HS20_OSEN_OUI_TYPE;
337281806Srpaulo
338281806Srpaulo	/* Group Data Cipher Suite */
339281806Srpaulo	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
340281806Srpaulo	eid += RSN_SELECTOR_LEN;
341281806Srpaulo
342281806Srpaulo	/* Pairwise Cipher Suite Count and List */
343281806Srpaulo	WPA_PUT_LE16(eid, 1);
344281806Srpaulo	eid += 2;
345281806Srpaulo	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
346281806Srpaulo	eid += RSN_SELECTOR_LEN;
347281806Srpaulo
348281806Srpaulo	/* AKM Suite Count and List */
349281806Srpaulo	WPA_PUT_LE16(eid, 1);
350281806Srpaulo	eid += 2;
351281806Srpaulo	RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
352281806Srpaulo	eid += RSN_SELECTOR_LEN;
353281806Srpaulo
354281806Srpaulo	/* RSN Capabilities */
355281806Srpaulo	capab = 0;
356281806Srpaulo	if (conf->wmm_enabled) {
357281806Srpaulo		/* 4 PTKSA replay counters when using WMM */
358281806Srpaulo		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
359281806Srpaulo	}
360281806Srpaulo#ifdef CONFIG_IEEE80211W
361281806Srpaulo	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
362281806Srpaulo		capab |= WPA_CAPABILITY_MFPC;
363281806Srpaulo		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
364281806Srpaulo			capab |= WPA_CAPABILITY_MFPR;
365281806Srpaulo	}
366281806Srpaulo#endif /* CONFIG_IEEE80211W */
367281806Srpaulo	WPA_PUT_LE16(eid, capab);
368281806Srpaulo	eid += 2;
369281806Srpaulo
370281806Srpaulo	*len = eid - len - 1;
371281806Srpaulo
372281806Srpaulo	return eid;
373281806Srpaulo}
374281806Srpaulo
375281806Srpaulo
376214501Srpauloint wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
377214501Srpaulo{
378214501Srpaulo	u8 *pos, buf[128];
379214501Srpaulo	int res;
380214501Srpaulo
381289549Srpaulo#ifdef CONFIG_TESTING_OPTIONS
382289549Srpaulo	if (wpa_auth->conf.own_ie_override_len) {
383289549Srpaulo		wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
384289549Srpaulo			    wpa_auth->conf.own_ie_override,
385289549Srpaulo			    wpa_auth->conf.own_ie_override_len);
386289549Srpaulo		os_free(wpa_auth->wpa_ie);
387289549Srpaulo		wpa_auth->wpa_ie =
388289549Srpaulo			os_malloc(wpa_auth->conf.own_ie_override_len);
389289549Srpaulo		if (wpa_auth->wpa_ie == NULL)
390289549Srpaulo			return -1;
391289549Srpaulo		os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
392289549Srpaulo			  wpa_auth->conf.own_ie_override_len);
393289549Srpaulo		wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
394289549Srpaulo		return 0;
395289549Srpaulo	}
396289549Srpaulo#endif /* CONFIG_TESTING_OPTIONS */
397289549Srpaulo
398214501Srpaulo	pos = buf;
399214501Srpaulo
400281806Srpaulo	if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
401281806Srpaulo		pos = wpa_write_osen(&wpa_auth->conf, pos);
402281806Srpaulo	}
403214501Srpaulo	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
404214501Srpaulo		res = wpa_write_rsn_ie(&wpa_auth->conf,
405214501Srpaulo				       pos, buf + sizeof(buf) - pos, NULL);
406214501Srpaulo		if (res < 0)
407214501Srpaulo			return res;
408214501Srpaulo		pos += res;
409214501Srpaulo	}
410214501Srpaulo#ifdef CONFIG_IEEE80211R
411252726Srpaulo	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
412214501Srpaulo		res = wpa_write_mdie(&wpa_auth->conf, pos,
413214501Srpaulo				     buf + sizeof(buf) - pos);
414214501Srpaulo		if (res < 0)
415214501Srpaulo			return res;
416214501Srpaulo		pos += res;
417214501Srpaulo	}
418214501Srpaulo#endif /* CONFIG_IEEE80211R */
419214501Srpaulo	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
420214501Srpaulo		res = wpa_write_wpa_ie(&wpa_auth->conf,
421214501Srpaulo				       pos, buf + sizeof(buf) - pos);
422214501Srpaulo		if (res < 0)
423214501Srpaulo			return res;
424214501Srpaulo		pos += res;
425214501Srpaulo	}
426214501Srpaulo
427214501Srpaulo	os_free(wpa_auth->wpa_ie);
428214501Srpaulo	wpa_auth->wpa_ie = os_malloc(pos - buf);
429214501Srpaulo	if (wpa_auth->wpa_ie == NULL)
430214501Srpaulo		return -1;
431214501Srpaulo	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
432214501Srpaulo	wpa_auth->wpa_ie_len = pos - buf;
433214501Srpaulo
434214501Srpaulo	return 0;
435214501Srpaulo}
436214501Srpaulo
437214501Srpaulo
438214501Srpaulou8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
439214501Srpaulo		 const u8 *data2, size_t data2_len)
440214501Srpaulo{
441214501Srpaulo	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
442214501Srpaulo	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
443214501Srpaulo	RSN_SELECTOR_PUT(pos, kde);
444214501Srpaulo	pos += RSN_SELECTOR_LEN;
445214501Srpaulo	os_memcpy(pos, data, data_len);
446214501Srpaulo	pos += data_len;
447214501Srpaulo	if (data2) {
448214501Srpaulo		os_memcpy(pos, data2, data2_len);
449214501Srpaulo		pos += data2_len;
450214501Srpaulo	}
451214501Srpaulo	return pos;
452214501Srpaulo}
453214501Srpaulo
454214501Srpaulo
455214501Srpaulostruct wpa_auth_okc_iter_data {
456214501Srpaulo	struct rsn_pmksa_cache_entry *pmksa;
457214501Srpaulo	const u8 *aa;
458214501Srpaulo	const u8 *spa;
459214501Srpaulo	const u8 *pmkid;
460214501Srpaulo};
461214501Srpaulo
462214501Srpaulo
463214501Srpaulostatic int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
464214501Srpaulo{
465214501Srpaulo	struct wpa_auth_okc_iter_data *data = ctx;
466214501Srpaulo	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
467214501Srpaulo					  data->pmkid);
468214501Srpaulo	if (data->pmksa)
469214501Srpaulo		return 1;
470214501Srpaulo	return 0;
471214501Srpaulo}
472214501Srpaulo
473214501Srpaulo
474214501Srpauloint wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
475214501Srpaulo			struct wpa_state_machine *sm,
476214501Srpaulo			const u8 *wpa_ie, size_t wpa_ie_len,
477214501Srpaulo			const u8 *mdie, size_t mdie_len)
478214501Srpaulo{
479214501Srpaulo	struct wpa_ie_data data;
480214501Srpaulo	int ciphers, key_mgmt, res, version;
481214501Srpaulo	u32 selector;
482214501Srpaulo	size_t i;
483214501Srpaulo	const u8 *pmkid = NULL;
484214501Srpaulo
485214501Srpaulo	if (wpa_auth == NULL || sm == NULL)
486214501Srpaulo		return WPA_NOT_ENABLED;
487214501Srpaulo
488214501Srpaulo	if (wpa_ie == NULL || wpa_ie_len < 1)
489214501Srpaulo		return WPA_INVALID_IE;
490214501Srpaulo
491214501Srpaulo	if (wpa_ie[0] == WLAN_EID_RSN)
492214501Srpaulo		version = WPA_PROTO_RSN;
493214501Srpaulo	else
494214501Srpaulo		version = WPA_PROTO_WPA;
495214501Srpaulo
496214501Srpaulo	if (!(wpa_auth->conf.wpa & version)) {
497214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
498214501Srpaulo			   version, MAC2STR(sm->addr));
499214501Srpaulo		return WPA_INVALID_PROTO;
500214501Srpaulo	}
501214501Srpaulo
502214501Srpaulo	if (version == WPA_PROTO_RSN) {
503214501Srpaulo		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
504214501Srpaulo
505214501Srpaulo		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
506214501Srpaulo		if (0) {
507214501Srpaulo		}
508281806Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
509281806Srpaulo			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
510281806Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
511281806Srpaulo			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
512214501Srpaulo#ifdef CONFIG_IEEE80211R
513214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
514214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
515214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
516214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
517214501Srpaulo#endif /* CONFIG_IEEE80211R */
518214501Srpaulo#ifdef CONFIG_IEEE80211W
519214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
520214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
521214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
522214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
523214501Srpaulo#endif /* CONFIG_IEEE80211W */
524252726Srpaulo#ifdef CONFIG_SAE
525252726Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
526252726Srpaulo			selector = RSN_AUTH_KEY_MGMT_SAE;
527252726Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
528252726Srpaulo			selector = RSN_AUTH_KEY_MGMT_FT_SAE;
529252726Srpaulo#endif /* CONFIG_SAE */
530214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
531214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
532214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
533214501Srpaulo			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
534214501Srpaulo		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
535214501Srpaulo
536252726Srpaulo		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
537252726Srpaulo					       data.pairwise_cipher);
538252726Srpaulo		if (!selector)
539214501Srpaulo			selector = RSN_CIPHER_SUITE_CCMP;
540214501Srpaulo		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
541214501Srpaulo
542252726Srpaulo		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
543252726Srpaulo					       data.group_cipher);
544252726Srpaulo		if (!selector)
545214501Srpaulo			selector = RSN_CIPHER_SUITE_CCMP;
546214501Srpaulo		wpa_auth->dot11RSNAGroupCipherSelected = selector;
547214501Srpaulo	} else {
548214501Srpaulo		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
549214501Srpaulo
550214501Srpaulo		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
551214501Srpaulo		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
552214501Srpaulo			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
553214501Srpaulo		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
554214501Srpaulo			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
555214501Srpaulo		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
556214501Srpaulo
557252726Srpaulo		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
558252726Srpaulo					       data.pairwise_cipher);
559252726Srpaulo		if (!selector)
560252726Srpaulo			selector = RSN_CIPHER_SUITE_TKIP;
561214501Srpaulo		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
562214501Srpaulo
563252726Srpaulo		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
564252726Srpaulo					       data.group_cipher);
565252726Srpaulo		if (!selector)
566214501Srpaulo			selector = WPA_CIPHER_SUITE_TKIP;
567214501Srpaulo		wpa_auth->dot11RSNAGroupCipherSelected = selector;
568214501Srpaulo	}
569214501Srpaulo	if (res) {
570214501Srpaulo		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
571214501Srpaulo			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
572214501Srpaulo		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
573214501Srpaulo		return WPA_INVALID_IE;
574214501Srpaulo	}
575214501Srpaulo
576214501Srpaulo	if (data.group_cipher != wpa_auth->conf.wpa_group) {
577214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
578214501Srpaulo			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
579214501Srpaulo		return WPA_INVALID_GROUP;
580214501Srpaulo	}
581214501Srpaulo
582214501Srpaulo	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
583214501Srpaulo	if (!key_mgmt) {
584214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
585214501Srpaulo			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
586214501Srpaulo		return WPA_INVALID_AKMP;
587214501Srpaulo	}
588214501Srpaulo	if (0) {
589214501Srpaulo	}
590281806Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
591281806Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
592281806Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
593281806Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
594214501Srpaulo#ifdef CONFIG_IEEE80211R
595214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
596214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
597214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
598214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
599214501Srpaulo#endif /* CONFIG_IEEE80211R */
600214501Srpaulo#ifdef CONFIG_IEEE80211W
601214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
602214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
603214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
604214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
605214501Srpaulo#endif /* CONFIG_IEEE80211W */
606252726Srpaulo#ifdef CONFIG_SAE
607252726Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_SAE)
608252726Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
609252726Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
610252726Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
611252726Srpaulo#endif /* CONFIG_SAE */
612214501Srpaulo	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
613214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
614214501Srpaulo	else
615214501Srpaulo		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
616214501Srpaulo
617214501Srpaulo	if (version == WPA_PROTO_RSN)
618214501Srpaulo		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
619214501Srpaulo	else
620214501Srpaulo		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
621214501Srpaulo	if (!ciphers) {
622214501Srpaulo		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
623214501Srpaulo			   "from " MACSTR,
624214501Srpaulo			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
625214501Srpaulo			   data.pairwise_cipher, MAC2STR(sm->addr));
626214501Srpaulo		return WPA_INVALID_PAIRWISE;
627214501Srpaulo	}
628214501Srpaulo
629214501Srpaulo#ifdef CONFIG_IEEE80211W
630214501Srpaulo	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
631214501Srpaulo		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
632214501Srpaulo			wpa_printf(MSG_DEBUG, "Management frame protection "
633214501Srpaulo				   "required, but client did not enable it");
634214501Srpaulo			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
635214501Srpaulo		}
636214501Srpaulo
637214501Srpaulo		if (ciphers & WPA_CIPHER_TKIP) {
638214501Srpaulo			wpa_printf(MSG_DEBUG, "Management frame protection "
639214501Srpaulo				   "cannot use TKIP");
640214501Srpaulo			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
641214501Srpaulo		}
642214501Srpaulo
643281806Srpaulo		if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
644281806Srpaulo		{
645214501Srpaulo			wpa_printf(MSG_DEBUG, "Unsupported management group "
646214501Srpaulo				   "cipher %d", data.mgmt_group_cipher);
647214501Srpaulo			return WPA_INVALID_MGMT_GROUP_CIPHER;
648214501Srpaulo		}
649214501Srpaulo	}
650214501Srpaulo
651214501Srpaulo	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
652214501Srpaulo	    !(data.capabilities & WPA_CAPABILITY_MFPC))
653214501Srpaulo		sm->mgmt_frame_prot = 0;
654214501Srpaulo	else
655214501Srpaulo		sm->mgmt_frame_prot = 1;
656214501Srpaulo#endif /* CONFIG_IEEE80211W */
657214501Srpaulo
658214501Srpaulo#ifdef CONFIG_IEEE80211R
659214501Srpaulo	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
660214501Srpaulo		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
661214501Srpaulo			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
662214501Srpaulo				   "MDIE not included");
663214501Srpaulo			return WPA_INVALID_MDIE;
664214501Srpaulo		}
665214501Srpaulo		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
666214501Srpaulo			      MOBILITY_DOMAIN_ID_LEN) != 0) {
667214501Srpaulo			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
668214501Srpaulo				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
669214501Srpaulo			return WPA_INVALID_MDIE;
670214501Srpaulo		}
671214501Srpaulo	}
672214501Srpaulo#endif /* CONFIG_IEEE80211R */
673214501Srpaulo
674281806Srpaulo	sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
675281806Srpaulo	if (sm->pairwise < 0)
676281806Srpaulo		return WPA_INVALID_PAIRWISE;
677214501Srpaulo
678214501Srpaulo	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
679214501Srpaulo	if (wpa_ie[0] == WLAN_EID_RSN)
680214501Srpaulo		sm->wpa = WPA_VERSION_WPA2;
681214501Srpaulo	else
682214501Srpaulo		sm->wpa = WPA_VERSION_WPA;
683214501Srpaulo
684214501Srpaulo	sm->pmksa = NULL;
685214501Srpaulo	for (i = 0; i < data.num_pmkid; i++) {
686214501Srpaulo		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
687214501Srpaulo			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
688214501Srpaulo		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
689214501Srpaulo						 &data.pmkid[i * PMKID_LEN]);
690214501Srpaulo		if (sm->pmksa) {
691214501Srpaulo			pmkid = sm->pmksa->pmkid;
692214501Srpaulo			break;
693214501Srpaulo		}
694214501Srpaulo	}
695214501Srpaulo	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
696214501Srpaulo		     i < data.num_pmkid; i++) {
697214501Srpaulo		struct wpa_auth_okc_iter_data idata;
698214501Srpaulo		idata.pmksa = NULL;
699214501Srpaulo		idata.aa = wpa_auth->addr;
700214501Srpaulo		idata.spa = sm->addr;
701214501Srpaulo		idata.pmkid = &data.pmkid[i * PMKID_LEN];
702214501Srpaulo		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
703214501Srpaulo		if (idata.pmksa) {
704214501Srpaulo			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
705214501Srpaulo					 "OKC match for PMKID");
706214501Srpaulo			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
707214501Srpaulo							idata.pmksa,
708214501Srpaulo							wpa_auth->addr,
709214501Srpaulo							idata.pmkid);
710214501Srpaulo			pmkid = idata.pmkid;
711214501Srpaulo			break;
712214501Srpaulo		}
713214501Srpaulo	}
714281806Srpaulo	if (sm->pmksa && pmkid) {
715214501Srpaulo		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
716214501Srpaulo				 "PMKID found from PMKSA cache "
717214501Srpaulo				 "eap_type=%d vlan_id=%d",
718214501Srpaulo				 sm->pmksa->eap_type_authsrv,
719214501Srpaulo				 sm->pmksa->vlan_id);
720214501Srpaulo		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
721214501Srpaulo	}
722214501Srpaulo
723214501Srpaulo	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
724214501Srpaulo		os_free(sm->wpa_ie);
725214501Srpaulo		sm->wpa_ie = os_malloc(wpa_ie_len);
726214501Srpaulo		if (sm->wpa_ie == NULL)
727214501Srpaulo			return WPA_ALLOC_FAIL;
728214501Srpaulo	}
729214501Srpaulo	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
730214501Srpaulo	sm->wpa_ie_len = wpa_ie_len;
731214501Srpaulo
732214501Srpaulo	return WPA_IE_OK;
733214501Srpaulo}
734214501Srpaulo
735214501Srpaulo
736281806Srpaulo#ifdef CONFIG_HS20
737281806Srpauloint wpa_validate_osen(struct wpa_authenticator *wpa_auth,
738281806Srpaulo		      struct wpa_state_machine *sm,
739281806Srpaulo		      const u8 *osen_ie, size_t osen_ie_len)
740281806Srpaulo{
741281806Srpaulo	if (wpa_auth == NULL || sm == NULL)
742281806Srpaulo		return -1;
743281806Srpaulo
744281806Srpaulo	/* TODO: parse OSEN element */
745281806Srpaulo	sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
746281806Srpaulo	sm->mgmt_frame_prot = 1;
747281806Srpaulo	sm->pairwise = WPA_CIPHER_CCMP;
748281806Srpaulo	sm->wpa = WPA_VERSION_WPA2;
749281806Srpaulo
750281806Srpaulo	if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
751281806Srpaulo		os_free(sm->wpa_ie);
752281806Srpaulo		sm->wpa_ie = os_malloc(osen_ie_len);
753281806Srpaulo		if (sm->wpa_ie == NULL)
754281806Srpaulo			return -1;
755281806Srpaulo	}
756281806Srpaulo
757281806Srpaulo	os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
758281806Srpaulo	sm->wpa_ie_len = osen_ie_len;
759281806Srpaulo
760281806Srpaulo	return 0;
761281806Srpaulo}
762281806Srpaulo
763281806Srpaulo#endif /* CONFIG_HS20 */
764281806Srpaulo
765281806Srpaulo
766214501Srpaulo/**
767214501Srpaulo * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
768214501Srpaulo * @pos: Pointer to the IE header
769214501Srpaulo * @end: Pointer to the end of the Key Data buffer
770214501Srpaulo * @ie: Pointer to parsed IE data
771214501Srpaulo * Returns: 0 on success, 1 if end mark is found, -1 on failure
772214501Srpaulo */
773214501Srpaulostatic int wpa_parse_generic(const u8 *pos, const u8 *end,
774214501Srpaulo			     struct wpa_eapol_ie_parse *ie)
775214501Srpaulo{
776214501Srpaulo	if (pos[1] == 0)
777214501Srpaulo		return 1;
778214501Srpaulo
779214501Srpaulo	if (pos[1] >= 6 &&
780214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
781214501Srpaulo	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
782214501Srpaulo	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
783214501Srpaulo		ie->wpa_ie = pos;
784214501Srpaulo		ie->wpa_ie_len = pos[1] + 2;
785214501Srpaulo		return 0;
786214501Srpaulo	}
787214501Srpaulo
788281806Srpaulo	if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
789281806Srpaulo		ie->osen = pos;
790281806Srpaulo		ie->osen_len = pos[1] + 2;
791281806Srpaulo		return 0;
792281806Srpaulo	}
793281806Srpaulo
794214501Srpaulo	if (pos + 1 + RSN_SELECTOR_LEN < end &&
795214501Srpaulo	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
796214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
797214501Srpaulo		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
798214501Srpaulo		return 0;
799214501Srpaulo	}
800214501Srpaulo
801214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
802214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
803214501Srpaulo		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
804214501Srpaulo		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
805214501Srpaulo		return 0;
806214501Srpaulo	}
807214501Srpaulo
808214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
809214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
810214501Srpaulo		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
811214501Srpaulo		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
812214501Srpaulo		return 0;
813214501Srpaulo	}
814214501Srpaulo
815214501Srpaulo#ifdef CONFIG_PEERKEY
816214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
817214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
818214501Srpaulo		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
819214501Srpaulo		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
820214501Srpaulo		return 0;
821214501Srpaulo	}
822214501Srpaulo
823214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
824214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
825214501Srpaulo		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
826214501Srpaulo		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
827214501Srpaulo		return 0;
828214501Srpaulo	}
829214501Srpaulo
830214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
831214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
832214501Srpaulo		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
833214501Srpaulo		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
834214501Srpaulo		return 0;
835214501Srpaulo	}
836214501Srpaulo
837214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
838214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
839214501Srpaulo		ie->error = pos + 2 + RSN_SELECTOR_LEN;
840214501Srpaulo		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
841214501Srpaulo		return 0;
842214501Srpaulo	}
843214501Srpaulo#endif /* CONFIG_PEERKEY */
844214501Srpaulo
845214501Srpaulo#ifdef CONFIG_IEEE80211W
846214501Srpaulo	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
847214501Srpaulo	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
848214501Srpaulo		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
849214501Srpaulo		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
850214501Srpaulo		return 0;
851214501Srpaulo	}
852214501Srpaulo#endif /* CONFIG_IEEE80211W */
853214501Srpaulo
854281806Srpaulo#ifdef CONFIG_P2P
855281806Srpaulo	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
856281806Srpaulo	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
857281806Srpaulo		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
858281806Srpaulo		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
859281806Srpaulo			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
860281806Srpaulo		return 0;
861281806Srpaulo	}
862281806Srpaulo
863281806Srpaulo	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
864281806Srpaulo	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
865281806Srpaulo		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
866281806Srpaulo		wpa_hexdump(MSG_DEBUG,
867281806Srpaulo			    "WPA: IP Address Allocation in EAPOL-Key",
868281806Srpaulo			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
869281806Srpaulo		return 0;
870281806Srpaulo	}
871281806Srpaulo#endif /* CONFIG_P2P */
872281806Srpaulo
873214501Srpaulo	return 0;
874214501Srpaulo}
875214501Srpaulo
876214501Srpaulo
877214501Srpaulo/**
878214501Srpaulo * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
879214501Srpaulo * @buf: Pointer to the Key Data buffer
880214501Srpaulo * @len: Key Data Length
881214501Srpaulo * @ie: Pointer to parsed IE data
882214501Srpaulo * Returns: 0 on success, -1 on failure
883214501Srpaulo */
884214501Srpauloint wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
885214501Srpaulo{
886214501Srpaulo	const u8 *pos, *end;
887214501Srpaulo	int ret = 0;
888214501Srpaulo
889214501Srpaulo	os_memset(ie, 0, sizeof(*ie));
890214501Srpaulo	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
891214501Srpaulo		if (pos[0] == 0xdd &&
892214501Srpaulo		    ((pos == buf + len - 1) || pos[1] == 0)) {
893214501Srpaulo			/* Ignore padding */
894214501Srpaulo			break;
895214501Srpaulo		}
896214501Srpaulo		if (pos + 2 + pos[1] > end) {
897214501Srpaulo			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
898214501Srpaulo				   "underflow (ie=%d len=%d pos=%d)",
899214501Srpaulo				   pos[0], pos[1], (int) (pos - buf));
900214501Srpaulo			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
901214501Srpaulo					buf, len);
902214501Srpaulo			ret = -1;
903214501Srpaulo			break;
904214501Srpaulo		}
905214501Srpaulo		if (*pos == WLAN_EID_RSN) {
906214501Srpaulo			ie->rsn_ie = pos;
907214501Srpaulo			ie->rsn_ie_len = pos[1] + 2;
908214501Srpaulo#ifdef CONFIG_IEEE80211R
909214501Srpaulo		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
910214501Srpaulo			ie->mdie = pos;
911214501Srpaulo			ie->mdie_len = pos[1] + 2;
912214501Srpaulo		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
913214501Srpaulo			ie->ftie = pos;
914214501Srpaulo			ie->ftie_len = pos[1] + 2;
915214501Srpaulo#endif /* CONFIG_IEEE80211R */
916214501Srpaulo		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
917214501Srpaulo			ret = wpa_parse_generic(pos, end, ie);
918214501Srpaulo			if (ret < 0)
919214501Srpaulo				break;
920214501Srpaulo			if (ret > 0) {
921214501Srpaulo				ret = 0;
922214501Srpaulo				break;
923214501Srpaulo			}
924214501Srpaulo		} else {
925214501Srpaulo			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
926214501Srpaulo				    "Key Data IE", pos, 2 + pos[1]);
927214501Srpaulo		}
928214501Srpaulo	}
929214501Srpaulo
930214501Srpaulo	return ret;
931214501Srpaulo}
932214501Srpaulo
933214501Srpaulo
934214501Srpauloint wpa_auth_uses_mfp(struct wpa_state_machine *sm)
935214501Srpaulo{
936214501Srpaulo	return sm ? sm->mgmt_frame_prot : 0;
937214501Srpaulo}
938