]>
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 */ |
862aac1f AW |
300 | if (conf->extended_key_id) |
301 | capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; | |
6fc6879b JM |
302 | WPA_PUT_LE16(pos, capab); |
303 | pos += 2; | |
304 | ||
305 | if (pmkid) { | |
1e72ba2e | 306 | if (2 + PMKID_LEN > buf + len - pos) |
6fc6879b JM |
307 | return -1; |
308 | /* PMKID Count */ | |
309 | WPA_PUT_LE16(pos, 1); | |
310 | pos += 2; | |
311 | os_memcpy(pos, pmkid, PMKID_LEN); | |
312 | pos += PMKID_LEN; | |
313 | } | |
314 | ||
44fa5e74 JM |
315 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION && |
316 | conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) { | |
1e72ba2e | 317 | if (2 + 4 > buf + len - pos) |
6fc6879b JM |
318 | return -1; |
319 | if (pmkid == NULL) { | |
320 | /* PMKID Count */ | |
321 | WPA_PUT_LE16(pos, 0); | |
322 | pos += 2; | |
323 | } | |
324 | ||
325 | /* Management Group Cipher Suite */ | |
8dd9f9cd JM |
326 | switch (conf->group_mgmt_cipher) { |
327 | case WPA_CIPHER_AES_128_CMAC: | |
328 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); | |
329 | break; | |
330 | case WPA_CIPHER_BIP_GMAC_128: | |
331 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128); | |
332 | break; | |
333 | case WPA_CIPHER_BIP_GMAC_256: | |
334 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256); | |
335 | break; | |
336 | case WPA_CIPHER_BIP_CMAC_256: | |
337 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256); | |
338 | break; | |
339 | default: | |
340 | wpa_printf(MSG_DEBUG, | |
341 | "Invalid group management cipher (0x%x)", | |
342 | conf->group_mgmt_cipher); | |
343 | return -1; | |
344 | } | |
6fc6879b JM |
345 | pos += RSN_SELECTOR_LEN; |
346 | } | |
6fc6879b | 347 | |
cd9fc786 JM |
348 | #ifdef CONFIG_RSN_TESTING |
349 | if (rsn_testing) { | |
350 | /* | |
351 | * Fill in any defined fields and add extra data to the end of | |
352 | * the element. | |
353 | */ | |
354 | int pmkid_count_set = pmkid != NULL; | |
355 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) | |
356 | pmkid_count_set = 1; | |
357 | /* PMKID Count */ | |
358 | WPA_PUT_LE16(pos, 0); | |
359 | pos += 2; | |
360 | if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { | |
361 | /* Management Group Cipher Suite */ | |
362 | RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); | |
363 | pos += RSN_SELECTOR_LEN; | |
364 | } | |
365 | ||
366 | os_memset(pos, 0x12, 17); | |
367 | pos += 17; | |
368 | } | |
369 | #endif /* CONFIG_RSN_TESTING */ | |
370 | ||
6fc6879b JM |
371 | hdr->len = (pos - buf) - 2; |
372 | ||
373 | return pos - buf; | |
374 | } | |
375 | ||
376 | ||
3134bb13 JM |
377 | int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) |
378 | { | |
379 | u8 *pos = buf; | |
380 | ||
381 | if (conf->sae_pwe != 1 && conf->sae_pwe != 2) | |
382 | return 0; /* no supported extended RSN capabilities */ | |
383 | ||
384 | if (len < 3) | |
385 | return -1; | |
386 | ||
387 | *pos++ = WLAN_EID_RSNX; | |
388 | *pos++ = 1; | |
389 | /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is | |
390 | * used for now */ | |
391 | *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E); | |
392 | ||
393 | return pos - buf; | |
394 | } | |
395 | ||
396 | ||
a14896e8 JM |
397 | static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid) |
398 | { | |
399 | u8 *len; | |
400 | u16 capab; | |
401 | ||
402 | *eid++ = WLAN_EID_VENDOR_SPECIFIC; | |
403 | len = eid++; /* to be filled */ | |
404 | WPA_PUT_BE24(eid, OUI_WFA); | |
405 | eid += 3; | |
406 | *eid++ = HS20_OSEN_OUI_TYPE; | |
407 | ||
408 | /* Group Data Cipher Suite */ | |
409 | RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); | |
410 | eid += RSN_SELECTOR_LEN; | |
411 | ||
412 | /* Pairwise Cipher Suite Count and List */ | |
413 | WPA_PUT_LE16(eid, 1); | |
414 | eid += 2; | |
415 | RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP); | |
416 | eid += RSN_SELECTOR_LEN; | |
417 | ||
418 | /* AKM Suite Count and List */ | |
419 | WPA_PUT_LE16(eid, 1); | |
420 | eid += 2; | |
421 | RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN); | |
422 | eid += RSN_SELECTOR_LEN; | |
423 | ||
424 | /* RSN Capabilities */ | |
425 | capab = 0; | |
426 | if (conf->wmm_enabled) { | |
427 | /* 4 PTKSA replay counters when using WMM */ | |
428 | capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); | |
429 | } | |
a14896e8 JM |
430 | if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { |
431 | capab |= WPA_CAPABILITY_MFPC; | |
432 | if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) | |
433 | capab |= WPA_CAPABILITY_MFPR; | |
434 | } | |
875ab60d MV |
435 | #ifdef CONFIG_OCV |
436 | if (conf->ocv) | |
437 | capab |= WPA_CAPABILITY_OCVC; | |
438 | #endif /* CONFIG_OCV */ | |
a14896e8 JM |
439 | WPA_PUT_LE16(eid, capab); |
440 | eid += 2; | |
441 | ||
442 | *len = eid - len - 1; | |
443 | ||
444 | return eid; | |
445 | } | |
446 | ||
447 | ||
6fc6879b JM |
448 | int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) |
449 | { | |
450 | u8 *pos, buf[128]; | |
451 | int res; | |
452 | ||
bc02843e JM |
453 | #ifdef CONFIG_TESTING_OPTIONS |
454 | if (wpa_auth->conf.own_ie_override_len) { | |
455 | wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", | |
456 | wpa_auth->conf.own_ie_override, | |
457 | wpa_auth->conf.own_ie_override_len); | |
458 | os_free(wpa_auth->wpa_ie); | |
459 | wpa_auth->wpa_ie = | |
460 | os_malloc(wpa_auth->conf.own_ie_override_len); | |
461 | if (wpa_auth->wpa_ie == NULL) | |
462 | return -1; | |
463 | os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override, | |
464 | wpa_auth->conf.own_ie_override_len); | |
465 | wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len; | |
466 | return 0; | |
467 | } | |
468 | #endif /* CONFIG_TESTING_OPTIONS */ | |
469 | ||
6fc6879b JM |
470 | pos = buf; |
471 | ||
a14896e8 JM |
472 | if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) { |
473 | pos = wpa_write_osen(&wpa_auth->conf, pos); | |
474 | } | |
6fc6879b JM |
475 | if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { |
476 | res = wpa_write_rsn_ie(&wpa_auth->conf, | |
477 | pos, buf + sizeof(buf) - pos, NULL); | |
478 | if (res < 0) | |
479 | return res; | |
480 | pos += res; | |
3134bb13 JM |
481 | res = wpa_write_rsnxe(&wpa_auth->conf, pos, |
482 | buf + sizeof(buf) - pos); | |
483 | if (res < 0) | |
484 | return res; | |
485 | pos += res; | |
6fc6879b | 486 | } |
4ec1fd8e | 487 | #ifdef CONFIG_IEEE80211R_AP |
0bf927a0 | 488 | if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { |
6fc6879b JM |
489 | res = wpa_write_mdie(&wpa_auth->conf, pos, |
490 | buf + sizeof(buf) - pos); | |
491 | if (res < 0) | |
492 | return res; | |
493 | pos += res; | |
494 | } | |
4ec1fd8e | 495 | #endif /* CONFIG_IEEE80211R_AP */ |
6fc6879b JM |
496 | if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { |
497 | res = wpa_write_wpa_ie(&wpa_auth->conf, | |
498 | pos, buf + sizeof(buf) - pos); | |
499 | if (res < 0) | |
500 | return res; | |
501 | pos += res; | |
502 | } | |
503 | ||
504 | os_free(wpa_auth->wpa_ie); | |
505 | wpa_auth->wpa_ie = os_malloc(pos - buf); | |
506 | if (wpa_auth->wpa_ie == NULL) | |
507 | return -1; | |
508 | os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); | |
509 | wpa_auth->wpa_ie_len = pos - buf; | |
510 | ||
511 | return 0; | |
512 | } | |
513 | ||
514 | ||
515 | u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, | |
516 | const u8 *data2, size_t data2_len) | |
517 | { | |
518 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | |
519 | *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; | |
520 | RSN_SELECTOR_PUT(pos, kde); | |
521 | pos += RSN_SELECTOR_LEN; | |
522 | os_memcpy(pos, data, data_len); | |
523 | pos += data_len; | |
524 | if (data2) { | |
525 | os_memcpy(pos, data2, data2_len); | |
526 | pos += data2_len; | |
527 | } | |
528 | return pos; | |
529 | } | |
530 | ||
531 | ||
bf98f7f3 JM |
532 | struct wpa_auth_okc_iter_data { |
533 | struct rsn_pmksa_cache_entry *pmksa; | |
534 | const u8 *aa; | |
535 | const u8 *spa; | |
536 | const u8 *pmkid; | |
537 | }; | |
538 | ||
539 | ||
540 | static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) | |
541 | { | |
542 | struct wpa_auth_okc_iter_data *data = ctx; | |
543 | data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, | |
544 | data->pmkid); | |
545 | if (data->pmksa) | |
546 | return 1; | |
547 | return 0; | |
548 | } | |
549 | ||
550 | ||
6fc6879b | 551 | int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, |
2c129a1b | 552 | struct wpa_state_machine *sm, int freq, |
6fc6879b | 553 | const u8 *wpa_ie, size_t wpa_ie_len, |
d3516cad | 554 | const u8 *rsnxe, size_t rsnxe_len, |
09368515 JM |
555 | const u8 *mdie, size_t mdie_len, |
556 | const u8 *owe_dh, size_t owe_dh_len) | |
6fc6879b | 557 | { |
862aac1f | 558 | struct wpa_auth_config *conf = &wpa_auth->conf; |
6fc6879b JM |
559 | struct wpa_ie_data data; |
560 | int ciphers, key_mgmt, res, version; | |
561 | u32 selector; | |
562 | size_t i; | |
bf98f7f3 | 563 | const u8 *pmkid = NULL; |
6fc6879b JM |
564 | |
565 | if (wpa_auth == NULL || sm == NULL) | |
566 | return WPA_NOT_ENABLED; | |
567 | ||
568 | if (wpa_ie == NULL || wpa_ie_len < 1) | |
569 | return WPA_INVALID_IE; | |
570 | ||
571 | if (wpa_ie[0] == WLAN_EID_RSN) | |
572 | version = WPA_PROTO_RSN; | |
573 | else | |
574 | version = WPA_PROTO_WPA; | |
575 | ||
2100a768 JM |
576 | if (!(wpa_auth->conf.wpa & version)) { |
577 | wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, | |
578 | version, MAC2STR(sm->addr)); | |
579 | return WPA_INVALID_PROTO; | |
580 | } | |
581 | ||
6fc6879b JM |
582 | if (version == WPA_PROTO_RSN) { |
583 | res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); | |
2c129a1b LD |
584 | if (!data.has_pairwise) |
585 | data.pairwise_cipher = wpa_default_rsn_cipher(freq); | |
586 | if (!data.has_group) | |
587 | data.group_cipher = wpa_default_rsn_cipher(freq); | |
6fc6879b | 588 | |
bb35e2d2 JD |
589 | if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie && |
590 | !wpa_key_mgmt_only_ft(data.key_mgmt)) { | |
591 | /* Workaround for some HP and Epson printers that seem | |
592 | * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP | |
593 | * advertised RSNE to Association Request frame. */ | |
594 | wpa_printf(MSG_DEBUG, | |
595 | "RSN: FT set in RSNE AKM but MDE is missing from " | |
596 | MACSTR | |
597 | " - ignore FT AKM(s) because there's also a non-FT AKM", | |
598 | MAC2STR(sm->addr)); | |
599 | data.key_mgmt &= ~WPA_KEY_MGMT_FT; | |
600 | } | |
601 | ||
6fc6879b JM |
602 | selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; |
603 | if (0) { | |
604 | } | |
5e3b5197 JM |
605 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) |
606 | selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; | |
666497c8 JM |
607 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) |
608 | selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; | |
c30ed45f | 609 | #ifdef CONFIG_FILS |
4ec1fd8e | 610 | #ifdef CONFIG_IEEE80211R_AP |
c30ed45f JM |
611 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) |
612 | selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; | |
613 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) | |
614 | selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; | |
4ec1fd8e | 615 | #endif /* CONFIG_IEEE80211R_AP */ |
c30ed45f JM |
616 | else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) |
617 | selector = RSN_AUTH_KEY_MGMT_FILS_SHA384; | |
618 | else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) | |
619 | selector = RSN_AUTH_KEY_MGMT_FILS_SHA256; | |
620 | #endif /* CONFIG_FILS */ | |
4ec1fd8e | 621 | #ifdef CONFIG_IEEE80211R_AP |
c22bb5bb JM |
622 | #ifdef CONFIG_SHA384 |
623 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) | |
624 | selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; | |
625 | #endif /* CONFIG_SHA384 */ | |
6fc6879b JM |
626 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) |
627 | selector = RSN_AUTH_KEY_MGMT_FT_802_1X; | |
628 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) | |
629 | selector = RSN_AUTH_KEY_MGMT_FT_PSK; | |
4ec1fd8e | 630 | #endif /* CONFIG_IEEE80211R_AP */ |
56586197 JM |
631 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) |
632 | selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; | |
633 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) | |
634 | selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; | |
c10347f2 JM |
635 | #ifdef CONFIG_SAE |
636 | else if (data.key_mgmt & WPA_KEY_MGMT_SAE) | |
637 | selector = RSN_AUTH_KEY_MGMT_SAE; | |
638 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) | |
639 | selector = RSN_AUTH_KEY_MGMT_FT_SAE; | |
640 | #endif /* CONFIG_SAE */ | |
6fc6879b JM |
641 | else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) |
642 | selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
643 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK) | |
644 | selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; | |
a1ea1b45 JM |
645 | #ifdef CONFIG_OWE |
646 | else if (data.key_mgmt & WPA_KEY_MGMT_OWE) | |
647 | selector = RSN_AUTH_KEY_MGMT_OWE; | |
648 | #endif /* CONFIG_OWE */ | |
567da5bb JM |
649 | #ifdef CONFIG_DPP |
650 | else if (data.key_mgmt & WPA_KEY_MGMT_DPP) | |
651 | selector = RSN_AUTH_KEY_MGMT_DPP; | |
652 | #endif /* CONFIG_DPP */ | |
8d660a4b JM |
653 | #ifdef CONFIG_HS20 |
654 | else if (data.key_mgmt & WPA_KEY_MGMT_OSEN) | |
655 | selector = RSN_AUTH_KEY_MGMT_OSEN; | |
656 | #endif /* CONFIG_HS20 */ | |
6fc6879b JM |
657 | wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; |
658 | ||
c3550295 JM |
659 | selector = wpa_cipher_to_suite(WPA_PROTO_RSN, |
660 | data.pairwise_cipher); | |
661 | if (!selector) | |
6fc6879b | 662 | selector = RSN_CIPHER_SUITE_CCMP; |
6fc6879b JM |
663 | wpa_auth->dot11RSNAPairwiseCipherSelected = selector; |
664 | ||
c3550295 JM |
665 | selector = wpa_cipher_to_suite(WPA_PROTO_RSN, |
666 | data.group_cipher); | |
667 | if (!selector) | |
6fc6879b | 668 | selector = RSN_CIPHER_SUITE_CCMP; |
6fc6879b JM |
669 | wpa_auth->dot11RSNAGroupCipherSelected = selector; |
670 | } else { | |
671 | res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); | |
672 | ||
673 | selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
674 | if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) | |
675 | selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; | |
676 | else if (data.key_mgmt & WPA_KEY_MGMT_PSK) | |
677 | selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; | |
678 | wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; | |
679 | ||
c3550295 JM |
680 | selector = wpa_cipher_to_suite(WPA_PROTO_WPA, |
681 | data.pairwise_cipher); | |
682 | if (!selector) | |
683 | selector = RSN_CIPHER_SUITE_TKIP; | |
6fc6879b JM |
684 | wpa_auth->dot11RSNAPairwiseCipherSelected = selector; |
685 | ||
c3550295 JM |
686 | selector = wpa_cipher_to_suite(WPA_PROTO_WPA, |
687 | data.group_cipher); | |
688 | if (!selector) | |
6fc6879b | 689 | selector = WPA_CIPHER_SUITE_TKIP; |
6fc6879b JM |
690 | wpa_auth->dot11RSNAGroupCipherSelected = selector; |
691 | } | |
692 | if (res) { | |
693 | wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " | |
694 | MACSTR " (res=%d)", MAC2STR(sm->addr), res); | |
695 | wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); | |
696 | return WPA_INVALID_IE; | |
697 | } | |
698 | ||
699 | if (data.group_cipher != wpa_auth->conf.wpa_group) { | |
700 | wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " | |
701 | MACSTR, data.group_cipher, MAC2STR(sm->addr)); | |
702 | return WPA_INVALID_GROUP; | |
703 | } | |
704 | ||
705 | key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; | |
706 | if (!key_mgmt) { | |
707 | wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " | |
708 | MACSTR, data.key_mgmt, MAC2STR(sm->addr)); | |
709 | return WPA_INVALID_AKMP; | |
710 | } | |
711 | if (0) { | |
712 | } | |
5e3b5197 JM |
713 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) |
714 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; | |
666497c8 JM |
715 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) |
716 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B; | |
c30ed45f | 717 | #ifdef CONFIG_FILS |
4ec1fd8e | 718 | #ifdef CONFIG_IEEE80211R_AP |
c30ed45f JM |
719 | else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) |
720 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384; | |
721 | else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) | |
722 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256; | |
4ec1fd8e | 723 | #endif /* CONFIG_IEEE80211R_AP */ |
c30ed45f JM |
724 | else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) |
725 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384; | |
726 | else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) | |
727 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256; | |
728 | #endif /* CONFIG_FILS */ | |
4ec1fd8e | 729 | #ifdef CONFIG_IEEE80211R_AP |
c22bb5bb JM |
730 | #ifdef CONFIG_SHA384 |
731 | else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) | |
732 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384; | |
733 | #endif /* CONFIG_SHA384 */ | |
6fc6879b JM |
734 | else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) |
735 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; | |
736 | else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) | |
737 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; | |
4ec1fd8e | 738 | #endif /* CONFIG_IEEE80211R_AP */ |
56586197 JM |
739 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) |
740 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; | |
741 | else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) | |
742 | sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; | |
c10347f2 JM |
743 | #ifdef CONFIG_SAE |
744 | else if (key_mgmt & WPA_KEY_MGMT_SAE) | |
745 | sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; | |
746 | else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) | |
747 | sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; | |
748 | #endif /* CONFIG_SAE */ | |
6fc6879b JM |
749 | else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) |
750 | sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
a1ea1b45 JM |
751 | #ifdef CONFIG_OWE |
752 | else if (key_mgmt & WPA_KEY_MGMT_OWE) | |
753 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OWE; | |
754 | #endif /* CONFIG_OWE */ | |
567da5bb JM |
755 | #ifdef CONFIG_DPP |
756 | else if (key_mgmt & WPA_KEY_MGMT_DPP) | |
757 | sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP; | |
758 | #endif /* CONFIG_DPP */ | |
8d660a4b JM |
759 | #ifdef CONFIG_HS20 |
760 | else if (key_mgmt & WPA_KEY_MGMT_OSEN) | |
761 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; | |
762 | #endif /* CONFIG_HS20 */ | |
6fc6879b JM |
763 | else |
764 | sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; | |
765 | ||
766 | if (version == WPA_PROTO_RSN) | |
767 | ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; | |
768 | else | |
769 | ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; | |
770 | if (!ciphers) { | |
771 | wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " | |
772 | "from " MACSTR, | |
773 | version == WPA_PROTO_RSN ? "RSN" : "WPA", | |
774 | data.pairwise_cipher, MAC2STR(sm->addr)); | |
775 | return WPA_INVALID_PAIRWISE; | |
776 | } | |
777 | ||
70f8cc8e | 778 | if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { |
0b60b0aa | 779 | if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { |
6fc6879b JM |
780 | wpa_printf(MSG_DEBUG, "Management frame protection " |
781 | "required, but client did not enable it"); | |
782 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
783 | } | |
784 | ||
8dd9f9cd JM |
785 | if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher) |
786 | { | |
6fc6879b JM |
787 | wpa_printf(MSG_DEBUG, "Unsupported management group " |
788 | "cipher %d", data.mgmt_group_cipher); | |
789 | return WPA_INVALID_MGMT_GROUP_CIPHER; | |
790 | } | |
791 | } | |
792 | ||
ba3d435f JM |
793 | #ifdef CONFIG_SAE |
794 | if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL && | |
74eebe93 | 795 | wpa_auth->conf.sae_require_mfp && |
ba3d435f JM |
796 | wpa_key_mgmt_sae(sm->wpa_key_mgmt) && |
797 | !(data.capabilities & WPA_CAPABILITY_MFPC)) { | |
798 | wpa_printf(MSG_DEBUG, | |
799 | "Management frame protection required with SAE, but client did not enable it"); | |
800 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
801 | } | |
802 | #endif /* CONFIG_SAE */ | |
803 | ||
1e93e423 MV |
804 | #ifdef CONFIG_OCV |
805 | if ((data.capabilities & WPA_CAPABILITY_OCVC) && | |
806 | !(data.capabilities & WPA_CAPABILITY_MFPC)) { | |
807 | wpa_printf(MSG_DEBUG, | |
808 | "Management frame protection required with OCV, but client did not enable it"); | |
809 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
810 | } | |
811 | wpa_auth_set_ocv(sm, wpa_auth->conf.ocv && | |
812 | (data.capabilities & WPA_CAPABILITY_OCVC)); | |
813 | #endif /* CONFIG_OCV */ | |
814 | ||
70f8cc8e | 815 | if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || |
0b60b0aa | 816 | !(data.capabilities & WPA_CAPABILITY_MFPC)) |
6fc6879b JM |
817 | sm->mgmt_frame_prot = 0; |
818 | else | |
819 | sm->mgmt_frame_prot = 1; | |
02b38d0a JM |
820 | |
821 | if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) { | |
822 | wpa_printf(MSG_DEBUG, | |
823 | "Management frame protection cannot use TKIP"); | |
824 | return WPA_MGMT_FRAME_PROTECTION_VIOLATION; | |
825 | } | |
6fc6879b | 826 | |
4ec1fd8e | 827 | #ifdef CONFIG_IEEE80211R_AP |
56586197 | 828 | if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { |
6fc6879b JM |
829 | if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { |
830 | wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " | |
831 | "MDIE not included"); | |
832 | return WPA_INVALID_MDIE; | |
833 | } | |
834 | if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, | |
835 | MOBILITY_DOMAIN_ID_LEN) != 0) { | |
836 | wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " | |
837 | "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); | |
838 | return WPA_INVALID_MDIE; | |
839 | } | |
209dad06 WG |
840 | } else if (mdie != NULL) { |
841 | wpa_printf(MSG_DEBUG, | |
842 | "RSN: Trying to use non-FT AKM suite, but MDIE included"); | |
843 | return WPA_INVALID_AKMP; | |
6fc6879b | 844 | } |
4ec1fd8e | 845 | #endif /* CONFIG_IEEE80211R_AP */ |
6fc6879b | 846 | |
09368515 JM |
847 | #ifdef CONFIG_OWE |
848 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && !owe_dh) { | |
849 | wpa_printf(MSG_DEBUG, | |
850 | "OWE: No Diffie-Hellman Parameter element"); | |
851 | return WPA_INVALID_AKMP; | |
852 | } | |
16a4e931 JM |
853 | #ifdef CONFIG_DPP |
854 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && owe_dh) { | |
855 | /* Diffie-Hellman Parameter element can be used with DPP as | |
856 | * well, so allow this to proceed. */ | |
857 | } else | |
858 | #endif /* CONFIG_DPP */ | |
09368515 JM |
859 | if (sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE && owe_dh) { |
860 | wpa_printf(MSG_DEBUG, | |
861 | "OWE: Unexpected Diffie-Hellman Parameter element with non-OWE AKM"); | |
862 | return WPA_INVALID_AKMP; | |
863 | } | |
864 | #endif /* CONFIG_OWE */ | |
865 | ||
edbd2a19 JM |
866 | sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0); |
867 | if (sm->pairwise < 0) | |
868 | return WPA_INVALID_PAIRWISE; | |
6fc6879b JM |
869 | |
870 | /* TODO: clear WPA/WPA2 state if STA changes from one to another */ | |
871 | if (wpa_ie[0] == WLAN_EID_RSN) | |
872 | sm->wpa = WPA_VERSION_WPA2; | |
873 | else | |
874 | sm->wpa = WPA_VERSION_WPA; | |
875 | ||
36536639 JM |
876 | #if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS) |
877 | if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 || | |
878 | sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) && | |
879 | (sm->auth_alg == WLAN_AUTH_FILS_SK || | |
880 | sm->auth_alg == WLAN_AUTH_FILS_SK_PFS || | |
881 | sm->auth_alg == WLAN_AUTH_FILS_PK) && | |
882 | (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid || | |
883 | os_memcmp_const(data.pmkid, sm->pmk_r1_name, | |
884 | WPA_PMK_NAME_LEN) != 0)) { | |
885 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
886 | "No PMKR1Name match for FILS+FT"); | |
887 | return WPA_INVALID_PMKID; | |
888 | } | |
889 | #endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */ | |
890 | ||
bf98f7f3 | 891 | sm->pmksa = NULL; |
6fc6879b JM |
892 | for (i = 0; i < data.num_pmkid; i++) { |
893 | wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", | |
894 | &data.pmkid[i * PMKID_LEN], PMKID_LEN); | |
4bb081f1 JM |
895 | sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, |
896 | &data.pmkid[i * PMKID_LEN]); | |
6fc6879b | 897 | if (sm->pmksa) { |
bf98f7f3 JM |
898 | pmkid = sm->pmksa->pmkid; |
899 | break; | |
900 | } | |
901 | } | |
902 | for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && | |
903 | i < data.num_pmkid; i++) { | |
904 | struct wpa_auth_okc_iter_data idata; | |
905 | idata.pmksa = NULL; | |
906 | idata.aa = wpa_auth->addr; | |
907 | idata.spa = sm->addr; | |
908 | idata.pmkid = &data.pmkid[i * PMKID_LEN]; | |
909 | wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); | |
910 | if (idata.pmksa) { | |
6fc6879b | 911 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, |
bf98f7f3 JM |
912 | "OKC match for PMKID"); |
913 | sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, | |
914 | idata.pmksa, | |
915 | wpa_auth->addr, | |
916 | idata.pmkid); | |
917 | pmkid = idata.pmkid; | |
6fc6879b JM |
918 | break; |
919 | } | |
920 | } | |
4a9d0ebe | 921 | if (sm->pmksa && pmkid) { |
8e44c192 | 922 | struct vlan_description *vlan; |
1889af2e | 923 | |
8e44c192 | 924 | vlan = sm->pmksa->vlan_desc; |
bf98f7f3 | 925 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, |
8e44c192 | 926 | "PMKID found from PMKSA cache eap_type=%d vlan=%d%s", |
bf98f7f3 | 927 | sm->pmksa->eap_type_authsrv, |
8e44c192 MB |
928 | vlan ? vlan->untagged : 0, |
929 | (vlan && vlan->tagged[0]) ? "+" : ""); | |
bf98f7f3 JM |
930 | os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); |
931 | } | |
6fc6879b | 932 | |
458d8984 AP |
933 | #ifdef CONFIG_SAE |
934 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid && | |
935 | !sm->pmksa) { | |
936 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
937 | "No PMKSA cache entry found for SAE"); | |
938 | return WPA_INVALID_PMKID; | |
939 | } | |
940 | #endif /* CONFIG_SAE */ | |
941 | ||
567da5bb JM |
942 | #ifdef CONFIG_DPP |
943 | if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) { | |
944 | wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, | |
945 | "No PMKSA cache entry found for DPP"); | |
946 | return WPA_INVALID_PMKID; | |
947 | } | |
948 | #endif /* CONFIG_DPP */ | |
949 | ||
862aac1f AW |
950 | if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 && |
951 | sm->pairwise != WPA_CIPHER_TKIP && | |
952 | (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { | |
953 | sm->use_ext_key_id = TRUE; | |
954 | if (conf->extended_key_id == 2 && | |
955 | !wpa_key_mgmt_ft(sm->wpa_key_mgmt) && | |
956 | !wpa_key_mgmt_fils(sm->wpa_key_mgmt)) | |
957 | sm->keyidx_active = 1; | |
958 | else | |
959 | sm->keyidx_active = 0; | |
960 | wpa_printf(MSG_DEBUG, | |
961 | "RSN: Extended Key ID supported (start with %d)", | |
962 | sm->keyidx_active); | |
963 | } else { | |
964 | sm->use_ext_key_id = FALSE; | |
965 | } | |
966 | ||
6fc6879b JM |
967 | if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { |
968 | os_free(sm->wpa_ie); | |
969 | sm->wpa_ie = os_malloc(wpa_ie_len); | |
970 | if (sm->wpa_ie == NULL) | |
971 | return WPA_ALLOC_FAIL; | |
972 | } | |
973 | os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); | |
974 | sm->wpa_ie_len = wpa_ie_len; | |
975 | ||
d3516cad JM |
976 | if (rsnxe && rsnxe_len) { |
977 | if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) { | |
978 | os_free(sm->rsnxe); | |
979 | sm->rsnxe = os_malloc(rsnxe_len); | |
980 | if (!sm->rsnxe) | |
981 | return WPA_ALLOC_FAIL; | |
982 | } | |
983 | os_memcpy(sm->rsnxe, rsnxe, rsnxe_len); | |
984 | sm->rsnxe_len = rsnxe_len; | |
985 | } else { | |
986 | os_free(sm->rsnxe); | |
987 | sm->rsnxe = NULL; | |
988 | sm->rsnxe_len = 0; | |
989 | } | |
990 | ||
6fc6879b JM |
991 | return WPA_IE_OK; |
992 | } | |
993 | ||
994 | ||
a14896e8 JM |
995 | #ifdef CONFIG_HS20 |
996 | int wpa_validate_osen(struct wpa_authenticator *wpa_auth, | |
997 | struct wpa_state_machine *sm, | |
998 | const u8 *osen_ie, size_t osen_ie_len) | |
999 | { | |
1000 | if (wpa_auth == NULL || sm == NULL) | |
1001 | return -1; | |
1002 | ||
1003 | /* TODO: parse OSEN element */ | |
1004 | sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; | |
1005 | sm->mgmt_frame_prot = 1; | |
1006 | sm->pairwise = WPA_CIPHER_CCMP; | |
1007 | sm->wpa = WPA_VERSION_WPA2; | |
1008 | ||
1009 | if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) { | |
1010 | os_free(sm->wpa_ie); | |
1011 | sm->wpa_ie = os_malloc(osen_ie_len); | |
1012 | if (sm->wpa_ie == NULL) | |
1013 | return -1; | |
1014 | } | |
1015 | ||
1016 | os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len); | |
1017 | sm->wpa_ie_len = osen_ie_len; | |
1018 | ||
1019 | return 0; | |
1020 | } | |
1021 | ||
1022 | #endif /* CONFIG_HS20 */ | |
1023 | ||
1024 | ||
f3f7540e JM |
1025 | int wpa_auth_uses_mfp(struct wpa_state_machine *sm) |
1026 | { | |
1027 | return sm ? sm->mgmt_frame_prot : 0; | |
1028 | } | |
d8c8d857 JM |
1029 | |
1030 | ||
1e93e423 MV |
1031 | #ifdef CONFIG_OCV |
1032 | ||
1033 | void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv) | |
1034 | { | |
1035 | if (sm) | |
1036 | sm->ocv_enabled = ocv; | |
1037 | } | |
1038 | ||
1039 | ||
1040 | int wpa_auth_uses_ocv(struct wpa_state_machine *sm) | |
1041 | { | |
1042 | return sm ? sm->ocv_enabled : 0; | |
1043 | } | |
1044 | ||
1045 | #endif /* CONFIG_OCV */ | |
1046 | ||
1047 | ||
d8c8d857 JM |
1048 | #ifdef CONFIG_OWE |
1049 | u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm, | |
1050 | u8 *pos, size_t max_len, | |
1051 | const u8 *req_ies, size_t req_ies_len) | |
1052 | { | |
1053 | int res; | |
8fc6d884 JM |
1054 | struct wpa_auth_config *conf; |
1055 | ||
1056 | if (!sm) | |
1057 | return pos; | |
1058 | conf = &sm->wpa_auth->conf; | |
a22e235f AP |
1059 | |
1060 | #ifdef CONFIG_TESTING_OPTIONS | |
1061 | if (conf->own_ie_override_len) { | |
1062 | if (max_len < conf->own_ie_override_len) | |
f5701cc6 | 1063 | return NULL; |
a22e235f AP |
1064 | wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing", |
1065 | conf->own_ie_override, conf->own_ie_override_len); | |
1066 | os_memcpy(pos, conf->own_ie_override, | |
1067 | conf->own_ie_override_len); | |
1068 | return pos + conf->own_ie_override_len; | |
1069 | } | |
1070 | #endif /* CONFIG_TESTING_OPTIONS */ | |
d8c8d857 | 1071 | |
04924b28 | 1072 | res = wpa_write_rsn_ie(conf, pos, max_len, |
d90f10fa | 1073 | sm->pmksa ? sm->pmksa->pmkid : NULL); |
d8c8d857 JM |
1074 | if (res < 0) |
1075 | return pos; | |
1076 | return pos + res; | |
1077 | } | |
1078 | #endif /* CONFIG_OWE */ | |
831d8c9c JM |
1079 | |
1080 | ||
1081 | #ifdef CONFIG_FILS | |
1082 | u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm, | |
1083 | u8 *pos, size_t max_len, | |
1084 | const u8 *req_ies, size_t req_ies_len) | |
1085 | { | |
1086 | int res; | |
1087 | ||
1088 | if (!sm || | |
1089 | sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 | | |
1090 | WPA_KEY_MGMT_FT_FILS_SHA384)) | |
1091 | return pos; | |
1092 | ||
1093 | res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL); | |
1094 | if (res < 0) | |
1095 | return pos; | |
1096 | return pos + res; | |
1097 | } | |
1098 | #endif /* CONFIG_FILS */ |