1 /*
2 * wpa_supplicant - WPA/RSN IE and KDE processing
3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14 #ifdef ESP_SUPPLICANT
15
16 #include "utils/includes.h"
17
18 #include "utils/common.h"
19 #include "rsn_supp/wpa.h"
20 #include "common/ieee802_11_defs.h"
21 #include "rsn_supp/wpa_ie.h"
22 #include "rsn_supp/pmksa_cache.h"
23
24 /**
25 * wpa_parse_wpa_ie - Parse WPA/RSN IE
26 * @wpa_ie: Pointer to WPA or RSN IE
27 * @wpa_ie_len: Length of the WPA/RSN IE
28 * @data: Pointer to data area for parsing results
29 * Returns: 0 on success, -1 on failure
30 *
31 * Parse the contents of WPA or RSN IE and write the parsed data into data.
32 */
wpa_parse_wpa_ie(const u8 * wpa_ie,size_t wpa_ie_len,struct wpa_ie_data * data)33 int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
34 struct wpa_ie_data *data)
35 {
36 if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) {
37 return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
38 } else if (wpa_ie_len >=1 && wpa_ie[0] == WLAN_EID_RSNX){
39 return wpa_parse_wpa_ie_rsnxe(wpa_ie, wpa_ie_len, data);
40 } else if (wpa_ie[0] == WLAN_EID_WAPI) {
41 return 0;
42 }
43
44 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
45 }
46
47
wpa_gen_wpa_ie_wpa(u8 * wpa_ie,size_t wpa_ie_len,int pairwise_cipher,int group_cipher,int key_mgmt)48 static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
49 int pairwise_cipher, int group_cipher,
50 int key_mgmt)
51 {
52 u8 *pos;
53 struct wpa_ie_hdr *hdr;
54 u32 suite;
55
56 if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
57 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
58 return -1;
59
60 hdr = (struct wpa_ie_hdr *) wpa_ie;
61 hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
62 RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
63 WPA_PUT_LE16(hdr->version, WPA_VERSION);
64 pos = (u8 *) (hdr + 1);
65
66 suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
67 if (suite == 0) {
68 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
69 group_cipher);
70 return -1;
71 }
72 RSN_SELECTOR_PUT(pos, suite);
73 pos += WPA_SELECTOR_LEN;
74
75 *pos++ = 1;
76 *pos++ = 0;
77 suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
78 if (suite == 0 ||
79 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
80 pairwise_cipher != WPA_CIPHER_NONE)) {
81 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
82 pairwise_cipher);
83 return -1;
84 }
85 RSN_SELECTOR_PUT(pos, suite);
86 pos += WPA_SELECTOR_LEN;
87
88 *pos++ = 1;
89 *pos++ = 0;
90 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
91 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
92 } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
93 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
94 } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
95 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
96 } else {
97 wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
98 key_mgmt);
99 return -1;
100 }
101 pos += WPA_SELECTOR_LEN;
102
103 /* WPA Capabilities; use defaults, so no need to include it */
104
105 hdr->len = (pos - wpa_ie) - 2;
106
107 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
108
109 return pos - wpa_ie;
110 }
111
112
wpa_gen_wpa_ie_rsn(u8 * rsn_ie,size_t rsn_ie_len,int pairwise_cipher,int group_cipher,int key_mgmt,int mgmt_group_cipher,struct wpa_sm * sm)113 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
114 int pairwise_cipher, int group_cipher,
115 int key_mgmt, int mgmt_group_cipher,
116 struct wpa_sm *sm)
117 {
118 u8 *pos;
119 struct rsn_ie_hdr *hdr;
120 u16 capab;
121 u8 min_len = 0;
122 u32 suite;
123
124 if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
125 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
126 (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
127 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
128 (unsigned long) rsn_ie_len);
129 return -1;
130 }
131
132 if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) {
133 min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2;
134 } else {
135 min_len = sizeof(*hdr) + RSN_SELECTOR_LEN;
136 }
137
138 if (rsn_ie_len < min_len) {
139 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len);
140 }
141
142 hdr = (struct rsn_ie_hdr *) rsn_ie;
143 hdr->elem_id = WLAN_EID_RSN;
144 WPA_PUT_LE16(hdr->version, RSN_VERSION);
145 pos = (u8 *) (hdr + 1);
146
147 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
148 if (suite == 0) {
149 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
150 group_cipher);
151 return -1;
152 }
153 RSN_SELECTOR_PUT(pos, suite);
154 pos += RSN_SELECTOR_LEN;
155
156 if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) {
157 hdr->len = (pos - rsn_ie) - 2;
158 return (pos - rsn_ie);
159 }
160
161 *pos++ = 1;
162 *pos++ = 0;
163 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
164 if (suite == 0 ||
165 (pairwise_cipher == WPA_CIPHER_NONE)) {
166 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
167 pairwise_cipher);
168 return -1;
169 }
170 RSN_SELECTOR_PUT(pos, suite);
171 pos += RSN_SELECTOR_LEN;
172
173 *pos++ = 1;
174 *pos++ = 0;
175
176 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
177 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
178 } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
179 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
180 #ifdef CONFIG_IEEE80211R
181 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
182 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
183 } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
184 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
185 #endif /* CONFIG_IEEE80211R */
186 #ifdef CONFIG_IEEE80211W
187 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
188 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
189 } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
190 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
191 #ifdef CONFIG_WPA3_SAE
192 } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
193 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
194 #endif /* CONFIG_WPA3_SAE */
195 #ifdef CONFIG_OWE_STA
196 } else if (key_mgmt == WPA_KEY_MGMT_OWE) {
197 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
198 #endif /* CONFIG_OWE_STA */
199 #endif /* CONFIG_IEEE80211W */
200 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
201 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
202 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
203 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
204 } else {
205 wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
206 key_mgmt);
207 return -1;
208 }
209 pos += RSN_SELECTOR_LEN;
210
211 /* RSN Capabilities */
212 capab = 0;
213 #ifdef CONFIG_IEEE80211W
214 if (sm->pmf_cfg.capable) {
215 capab |= WPA_CAPABILITY_MFPC;
216 if (sm->pmf_cfg.required || key_mgmt == WPA_KEY_MGMT_SAE || key_mgmt == WPA_KEY_MGMT_OWE) {
217 capab |= WPA_CAPABILITY_MFPR;
218 }
219 }
220 #endif /* CONFIG_IEEE80211W */
221
222 if (sm->spp_sup.capable) {
223 capab |= WPA_CAPABILITY_SPP_CAPABLE;
224 }
225
226 if (sm->spp_sup.require) {
227 capab |= WPA_CAPABILITY_SPP_REQUIRED;
228 }
229
230 WPA_PUT_LE16(pos, capab);
231 pos += 2;
232
233 if (sm->cur_pmksa) {
234 /* PMKID Count (2 octets, little endian) */
235 *pos++ = 1;
236 *pos++ = 0;
237 /* PMKID */
238 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
239 pos += PMKID_LEN;
240 }
241
242 #ifdef CONFIG_IEEE80211W
243 if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
244 if (!sm->cur_pmksa) {
245 /* 0 PMKID Count */
246 WPA_PUT_LE16(pos, 0);
247 pos += 2;
248 }
249
250 /* Management Group Cipher Suite */
251 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
252 mgmt_group_cipher));;
253 pos += RSN_SELECTOR_LEN;
254 }
255 #endif /* CONFIG_IEEE80211W */
256
257 hdr->len = (pos - rsn_ie) - 2;
258
259 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
260
261 return pos - rsn_ie;
262 }
263
264
265 /**
266 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
267 * @sm: Pointer to WPA state machine data from wpa_sm_init()
268 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
269 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
270 * Returns: Length of the generated WPA/RSN IE or -1 on failure
271 */
wpa_gen_wpa_ie(struct wpa_sm * sm,u8 * wpa_ie,size_t wpa_ie_len)272 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
273 {
274 if (sm->proto == WPA_PROTO_RSN) {
275 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
276 sm->pairwise_cipher,
277 sm->group_cipher,
278 sm->key_mgmt, sm->mgmt_group_cipher,
279 sm);
280 } else if (sm->proto == WPA_PROTO_WAPI) {
281 return 0;
282 }
283
284 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
285 sm->pairwise_cipher,
286 sm->group_cipher,
287 sm->key_mgmt);
288 }
289
290
wpa_gen_rsnxe(struct wpa_sm * sm,u8 * rsnxe,size_t rsnxe_len)291 int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
292 {
293 u8 *pos = rsnxe;
294 u16 capab = 0;
295 size_t flen;
296
297 if (wpa_key_mgmt_sae(sm->key_mgmt) &&
298 (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
299 sm->sae_pwe == SAE_PWE_BOTH)) {
300 capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
301 #ifdef CONFIG_SAE_PK
302 if (sm->sae_pk) {
303 capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
304 }
305 #endif /* CONFIG_SAE_PK */
306 }
307
308 flen = (capab & 0xff00) ? 2 : 1;
309 if (!capab)
310 return 0; /* no supported extended RSN capabilities */
311 if (rsnxe_len < 2 + flen)
312 return -1;
313 capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
314
315 *pos++ = WLAN_EID_RSNX;
316 *pos++ = flen;
317 *pos++ = capab & 0x00ff;
318 capab >>= 8;
319 if (capab)
320 *pos++ = capab;
321
322 return pos - rsnxe;
323 }
324
325 /**
326 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
327 * @pos: Pointer to the IE header
328 * @end: Pointer to the end of the Key Data buffer
329 * @ie: Pointer to parsed IE data
330 * Returns: 0 on success, 1 if end mark is found, -1 on failure
331 */
wpa_parse_generic(const u8 * pos,const u8 * end,struct wpa_eapol_ie_parse * ie)332 static int wpa_parse_generic(const u8 *pos, const u8 *end,
333 struct wpa_eapol_ie_parse *ie)
334 {
335 if (pos[1] == 0)
336 return 1;
337
338 if (pos[1] >= 6 &&
339 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
340 pos[2 + WPA_SELECTOR_LEN] == 1 &&
341 pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
342 ie->wpa_ie = pos;
343 ie->wpa_ie_len = pos[1] + 2;
344 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
345 ie->wpa_ie, ie->wpa_ie_len);
346 return 0;
347 }
348
349 if (pos + 1 + RSN_SELECTOR_LEN < end &&
350 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
351 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
352 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
353 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
354 pos, pos[1] + 2);
355 return 0;
356 }
357
358 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
359 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
360 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
361 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
362 wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
363 pos, pos[1] + 2);
364 return 0;
365 }
366
367 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
368 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
369 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
370 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
371 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
372 pos, pos[1] + 2);
373 return 0;
374 }
375 #ifdef CONFIG_IEEE80211W
376 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
377 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
378 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
379 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
380 wpa_hexdump(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
381 pos, pos[1] + 2);
382 return 0;
383 }
384 #endif
385 if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
386 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
387 ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
388 ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
389 wpa_hexdump(MSG_DEBUG,
390 "WPA: Transition Disable KDE in EAPOL-Key",
391 pos, pos[1] + 2);
392 return 0;
393 }
394 return 0;
395 }
396
397
398 /**
399 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
400 * @buf: Pointer to the Key Data buffer
401 * @len: Key Data Length
402 * @ie: Pointer to parsed IE data
403 * Returns: 0 on success, -1 on failure
404 */
wpa_supplicant_parse_ies(const u8 * buf,size_t len,struct wpa_eapol_ie_parse * ie)405 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
406 struct wpa_eapol_ie_parse *ie)
407 {
408 const u8 *pos, *end;
409 int ret = 0;
410
411 memset(ie, 0, sizeof(*ie));
412 for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
413 if (pos[0] == 0xdd &&
414 ((pos == buf + len - 1) || pos[1] == 0)) {
415 /* Ignore padding */
416 break;
417 }
418 if (pos + 2 + pos[1] > end) {
419 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
420 "underflow (ie=%d len=%d pos=%d)",
421 pos[0], pos[1], (int) (pos - buf));
422 wpa_hexdump(MSG_DEBUG, "WPA: Key Data",
423 buf, len);
424 ret = -1;
425 break;
426 }
427 if (*pos == WLAN_EID_RSN) {
428 ie->rsn_ie = pos;
429 ie->rsn_ie_len = pos[1] + 2;
430 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
431 ie->rsn_ie, ie->rsn_ie_len);
432 } else if (*pos == WLAN_EID_RSNX) {
433 ie->rsnxe = pos;
434 ie->rsnxe_len = pos[1] + 2;
435 wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
436 ie->rsnxe, ie->rsnxe_len);
437 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
438 ret = wpa_parse_generic(pos, end, ie);
439 if (ret < 0)
440 break;
441 if (ret > 0) {
442 ret = 0;
443 break;
444 }
445 } else {
446 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
447 "Key Data IE", pos, 2 + pos[1]);
448 }
449 }
450
451 return ret;
452 }
453
454
455 #endif // ESP_SUPPLICANT
456