]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * hostapd - WPA/RSN IE and KDE definitions | |
c22bb5bb | 3 | * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> |
6fc6879b | 4 | * |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
6fc6879b JM |
7 | */ |
8 | ||
6226e38d | 9 | #include "utils/includes.h" |
6fc6879b | 10 | |
6226e38d | 11 | #include "utils/common.h" |
81f4f619 | 12 | #include "common/ieee802_11_defs.h" |
281c950b | 13 | #include "eapol_auth/eapol_auth_sm.h" |
6226e38d JM |
14 | #include "ap_config.h" |
15 | #include "ieee802_11.h" | |
16 | #include "wpa_auth.h" | |
17 | #include "pmksa_cache_auth.h" | |
6fc6879b JM |
18 | #include "wpa_auth_ie.h" |
19 | #include "wpa_auth_i.h" | |
20 | ||
21 | ||
cd9fc786 JM |
22 | #ifdef CONFIG_RSN_TESTING |
23 | int rsn_testing = 0; | |
24 | #endif /* CONFIG_RSN_TESTING */ | |
25 | ||
26 | ||
6fc6879b JM |
27 | static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) |
28 | { | |
29 | struct wpa_ie_hdr *hdr; | |
30 | int num_suites; | |
31 | u8 *pos, *count; | |
c3550295 | 32 | u32 suite; |
6fc6879b JM |
33 | |
34 | hdr = (struct wpa_ie_hdr *) buf; | |
35 | hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; | |
36 | RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); | |
37 | WPA_PUT_LE16(hdr->version, WPA_VERSION); | |
38 | pos = (u8 *) (hdr + 1); | |
39 | ||
c3550295 JM |
40 | suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group); |
41 | if (suite == 0) { | |
6fc6879b JM |
42 | wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", |
43 | conf->wpa_group); | |
44 | return -1; | |
45 | } | |
c3550295 | 46 | RSN_SELECTOR_PUT(pos, suite); |
6fc6879b JM |
47 | pos += WPA_SELECTOR_LEN; |
48 | ||
6fc6879b JM |
49 | count = pos; |
50 | pos += 2; | |
51 | ||
c3550295 | 52 | num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise); |
6fc6879b JM |
53 | if (num_suites == 0) { |
54 | wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", | |
55 | conf->wpa_pairwise); | |
56 | return -1; | |
57 | } | |
c3550295 | 58 | pos += num_suites * WPA_SELECTOR_LEN; |
6fc6879b JM |
59 | WPA_PUT_LE16(count, num_suites); |
60 | ||
61 | num_suites = 0; | |
62 | count = pos; | |
63 | pos += 2; | |
64 | ||
65 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { | |
66 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); | |
67 | pos += WPA_SELECTOR_LEN; | |
68 | num_suites++; | |
69 | } | |
70 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { | |
71 | RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); | |
72 | pos += WPA_SELECTOR_LEN; | |
73 | num_suites++; | |
74 | } | |
75 | ||
76 | if (num_suites == 0) { | |
77 | wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", | |
78 | conf->wpa_key_mgmt); | |
79 | return -1; | |
80 | } | |
81 | WPA_PUT_LE16(count, num_suites); | |
82 | ||
83 | /* WPA Capabilities; use defaults, so no need to include it */ | |
84 | ||
85 | hdr->len = (pos - buf) - 2; | |
86 | ||
87 | return pos - buf; | |
88 | } | |
89 | ||
90 | ||
91 | int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, | |
92 | const u8 *pmkid) | |
93 | { | |
94 | struct rsn_ie_hdr *hdr; | |
c3550295 | 95 | int num_suites, res; |
6fc6879b JM |
96 | u8 *pos, *count; |
97 | u16 capab; | |
c3550295 | 98 | u32 suite; |
6fc6879b JM |
99 | |
100 | hdr = (struct rsn_ie_hdr *) buf; | |
101 | hdr->elem_id = WLAN_EID_RSN; | |
102 | WPA_PUT_LE16(hdr->version, RSN_VERSION); | |
103 | pos = (u8 *) (hdr + 1); | |
104 | ||
c3550295 JM |
105 | suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); |
106 | if (suite == 0) { | |
6fc6879b JM |
107 | wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", |
108 | conf->wpa_group); | |
109 | return -1; | |
110 | } | |
c3550295 | 111 | RSN_SELECTOR_PUT(pos, suite); |
6fc6879b JM |
112 | pos += RSN_SELECTOR_LEN; |
113 | ||
114 | num_suites = 0; | |
115 | count = pos; | |
116 | pos += 2; | |
117 | ||
cd9fc786 JM |
118 | #ifdef CONFIG_RSN_TESTING |
119 | if (rsn_testing) { | |
120 | RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); | |
121 | pos += RSN_SELECTOR_LEN; | |
122 | num_suites++; | |
123 | } | |
124 | #endif /* CONFIG_RSN_TESTING */ | |
125 | ||
c3550295 JM |
126 | res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); |
127 | num_suites += res; | |
128 | pos += res * RSN_SELECTOR_LEN; | |
6fc6879b | 129 | |
cd9fc786 JM |
130 | #ifdef CONFIG_RSN_TESTING |
131 | if (rsn_testing) { | |
132 | RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); | |
133 | pos += RSN_SELECTOR_LEN; | |
134 | num_suites++; | |
135 | } | |
136 | #endif /* CONFIG_RSN_TESTING */ | |
137 | ||
6fc6879b JM |
138 | if (num_suites == 0) { |
139 | wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", | |
140 | conf->rsn_pairwise); | |
141 | return -1; | |
142 | } | |
143 | WPA_PUT_LE16(count, num_suites); | |
144 | ||
145 | num_suites = 0; | |
146 | count = pos; | |
147 | pos += 2; | |
148 | ||
cd9fc786 JM |
149 | #ifdef CONFIG_RSN_TESTING |
150 | if (rsn_testing) { | |
151 | RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); | |
152 | pos += RSN_SELECTOR_LEN; | |
153 | num_suites++; | |
154 | } | |
155 | #endif /* CONFIG_RSN_TESTING */ | |
156 | ||
6fc6879b JM |
157 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { |
158 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); | |
159 | pos += RSN_SELECTOR_LEN; | |
160 | num_suites++; | |
161 | } | |
162 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { | |
163 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); | |
164 | pos += RSN_SELECTOR_LEN; | |
165 | num_suites++; | |
166 | } | |
4ec1fd8e | 167 | #ifdef CONFIG_IEEE80211R_AP |
6fc6879b JM |
168 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { |
169 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); | |
170 | pos += RSN_SELECTOR_LEN; | |
171 | num_suites++; | |
172 | } | |
c22bb5bb JM |
173 | #ifdef CONFIG_SHA384 |
174 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) { | |
175 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384); | |
176 | pos += RSN_SELECTOR_LEN; | |
177 | num_suites++; | |
178 | } | |
179 | #endif /* CONFIG_SHA384 */ | |
6fc6879b JM |
180 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { |
181 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); | |
182 | pos += RSN_SELECTOR_LEN; | |
183 | num_suites++; | |
184 | } | |
4ec1fd8e | 185 | #endif /* CONFIG_IEEE80211R_AP */ |
56586197 JM |
186 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { |
187 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); | |
188 | pos += RSN_SELECTOR_LEN; | |
189 | num_suites++; | |
190 | } | |
191 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { | |
192 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); | |
193 | pos += RSN_SELECTOR_LEN; | |
194 | num_suites++; | |
195 | } | |
c10347f2 JM |
196 | #ifdef CONFIG_SAE |
197 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { | |
198 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); | |
199 | pos += RSN_SELECTOR_LEN; | |
200 | num_suites++; | |
201 | } | |
202 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { | |
203 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); | |
204 | pos += RSN_SELECTOR_LEN; | |
205 | num_suites++; | |
206 | } | |
207 | #endif /* CONFIG_SAE */ | |
666497c8 JM |
208 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { |
209 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); | |
210 | pos += RSN_SELECTOR_LEN; | |
211 | num_suites++; | |
212 | } | |
5e3b5197 JM |
213 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { |
214 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192); | |
215 | pos += RSN_SELECTOR_LEN; | |
216 | num_suites++; | |
217 | } | |
94318a0d JM |
218 | #ifdef CONFIG_FILS |
219 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) { | |
220 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256); | |
221 | pos += RSN_SELECTOR_LEN; | |
222 | num_suites++; | |
223 | } | |
224 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) { | |
225 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384); | |
226 | pos += RSN_SELECTOR_LEN; | |
227 | num_suites++; | |
228 | } | |
4ec1fd8e | 229 | #ifdef CONFIG_IEEE80211R_AP |
94318a0d JM |
230 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { |
231 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256); | |
232 | pos += RSN_SELECTOR_LEN; | |
233 | num_suites++; | |
234 | } | |
235 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) { | |
236 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384); | |
237 | pos += RSN_SELECTOR_LEN; | |
238 | num_suites++; | |
239 | } | |
4ec1fd8e | 240 | #endif /* CONFIG_IEEE80211R_AP */ |
94318a0d | 241 | #endif /* CONFIG_FILS */ |
a1ea1b45 JM |
242 | #ifdef CONFIG_OWE |
243 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) { | |
244 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE); | |
245 | pos += RSN_SELECTOR_LEN; | |
246 | num_suites++; | |
247 | } | |
248 | #endif /* CONFIG_OWE */ | |
567da5bb JM |
249 | #ifdef CONFIG_DPP |
250 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) { | |
251 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP); | |
252 | pos += RSN_SELECTOR_LEN; | |
253 | num_suites++; | |
254 | } | |
255 | #endif /* CONFIG_DPP */ | |
8d660a4b JM |
256 | #ifdef CONFIG_HS20 |
257 | if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) { | |
258 | RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); | |
259 | pos += RSN_SELECTOR_LEN; | |
260 | num_suites++; | |
261 | } | |
262 | #endif /* CONFIG_HS20 */ | |
6fc6879b | 263 | |
cd9fc786 JM |
264 | #ifdef CONFIG_RSN_TESTING |
265 | if (rsn_testing) { | |
266 | RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); | |
267 | pos += RSN_SELECTOR_LEN; | |
268 | num_suites++; | |
269 | } | |
270 | #endif /* CONFIG_RSN_TESTING */ | |
271 | ||
6fc6879b JM |
272 | if (num_suites == 0) { |
273 | wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", | |
274 | conf->wpa_key_mgmt); | |
275 | return -1; | |
276 | } | |
277 | WPA_PUT_LE16(count, num_suites); | |
278 | ||
279 | /* RSN Capabilities */ | |
280 | capab = 0; | |
281 | if (conf->rsn_preauth) | |
282 | capab |= WPA_CAPABILITY_PREAUTH; | |
3ae0800c JM |
283 | if (conf->wmm_enabled) { |
284 | /* 4 PTKSA replay counters when using WMM */ | |
6fc6879b JM |
285 | capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); |
286 | } | |
70f8cc8e | 287 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { |
0b60b0aa | 288 | capab |= WPA_CAPABILITY_MFPC; |
70f8cc8e | 289 | if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) |
0b60b0aa JM |
290 | capab |= WPA_CAPABILITY_MFPR; |
291 | } | |
875ab60d MV |
292 | #ifdef CONFIG_OCV |
293 | if (conf->ocv) | |
294 | capab |= WPA_CAPABILITY_OCVC; | |
295 | #endif /* CONFIG_OCV */ | |
cd9fc786 JM |
296 | #ifdef CONFIG_RSN_TESTING |
297 | if (rsn_testing) | |
875ab60d | 298 | capab |= BIT(8) | BIT(15); |
cd9fc786 | 299 | #endif /* CONFIG_RSN_TESTING */ |
6fc6879b JM |
300 | WPA_PUT_LE16(pos, capab); |
301 | pos += 2; | |
302 | ||
303 | if (pmkid) { | |
1e72ba2e | 304 | if (2 + PMKID_LEN > buf + len - pos) |
6fc6879b JM |
305 | return -1; |
306 | /* PMKID Count */ | |
307 | WPA_PUT_LE16(pos, 1); | |
308 | pos += 2; | |
309 | os_memcpy(pos, pmkid, PMKID_LEN); | |
310 | pos += PMKID_LEN; | |
311 | } | |
312 | ||
44fa5e74 JM |
313 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION && |
314 | conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) { | |
1e72ba2e | 315 | if (2 + 4 > buf + len - pos) |
6fc6879b JM |
316 | return -1; |
317 | if (pmkid == NULL) { | |
318 | /* PMKID Count */ | |
319 | WPA_PUT_LE16(pos, 0); | |
320 | pos += 2; | |
321 | } | |
322 | ||
323 | /* Management Group Cipher Suite */ | |
8dd9f9cd JM |
324 | switch (conf->group_mgmt_cipher) { |
325 | case WPA_CIPHER_AES_128_CMAC: | |
326 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); | |
327 | break; | |
328 | case WPA_CIPHER_BIP_GMAC_128: | |
329 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128); | |
330 | break; | |
331 | case WPA_CIPHER_BIP_GMAC_256: | |
332 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256); | |
333 | break; | |
334 | case WPA_CIPHER_BIP_CMAC_256: | |
335 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256); | |
336 | break; | |
337 | default: | |
338 | wpa_printf(MSG_DEBUG, | |
339 | "Invalid group management cipher (0x%x)", | |
340 | conf->group_mgmt_cipher); | |
341 | return -1; | |
342 | } | |
6fc6879b JM |
343 | pos += RSN_SELECTOR_LEN; |
344 | } | |
6fc6879b | 345 | |
cd9fc786 JM |
346 | #ifdef CONFIG_RSN_TESTING |
347 | if (rsn_testing) { | |
348 | /* | |
349 | * Fill in any defined fields and add extra data to the end of | |
350 | * the element. | |
351 | */ | |
352 | int pmkid_count_set = pmkid != NULL; | |
353 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) | |
354 | pmkid_count_set = 1; | |
355 | /* PMKID Count */ | |
356 | WPA_PUT_LE16(pos, 0); | |
357 | pos += 2; | |
358 | if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { | |
359 | /* Management Group Cipher Suite */ | |
360 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); | |
361 | pos += RSN_SELECTOR_LEN; | |
362 | } | |
363 | ||
364 | os_memset(pos, 0x12, 17); | |
365 | pos += 17; | |
366 | } | |
367 | #endif /* CONFIG_RSN_TESTING */ | |
368 | ||
6fc6879b JM |
369 | hdr->len = (pos - buf) - 2; |
370 | ||
371 | return pos - buf; | |
372 | } | |
373 | ||
374 | ||
3134bb13 JM |
375 | int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) |
376 | { | |
377 | u8 *pos = buf; | |
378 | ||
379 | if (conf->sae_pwe != 1 && conf->sae_pwe != 2) | |
380 | return 0; /* no supported extended RSN capabilities */ | |
381 | ||
382 | if (len < 3) | |
383 | return -1; | |
384 | ||
385 | *pos++ = WLAN_EID_RSNX; | |
386 | *pos++ = 1; | |
387 | /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is | |
388 | * used for now */ | |
389 | *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E); | |
390 | ||
391 | return pos - buf; | |
392 | } | |
393 | ||
394 | ||
a14896e8 JM |
395 | static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid) |
396 | { | |
397 | u8 *len; | |
398 | u16 capab; | |
399 | ||
400 | *eid++ = WLAN_EID_VENDOR_SPECIFIC; | |
401 | len = eid++; /* to be filled */ | |
402 | WPA_PUT_BE24(eid, OUI_WFA); | |
403 | eid += 3; | |
404 | *eid++ = HS20_OSEN_OUI_TYPE; | |
405 | ||
406 | /* Group Data Cipher Suite */ | |
407 | RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); | |
408 | eid += RSN_SELECTOR_LEN; | |
409 | ||
410 | /* Pairwise Cipher Suite Count and List */ | |
411 | WPA_PUT_LE16(eid, 1); | |
412 | eid += 2; | |
413 | RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); | |
414 | eid += RSN_SELECTOR_LEN; | |
415 | ||
416 | /* AKM Suite Count and List */ | |
417 | WPA_PUT_LE16(eid, 1); | |
418 | eid += 2; | |
419 | RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); | |
420 | eid += RSN_SELECTOR_LEN; | |
421 | ||
422 | /* RSN Capabilities */ | |
423 | capab = 0; | |
424 | if (conf->wmm_enabled) { | |
425 | /* 4 PTKSA replay counters when using WMM */ | |
426 | capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); | |
427 | } | |
a14896e8 JM |
428 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { |
429 | capab |= WPA_CAPABILITY_MFPC; | |
430 | if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) | |
431 | capab |= WPA_CAPABILITY_MFPR; | |
432 | } | |
875ab60d MV |
433 | #ifdef CONFIG_OCV |
434 | if (conf->ocv) | |
435 | capab |= WPA_CAPABILITY_OCVC; | |
436 | #endif /* CONFIG_OCV */ | |
a14896e8 JM |
437 | WPA_PUT_LE16(eid, capab); |
438 | eid += 2; | |
439 | ||
440 | *len = eid - len - 1; | |
441 | ||
442 | return eid; | |
443 | } | |
444 | ||
445 | ||
6fc6879b JM |
446 | int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) |
447 | { | |
448 | u8 *pos, buf[128]; | |
449 | int res; | |
450 | ||
bc02843e JM |
451 | #ifdef CONFIG_TESTING_OPTIONS |
452 | if (wpa_auth->conf.own_ie_override_len) { | |
453 | wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", | |
454 | wpa_auth->conf.own_ie_override, | |
455 | wpa_auth->conf.own_ie_override_len); | |
456 | os_free(wpa_auth->wpa_ie); | |
457 | wpa_auth->wpa_ie = | |
458 | os_malloc(wpa_auth->conf.own_ie_override_len); | |
459 | if (wpa_auth->wpa_ie == NULL) | |
460 | return -1; | |
461 | os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override, | |
462 | wpa_auth->conf.own_ie_override_len); | |
463 | wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len; | |
464 | return 0; | |
465 | } | |
466 | #endif /* CONFIG_TESTING_OPTIONS */ | |
467 | ||
6fc6879b JM |
468 | pos = buf; |
469 | ||
a14896e8 JM |
470 | if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) { |
471 | pos = wpa_write_osen(&wpa_auth->conf, pos); | |
472 | } | |
6fc6879b JM |
473 | if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { |
474 | res = wpa_write_rsn_ie(&wpa_auth->conf, | |
475 | pos, buf + sizeof(buf) - pos, NULL); | |
476 | if (res < 0) | |
477 | return res; | |
478 | pos += res; | |
3134bb13 JM |
479 | res = wpa_write_rsnxe(&wpa_auth->conf, pos, |
480 | buf + sizeof(buf) - pos); | |
481 | if (res < 0) | |
482 | return res; | |
483 | pos += res; | |
6fc6879b | 484 | } |
4ec1fd8e | 485 | #ifdef CONFIG_IEEE80211R_AP |
0bf927a0 | 486 | if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { |
6fc6879b JM |
487 | res = wpa_write_mdie(&wpa_auth->conf, pos, |
488 | buf + sizeof(buf) - pos); | |
489 | if (res < 0) | |
490 | return res; | |
491 | pos += res; | |
492 | } | |
4ec1fd8e | 493 | #endif /* CONFIG_IEEE80211R_AP */ |
6fc6879b JM |
494 | if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { |
495 | res = wpa_write_wpa_ie(&wpa_auth->conf, | |
496 | pos, buf + sizeof(buf) - pos); | |
497 | if (res < 0) | |
498 | return res; | |
499 | pos += res; | |
500 | } | |
501 | ||
502 | os_free(wpa_auth->wpa_ie); | |
503 | wpa_auth->wpa_ie = os_malloc(pos - buf); | |
504 | if (wpa_auth->wpa_ie == NULL) | |
505 | return -1; | |
506 | os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); | |
507 | wpa_auth->wpa_ie_len = pos - buf; | |
508 | ||
509 | return 0; | |
510 | } | |
511 | ||
512 | ||
513 | u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, | |
514 | const u8 *data2, size_t data2_len) | |
515 | { | |
516 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | |
517 | *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; | |
518 | RSN_SELECTOR_PUT(pos, kde); | |
519 | pos += RSN_SELECTOR_LEN; | |
520 | os_memcpy(pos, data, data_len); | |
521 | pos += data_len; | |
522 | if (data2) { | |
523 | os_memcpy(pos, data2, data2_len); | |
524 | pos += data2_len; | |
525 | } | |
526 | return pos; | |
527 | } | |
528 | ||
529 | ||
bf98f7f3 JM |
530 | struct wpa_auth_okc_iter_data { |
531 | struct rsn_pmksa_cache_entry *pmksa; | |
532 | const u8 *aa; | |
533 | const u8 *spa; | |
534 | const u8 *pmkid; | |
535 | }; | |
536 | ||
537 | ||
538 | static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) | |
539 | { | |
540 | struct wpa_auth_okc_iter_data *data = ctx; | |
541 | data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, | |
542 | data->pmkid); | |
543 | if (data->pmksa) | |
544 | return 1; | |
545 | return 0; | |
546 | } | |
547 | ||
548 | ||
6fc6879b | 549 | int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, |
2c129a1b | 550 | struct wpa_state_machine *sm, int freq, |
6fc6879b | 551 | const u8 *wpa_ie, size_t wpa_ie_len, |
d3516cad | 552 | const u8 *rsnxe, size_t rsnxe_len, |
09368515 JM |
553 | const u8 *mdie, size_t mdie_len, |
554 | const u8 *owe_dh, size_t owe_dh_len) | |
6fc6879b JM |
555 | { |
556 | struct wpa_ie_data data; | |
557 | int ciphers, key_mgmt, res, version; | |
558 | u32 selector; | |
559 | size_t i; | |
bf98f7f3 | 560 | const u8 *pmkid = NULL; |
6fc6879b JM |
561 | |
562 | if (wpa_auth == NULL || sm == NULL) | |
563 | return WPA_NOT_ENABLED; | |
564 | ||
565 | if (wpa_ie == NULL || wpa_ie_len < 1) | |
566 | return WPA_INVALID_IE; | |
567 | ||
568 | if (wpa_ie[0] == WLAN_EID_RSN) | |
569 | version = WPA_PROTO_RSN; | |
570 | else | |
571 | version = WPA_PROTO_WPA; | |
572 | ||
2100a768 JM |
573 | if (!(wpa_auth->conf.wpa & version)) { |
574 | wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, | |
575 | version, MAC2STR(sm->addr)); | |
576 | return WPA_INVALID_PROTO; | |
577 | } | |
578 | ||
6fc6879b JM |
579 | if (version == WPA_PROTO_RSN) { |
580 | res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); | |
2c129a1b LD |
581 | if (!data.has_pairwise) |
582 | data.pairwise_cipher = wpa_default_rsn_cipher(freq); | |
583 | if (!data.has_group) | |
584 | data.group_cipher = wpa_default_rsn_cipher(freq); | |
6fc6879b | 585 | |
bb35e2d2 JD |
586 | if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie && |
587 | !wpa_key_mgmt_only_ft(data.key_mgmt)) { | |
588 | /* Workaround for some HP and Epson printers that seem | |
589 | * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP | |
590 | * advertised RSNE to Association Request frame. */ | |
591 | wpa_printf(MSG_DEBUG, | |
592 | "RSN: FT set in RSNE AKM but MDE is missing from " | |
593 | MACSTR | |
594 | " - ignore FT AKM(s) because there's also a non-FT AKM", | |
595 | MAC2STR(sm->addr)); | |
596 | data.key_mgmt &= ~WPA_KEY_MGMT_FT; | |
597 | } | |
598 | ||
6fc6879b JM |
599 | selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; |
600 | if (0) { | |
601 | } | |
5e3b5197 JM |
602 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) |
603 | selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; | |
666497c8 JM |
604 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) |
605 | selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; | |
c30ed45f | 606 | #ifdef CONFIG_FILS |
4ec1fd8e | 607 | #ifdef CONFIG_IEEE80211R_AP |
c30ed45f JM |
608 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) |
609 | selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; | |
610 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) | |
611 | selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; | |
4ec1fd8e | 612 | #endif /* CONFIG_IEEE80211R_AP */ |
c30ed45f JM |
613 | else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) |
614 | selector = RSN_AUTH_KEY_MGMT_FILS_SHA384; | |
615 | else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) | |
616 | selector = RSN_AUTH_KEY_MGMT_FILS_SHA256; | |
617 | #endif /* CONFIG_FILS */ | |
4ec1fd8e | 618 | #ifdef CONFIG_IEEE80211R_AP |
c22bb5bb JM |
619 | #ifdef CONFIG_SHA384 |
620 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) | |
621 | selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; | |
622 | #endif /* CONFIG_SHA384 */ | |
6fc6879b JM |
623 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) |
624 | selector = RSN_AUTH_KEY_MGMT_FT_802_1X; | |
625 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) | |
626 | selector = RSN_AUTH_KEY_MGMT_FT_PSK; | |
4ec1fd8e | 627 | #endif /* CONFIG_IEEE80211R_AP */ |
56586197 JM |
628 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) |
629 | selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; | |
630 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) | |
631 | selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; | |
c10347f2 JM |
632 | #ifdef CONFIG_SAE |
633 | else if (data.key_mgmt & WPA_KEY_MGMT_SAE) | |
634 | selector = RSN_AUTH_KEY_MGMT_SAE; | |
635 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) | |
636 | selector = RSN_AUTH_KEY_MGMT_FT_SAE; | |
637 | #endif /* CONFIG_SAE */ | |
6fc6879b JM |
638 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) |
639 | selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
640 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK) | |
641 | selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; | |
a1ea1b45 JM |
642 | #ifdef CONFIG_OWE |
643 | else if (data.key_mgmt & WPA_KEY_MGMT_OWE) | |
644 | selector = RSN_AUTH_KEY_MGMT_OWE; | |
645 | #endif /* CONFIG_OWE */ | |
567da5bb JM |
646 | #ifdef CONFIG_DPP |
647 | else if (data.key_mgmt & WPA_KEY_MGMT_DPP) | |
648 | selector = RSN_AUTH_KEY_MGMT_DPP; | |
649 | #endif /* CONFIG_DPP */ | |
8d660a4b JM |
650 | #ifdef CONFIG_HS20 |
651 | else if (data.key_mgmt & WPA_KEY_MGMT_OSEN) | |
652 | selector = RSN_AUTH_KEY_MGMT_OSEN; | |
653 | #endif /* CONFIG_HS20 */ | |
6fc6879b JM |
654 | wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; |
655 | ||
c3550295 JM |
656 | selector = wpa_cipher_to_suite(WPA_PROTO_RSN, |
657 | data.pairwise_cipher); | |
658 | if (!selector) | |
6fc6879b | 659 | selector = RSN_CIPHER_SUITE_CCMP; |
6fc6879b JM |
660 | wpa_auth->dot11RSNAPairwiseCipherSelected = selector; |
661 | ||
c3550295 JM |
662 | selector = wpa_cipher_to_suite(WPA_PROTO_RSN, |
663 | data.group_cipher); | |
664 | if (!selector) | |
6fc6879b | 665 | selector = RSN_CIPHER_SUITE_CCMP; |
6fc6879b JM |
666 | wpa_auth->dot11RSNAGroupCipherSelected = selector; |
667 | } else { | |
668 | res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); | |
669 | ||
670 | selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
671 | if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) | |
672 | selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
673 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK) | |
674 | selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; | |
675 | wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; | |
676 | ||
c3550295 JM |
677 | selector = wpa_cipher_to_suite(WPA_PROTO_WPA, |
678 | data.pairwise_cipher); | |
679 | if (!selector) | |
680 | selector = RSN_CIPHER_SUITE_TKIP; | |
6fc6879b JM |
681 | wpa_auth->dot11RSNAPairwiseCipherSelected = selector; |
682 | ||
c3550295 JM |
683 | selector = wpa_cipher_to_suite(WPA_PROTO_WPA, |
684 | data.group_cipher); | |
685 | if (!selector) | |
6fc6879b | 686 | selector = WPA_CIPHER_SUITE_TKIP; |
6fc6879b JM |
687 | wpa_auth->dot11RSNAGroupCipherSelected = selector; |
688 | } | |
689 | if (res) { | |
690 | wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " | |
691 | MACSTR " (res=%d)", MAC2STR(sm->addr), res); | |
692 | wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); | |
693 | return WPA_INVALID_IE; | |
694 | } | |
695 | ||
696 | if (data.group_cipher != wpa_auth->conf.wpa_group) { | |
697 | wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " | |
698 | MACSTR, data.group_cipher, MAC2STR(sm->addr)); | |
699 | return WPA_INVALID_GROUP; | |
700 | } | |
701 | ||
702 | key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; | |
703 | if (!key_mgmt) { | |
704 | wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " | |
705 | MACSTR, data.key_mgmt, MAC2STR(sm->addr)); | |
706 | return WPA_INVALID_AKMP; | |
707 | } | |
708 | if (0) { | |
709 | } | |
5e3b5197 JM |
710 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) |
711 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; | |
666497c8 JM |
712 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) |
713 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B; | |
c30ed45f | 714 | #ifdef CONFIG_FILS |
4ec1fd8e | 715 | #ifdef CONFIG_IEEE80211R_AP |
c30ed45f JM |
716 | else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) |
717 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384; | |
718 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) | |
719 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256; | |
4ec1fd8e | 720 | #endif /* CONFIG_IEEE80211R_AP */ |
c30ed45f JM |
721 | else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) |
722 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384; | |
723 | else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) | |
724 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256; | |
725 | #endif /* CONFIG_FILS */ | |
4ec1fd8e | 726 | #ifdef CONFIG_IEEE80211R_AP |
c22bb5bb JM |
727 | #ifdef CONFIG_SHA384 |
728 | else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) | |
729 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384; | |
730 | #endif /* CONFIG_SHA384 */ | |
6fc6879b JM |
731 | else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) |
732 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; | |
733 | else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) | |
734 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; | |
4ec1fd8e | 735 | #endif /* CONFIG_IEEE80211R_AP */ |
56586197 JM |
736 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) |
737 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; | |
738 | else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) | |
739 | sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; | |
c10347f2 JM |
740 | #ifdef CONFIG_SAE |
741 | else if (key_mgmt & WPA_KEY_MGMT_SAE) | |
742 | sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; | |
743 | else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) | |
744 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; | |
745 | #endif /* CONFIG_SAE */ | |
6fc6879b JM |
746 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) |
747 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
a1ea1b45 JM |
748 | #ifdef CONFIG_OWE |
749 | else if (key_mgmt & WPA_KEY_MGMT_OWE) | |
750 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OWE; | |
751 | #endif /* CONFIG_OWE */ | |
567da5bb JM |
752 | #ifdef CONFIG_DPP |
753 | else if (key_mgmt & WPA_KEY_MGMT_DPP) | |
754 | sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP; | |
755 | #endif /* CONFIG_DPP */ | |
8d660a4b JM |
756 | #ifdef CONFIG_HS20 |
757 | else if (key_mgmt & WPA_KEY_MGMT_OSEN) | |
758 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; | |
759 | #endif /* CONFIG_HS20 */ | |
6fc6879b JM |
760 | else |
761 | sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; | |
762 | ||
763 | if (version == WPA_PROTO_RSN) | |
764 | ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; | |
765 | else | |
766 | ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; | |
767 | if (!ciphers) { | |
768 | wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " | |
769 | "from " MACSTR, | |
770 | version == WPA_PROTO_RSN ? "RSN" : "WPA", | |
771 | data.pairwise_cipher, MAC2STR(sm->addr)); | |
772 | return WPA_INVALID_PAIRWISE; | |
773 | } | |
774 | ||
70f8cc8e | 775 | if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { |
0b60b0aa | 776 | if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { |
6fc6879b JM |
777 | wpa_printf(MSG_DEBUG, "Management frame protection " |
778 | "required, but client did not enable it"); | |
779 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
780 | } | |
781 | ||
8dd9f9cd JM |
782 | if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher) |
783 | { | |
6fc6879b JM |
784 | wpa_printf(MSG_DEBUG, "Unsupported management group " |
785 | "cipher %d", data.mgmt_group_cipher); | |
786 | return WPA_INVALID_MGMT_GROUP_CIPHER; | |
787 | } | |
788 | } | |
789 | ||
ba3d435f JM |
790 | #ifdef CONFIG_SAE |
791 | if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL && | |
74eebe93 | 792 | wpa_auth->conf.sae_require_mfp && |
ba3d435f JM |
793 | wpa_key_mgmt_sae(sm->wpa_key_mgmt) && |
794 | !(data.capabilities & WPA_CAPABILITY_MFPC)) { | |
795 | wpa_printf(MSG_DEBUG, | |
796 | "Management frame protection required with SAE, but client did not enable it"); | |
797 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
798 | } | |
799 | #endif /* CONFIG_SAE */ | |
800 | ||
1e93e423 MV |
801 | #ifdef CONFIG_OCV |
802 | if ((data.capabilities & WPA_CAPABILITY_OCVC) && | |
803 | !(data.capabilities & WPA_CAPABILITY_MFPC)) { | |
804 | wpa_printf(MSG_DEBUG, | |
805 | "Management frame protection required with OCV, but client did not enable it"); | |
806 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
807 | } | |
808 | wpa_auth_set_ocv(sm, wpa_auth->conf.ocv && | |
809 | (data.capabilities & WPA_CAPABILITY_OCVC)); | |
810 | #endif /* CONFIG_OCV */ | |
811 | ||
70f8cc8e | 812 | if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || |
0b60b0aa | 813 | !(data.capabilities & WPA_CAPABILITY_MFPC)) |
6fc6879b JM |
814 | sm->mgmt_frame_prot = 0; |
815 | else | |
816 | sm->mgmt_frame_prot = 1; | |
02b38d0a JM |
817 | |
818 | if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) { | |
819 | wpa_printf(MSG_DEBUG, | |
820 | "Management frame protection cannot use TKIP"); | |
821 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
822 | } | |
6fc6879b | 823 | |
4ec1fd8e | 824 | #ifdef CONFIG_IEEE80211R_AP |
56586197 | 825 | if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { |
6fc6879b JM |
826 | if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { |
827 | wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " | |
828 | "MDIE not included"); | |
829 | return WPA_INVALID_MDIE; | |
830 | } | |
831 | if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, | |
832 | MOBILITY_DOMAIN_ID_LEN) != 0) { | |
833 | wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " | |
834 | "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); | |
835 | return WPA_INVALID_MDIE; | |
836 | } | |
209dad06 WG |
837 | } else if (mdie != NULL) { |
838 | wpa_printf(MSG_DEBUG, | |
839 | "RSN: Trying to use non-FT AKM suite, but MDIE included"); | |
840 | return WPA_INVALID_AKMP; | |
6fc6879b | 841 | } |
4ec1fd8e | 842 | #endif /* CONFIG_IEEE80211R_AP */ |
6fc6879b | 843 | |
09368515 JM |
844 | #ifdef CONFIG_OWE |
845 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && !owe_dh) { | |
846 | wpa_printf(MSG_DEBUG, | |
847 | "OWE: No Diffie-Hellman Parameter element"); | |
848 | return WPA_INVALID_AKMP; | |
849 | } | |
16a4e931 JM |
850 | #ifdef CONFIG_DPP |
851 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) { | |
852 | /* Diffie-Hellman Parameter element can be used with DPP as | |
853 | * well, so allow this to proceed. */ | |
854 | } else | |
855 | #endif /* CONFIG_DPP */ | |
09368515 JM |
856 | if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) { |
857 | wpa_printf(MSG_DEBUG, | |
858 | "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM"); | |
859 | return WPA_INVALID_AKMP; | |
860 | } | |
861 | #endif /* CONFIG_OWE */ | |
862 | ||
edbd2a19 JM |
863 | sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0); |
864 | if (sm->pairwise < 0) | |
865 | return WPA_INVALID_PAIRWISE; | |
6fc6879b JM |
866 | |
867 | /* TODO: clear WPA/WPA2 state if STA changes from one to another */ | |
868 | if (wpa_ie[0] == WLAN_EID_RSN) | |
869 | sm->wpa = WPA_VERSION_WPA2; | |
870 | else | |
871 | sm->wpa = WPA_VERSION_WPA; | |
872 | ||
36536639 JM |
873 | #if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS) |
874 | if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 || | |
875 | sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) && | |
876 | (sm->auth_alg == WLAN_AUTH_FILS_SK || | |
877 | sm->auth_alg == WLAN_AUTH_FILS_SK_PFS || | |
878 | sm->auth_alg == WLAN_AUTH_FILS_PK) && | |
879 | (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid || | |
880 | os_memcmp_const(data.pmkid, sm->pmk_r1_name, | |
881 | WPA_PMK_NAME_LEN) != 0)) { | |
882 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
883 | "No PMKR1Name match for FILS+FT"); | |
884 | return WPA_INVALID_PMKID; | |
885 | } | |
886 | #endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */ | |
887 | ||
bf98f7f3 | 888 | sm->pmksa = NULL; |
6fc6879b JM |
889 | for (i = 0; i < data.num_pmkid; i++) { |
890 | wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", | |
891 | &data.pmkid[i * PMKID_LEN], PMKID_LEN); | |
4bb081f1 JM |
892 | sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, |
893 | &data.pmkid[i * PMKID_LEN]); | |
6fc6879b | 894 | if (sm->pmksa) { |
bf98f7f3 JM |
895 | pmkid = sm->pmksa->pmkid; |
896 | break; | |
897 | } | |
898 | } | |
899 | for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && | |
900 | i < data.num_pmkid; i++) { | |
901 | struct wpa_auth_okc_iter_data idata; | |
902 | idata.pmksa = NULL; | |
903 | idata.aa = wpa_auth->addr; | |
904 | idata.spa = sm->addr; | |
905 | idata.pmkid = &data.pmkid[i * PMKID_LEN]; | |
906 | wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); | |
907 | if (idata.pmksa) { | |
6fc6879b | 908 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, |
bf98f7f3 JM |
909 | "OKC match for PMKID"); |
910 | sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, | |
911 | idata.pmksa, | |
912 | wpa_auth->addr, | |
913 | idata.pmkid); | |
914 | pmkid = idata.pmkid; | |
6fc6879b JM |
915 | break; |
916 | } | |
917 | } | |
4a9d0ebe | 918 | if (sm->pmksa && pmkid) { |
8e44c192 | 919 | struct vlan_description *vlan; |
1889af2e | 920 | |
8e44c192 | 921 | vlan = sm->pmksa->vlan_desc; |
bf98f7f3 | 922 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, |
8e44c192 | 923 | "PMKID found from PMKSA cache eap_type=%d vlan=%d%s", |
bf98f7f3 | 924 | sm->pmksa->eap_type_authsrv, |
8e44c192 MB |
925 | vlan ? vlan->untagged : 0, |
926 | (vlan && vlan->tagged[0]) ? "+" : ""); | |
bf98f7f3 JM |
927 | os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); |
928 | } | |
6fc6879b | 929 | |
458d8984 AP |
930 | #ifdef CONFIG_SAE |
931 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid && | |
932 | !sm->pmksa) { | |
933 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
934 | "No PMKSA cache entry found for SAE"); | |
935 | return WPA_INVALID_PMKID; | |
936 | } | |
937 | #endif /* CONFIG_SAE */ | |
938 | ||
567da5bb JM |
939 | #ifdef CONFIG_DPP |
940 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) { | |
941 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
942 | "No PMKSA cache entry found for DPP"); | |
943 | return WPA_INVALID_PMKID; | |
944 | } | |
945 | #endif /* CONFIG_DPP */ | |
946 | ||
6fc6879b JM |
947 | if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { |
948 | os_free(sm->wpa_ie); | |
949 | sm->wpa_ie = os_malloc(wpa_ie_len); | |
950 | if (sm->wpa_ie == NULL) | |
951 | return WPA_ALLOC_FAIL; | |
952 | } | |
953 | os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); | |
954 | sm->wpa_ie_len = wpa_ie_len; | |
955 | ||
d3516cad JM |
956 | if (rsnxe && rsnxe_len) { |
957 | if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) { | |
958 | os_free(sm->rsnxe); | |
959 | sm->rsnxe = os_malloc(rsnxe_len); | |
960 | if (!sm->rsnxe) | |
961 | return WPA_ALLOC_FAIL; | |
962 | } | |
963 | os_memcpy(sm->rsnxe, rsnxe, rsnxe_len); | |
964 | sm->rsnxe_len = rsnxe_len; | |
965 | } else { | |
966 | os_free(sm->rsnxe); | |
967 | sm->rsnxe = NULL; | |
968 | sm->rsnxe_len = 0; | |
969 | } | |
970 | ||
6fc6879b JM |
971 | return WPA_IE_OK; |
972 | } | |
973 | ||
974 | ||
a14896e8 JM |
975 | #ifdef CONFIG_HS20 |
976 | int wpa_validate_osen(struct wpa_authenticator *wpa_auth, | |
977 | struct wpa_state_machine *sm, | |
978 | const u8 *osen_ie, size_t osen_ie_len) | |
979 | { | |
980 | if (wpa_auth == NULL || sm == NULL) | |
981 | return -1; | |
982 | ||
983 | /* TODO: parse OSEN element */ | |
984 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; | |
985 | sm->mgmt_frame_prot = 1; | |
986 | sm->pairwise = WPA_CIPHER_CCMP; | |
987 | sm->wpa = WPA_VERSION_WPA2; | |
988 | ||
989 | if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) { | |
990 | os_free(sm->wpa_ie); | |
991 | sm->wpa_ie = os_malloc(osen_ie_len); | |
992 | if (sm->wpa_ie == NULL) | |
993 | return -1; | |
994 | } | |
995 | ||
996 | os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len); | |
997 | sm->wpa_ie_len = osen_ie_len; | |
998 | ||
999 | return 0; | |
1000 | } | |
1001 | ||
1002 | #endif /* CONFIG_HS20 */ | |
1003 | ||
1004 | ||
6fc6879b JM |
1005 | /** |
1006 | * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs | |
1007 | * @pos: Pointer to the IE header | |
1008 | * @end: Pointer to the end of the Key Data buffer | |
1009 | * @ie: Pointer to parsed IE data | |
1010 | * Returns: 0 on success, 1 if end mark is found, -1 on failure | |
1011 | */ | |
1012 | static int wpa_parse_generic(const u8 *pos, const u8 *end, | |
1013 | struct wpa_eapol_ie_parse *ie) | |
1014 | { | |
1015 | if (pos[1] == 0) | |
1016 | return 1; | |
1017 | ||
1018 | if (pos[1] >= 6 && | |
1019 | RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && | |
1020 | pos[2 + WPA_SELECTOR_LEN] == 1 && | |
1021 | pos[2 + WPA_SELECTOR_LEN + 1] == 0) { | |
1022 | ie->wpa_ie = pos; | |
1023 | ie->wpa_ie_len = pos[1] + 2; | |
1024 | return 0; | |
1025 | } | |
1026 | ||
a14896e8 JM |
1027 | if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) { |
1028 | ie->osen = pos; | |
1029 | ie->osen_len = pos[1] + 2; | |
1030 | return 0; | |
1031 | } | |
1032 | ||
1e72ba2e | 1033 | if (1 + RSN_SELECTOR_LEN < end - pos && |
6fc6879b JM |
1034 | pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && |
1035 | RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { | |
1036 | ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; | |
1037 | return 0; | |
1038 | } | |
1039 | ||
1040 | if (pos[1] > RSN_SELECTOR_LEN + 2 && | |
1041 | RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { | |
1042 | ie->gtk = pos + 2 + RSN_SELECTOR_LEN; | |
1043 | ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; | |
1044 | return 0; | |
1045 | } | |
1046 | ||
1047 | if (pos[1] > RSN_SELECTOR_LEN + 2 && | |
1048 | RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { | |
1049 | ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; | |
1050 | ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; | |
1051 | return 0; | |
1052 | } | |
1053 | ||
6fc6879b JM |
1054 | if (pos[1] > RSN_SELECTOR_LEN + 2 && |
1055 | RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { | |
1056 | ie->igtk = pos + 2 + RSN_SELECTOR_LEN; | |
1057 | ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; | |
1058 | return 0; | |
1059 | } | |
6fc6879b | 1060 | |
25ef8529 JM |
1061 | #ifdef CONFIG_P2P |
1062 | if (pos[1] >= RSN_SELECTOR_LEN + 1 && | |
1063 | RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { | |
1064 | ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; | |
1065 | wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", | |
1066 | ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); | |
1067 | return 0; | |
1068 | } | |
1069 | ||
1070 | if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && | |
1071 | RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { | |
1072 | ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; | |
1073 | wpa_hexdump(MSG_DEBUG, | |
1074 | "WPA: IP Address Allocation in EAPOL-Key", | |
1075 | ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); | |
1076 | return 0; | |
1077 | } | |
1078 | #endif /* CONFIG_P2P */ | |
1079 | ||
f53aeff4 MV |
1080 | #ifdef CONFIG_OCV |
1081 | if (pos[1] > RSN_SELECTOR_LEN + 2 && | |
1082 | RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) { | |
1083 | ie->oci = pos + 2 + RSN_SELECTOR_LEN; | |
1084 | ie->oci_len = pos[1] - RSN_SELECTOR_LEN; | |
1085 | return 0; | |
1086 | } | |
1087 | #endif /* CONFIG_OCV */ | |
1088 | ||
6fc6879b JM |
1089 | return 0; |
1090 | } | |
1091 | ||
1092 | ||
1093 | /** | |
1094 | * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs | |
1095 | * @buf: Pointer to the Key Data buffer | |
1096 | * @len: Key Data Length | |
1097 | * @ie: Pointer to parsed IE data | |
1098 | * Returns: 0 on success, -1 on failure | |
1099 | */ | |
1100 | int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) | |
1101 | { | |
1102 | const u8 *pos, *end; | |
1103 | int ret = 0; | |
1104 | ||
1105 | os_memset(ie, 0, sizeof(*ie)); | |
1e72ba2e | 1106 | for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) { |
6fc6879b JM |
1107 | if (pos[0] == 0xdd && |
1108 | ((pos == buf + len - 1) || pos[1] == 0)) { | |
1109 | /* Ignore padding */ | |
1110 | break; | |
1111 | } | |
1e72ba2e | 1112 | if (2 + pos[1] > end - pos) { |
6fc6879b JM |
1113 | wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " |
1114 | "underflow (ie=%d len=%d pos=%d)", | |
1115 | pos[0], pos[1], (int) (pos - buf)); | |
1116 | wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", | |
1117 | buf, len); | |
1118 | ret = -1; | |
1119 | break; | |
1120 | } | |
1121 | if (*pos == WLAN_EID_RSN) { | |
1122 | ie->rsn_ie = pos; | |
1123 | ie->rsn_ie_len = pos[1] + 2; | |
4ec1fd8e | 1124 | #ifdef CONFIG_IEEE80211R_AP |
6fc6879b JM |
1125 | } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { |
1126 | ie->mdie = pos; | |
1127 | ie->mdie_len = pos[1] + 2; | |
0f857f43 JM |
1128 | } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { |
1129 | ie->ftie = pos; | |
1130 | ie->ftie_len = pos[1] + 2; | |
4ec1fd8e | 1131 | #endif /* CONFIG_IEEE80211R_AP */ |
6fc6879b JM |
1132 | } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { |
1133 | ret = wpa_parse_generic(pos, end, ie); | |
1134 | if (ret < 0) | |
1135 | break; | |
1136 | if (ret > 0) { | |
1137 | ret = 0; | |
1138 | break; | |
1139 | } | |
1140 | } else { | |
1141 | wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " | |
1142 | "Key Data IE", pos, 2 + pos[1]); | |
1143 | } | |
1144 | } | |
1145 | ||
1146 | return ret; | |
1147 | } | |
f3f7540e JM |
1148 | |
1149 | ||
1150 | int wpa_auth_uses_mfp(struct wpa_state_machine *sm) | |
1151 | { | |
1152 | return sm ? sm->mgmt_frame_prot : 0; | |
1153 | } | |
d8c8d857 JM |
1154 | |
1155 | ||
1e93e423 MV |
1156 | #ifdef CONFIG_OCV |
1157 | ||
1158 | void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv) | |
1159 | { | |
1160 | if (sm) | |
1161 | sm->ocv_enabled = ocv; | |
1162 | } | |
1163 | ||
1164 | ||
1165 | int wpa_auth_uses_ocv(struct wpa_state_machine *sm) | |
1166 | { | |
1167 | return sm ? sm->ocv_enabled : 0; | |
1168 | } | |
1169 | ||
1170 | #endif /* CONFIG_OCV */ | |
1171 | ||
1172 | ||
d8c8d857 JM |
1173 | #ifdef CONFIG_OWE |
1174 | u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, | |
1175 | u8 *pos, size_t max_len, | |
1176 | const u8 *req_ies, size_t req_ies_len) | |
1177 | { | |
1178 | int res; | |
8fc6d884 JM |
1179 | struct wpa_auth_config *conf; |
1180 | ||
1181 | if (!sm) | |
1182 | return pos; | |
1183 | conf = &sm->wpa_auth->conf; | |
a22e235f AP |
1184 | |
1185 | #ifdef CONFIG_TESTING_OPTIONS | |
1186 | if (conf->own_ie_override_len) { | |
1187 | if (max_len < conf->own_ie_override_len) | |
f5701cc6 | 1188 | return NULL; |
a22e235f AP |
1189 | wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", |
1190 | conf->own_ie_override, conf->own_ie_override_len); | |
1191 | os_memcpy(pos, conf->own_ie_override, | |
1192 | conf->own_ie_override_len); | |
1193 | return pos + conf->own_ie_override_len; | |
1194 | } | |
1195 | #endif /* CONFIG_TESTING_OPTIONS */ | |
d8c8d857 | 1196 | |
04924b28 | 1197 | res = wpa_write_rsn_ie(conf, pos, max_len, |
d90f10fa | 1198 | sm->pmksa ? sm->pmksa->pmkid : NULL); |
d8c8d857 JM |
1199 | if (res < 0) |
1200 | return pos; | |
1201 | return pos + res; | |
1202 | } | |
1203 | #endif /* CONFIG_OWE */ | |
831d8c9c JM |
1204 | |
1205 | ||
1206 | #ifdef CONFIG_FILS | |
1207 | u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm, | |
1208 | u8 *pos, size_t max_len, | |
1209 | const u8 *req_ies, size_t req_ies_len) | |
1210 | { | |
1211 | int res; | |
1212 | ||
1213 | if (!sm || | |
1214 | sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 | | |
1215 | WPA_KEY_MGMT_FT_FILS_SHA384)) | |
1216 | return pos; | |
1217 | ||
1218 | res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL); | |
1219 | if (res < 0) | |
1220 | return pos; | |
1221 | return pos + res; | |
1222 | } | |
1223 | #endif /* CONFIG_FILS */ |