]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/rsn_supp/wpa_ie.c
ae9f4ca241d8248551502ef3429dbf44bfaa2482
[thirdparty/hostap.git] / src / rsn_supp / wpa_ie.c
1 /*
2 * wpa_supplicant - WPA/RSN IE and KDE processing
3 * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "wpa.h"
13 #include "pmksa_cache.h"
14 #include "common/ieee802_11_defs.h"
15 #include "wpa_i.h"
16 #include "wpa_ie.h"
17
18
19 /**
20 * wpa_parse_wpa_ie - Parse WPA/RSN IE
21 * @wpa_ie: Pointer to WPA or RSN IE
22 * @wpa_ie_len: Length of the WPA/RSN IE
23 * @data: Pointer to data area for parsing results
24 * Returns: 0 on success, -1 on failure
25 *
26 * Parse the contents of WPA or RSN IE and write the parsed data into data.
27 */
28 int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
29 struct wpa_ie_data *data)
30 {
31 if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
32 return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
33 if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
34 wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
35 return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
36 else
37 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
38 }
39
40
41 static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
42 int pairwise_cipher, int group_cipher,
43 int key_mgmt)
44 {
45 u8 *pos;
46 struct wpa_ie_hdr *hdr;
47 u32 suite;
48
49 if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
50 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
51 return -1;
52
53 hdr = (struct wpa_ie_hdr *) wpa_ie;
54 hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
55 RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
56 WPA_PUT_LE16(hdr->version, WPA_VERSION);
57 pos = (u8 *) (hdr + 1);
58
59 suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
60 if (suite == 0) {
61 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
62 group_cipher);
63 return -1;
64 }
65 RSN_SELECTOR_PUT(pos, suite);
66 pos += WPA_SELECTOR_LEN;
67
68 *pos++ = 1;
69 *pos++ = 0;
70 suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
71 if (suite == 0 ||
72 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
73 pairwise_cipher != WPA_CIPHER_NONE)) {
74 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
75 pairwise_cipher);
76 return -1;
77 }
78 RSN_SELECTOR_PUT(pos, suite);
79 pos += WPA_SELECTOR_LEN;
80
81 *pos++ = 1;
82 *pos++ = 0;
83 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
84 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
85 } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
86 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
87 } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
88 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
89 } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
90 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
91 } else {
92 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
93 key_mgmt);
94 return -1;
95 }
96 pos += WPA_SELECTOR_LEN;
97
98 /* WPA Capabilities; use defaults, so no need to include it */
99
100 hdr->len = (pos - wpa_ie) - 2;
101
102 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
103
104 return pos - wpa_ie;
105 }
106
107
108 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
109 int pairwise_cipher, int group_cipher,
110 int key_mgmt, int mgmt_group_cipher,
111 struct wpa_sm *sm)
112 {
113 u8 *pos;
114 struct rsn_ie_hdr *hdr;
115 u16 capab;
116 u32 suite;
117
118 if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
119 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
120 (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
121 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
122 (unsigned long) rsn_ie_len);
123 return -1;
124 }
125
126 hdr = (struct rsn_ie_hdr *) rsn_ie;
127 hdr->elem_id = WLAN_EID_RSN;
128 WPA_PUT_LE16(hdr->version, RSN_VERSION);
129 pos = (u8 *) (hdr + 1);
130
131 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
132 if (suite == 0) {
133 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
134 group_cipher);
135 return -1;
136 }
137 RSN_SELECTOR_PUT(pos, suite);
138 pos += RSN_SELECTOR_LEN;
139
140 *pos++ = 1;
141 *pos++ = 0;
142 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
143 if (suite == 0 ||
144 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
145 pairwise_cipher != WPA_CIPHER_NONE)) {
146 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
147 pairwise_cipher);
148 return -1;
149 }
150 RSN_SELECTOR_PUT(pos, suite);
151 pos += RSN_SELECTOR_LEN;
152
153 *pos++ = 1;
154 *pos++ = 0;
155 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
156 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
157 } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
158 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
159 } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
160 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
161 #ifdef CONFIG_IEEE80211R
162 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
163 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
164 #ifdef CONFIG_SHA384
165 } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
166 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
167 #endif /* CONFIG_SHA384 */
168 } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
169 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
170 #endif /* CONFIG_IEEE80211R */
171 #ifdef CONFIG_IEEE80211W
172 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
173 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
174 } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
175 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
176 #endif /* CONFIG_IEEE80211W */
177 #ifdef CONFIG_SAE
178 } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
179 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
180 } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
181 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
182 #endif /* CONFIG_SAE */
183 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
184 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
185 } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
186 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
187 #ifdef CONFIG_FILS
188 } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
189 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
190 } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
191 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
192 #ifdef CONFIG_IEEE80211R
193 } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
194 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
195 } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
196 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
197 #endif /* CONFIG_IEEE80211R */
198 #endif /* CONFIG_FILS */
199 #ifdef CONFIG_OWE
200 } else if (key_mgmt & WPA_KEY_MGMT_OWE) {
201 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
202 #endif /* CONFIG_OWE */
203 #ifdef CONFIG_DPP
204 } else if (key_mgmt & WPA_KEY_MGMT_DPP) {
205 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
206 #endif /* CONFIG_DPP */
207 #ifdef CONFIG_HS20
208 } else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
209 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
210 #endif /* CONFIG_HS20 */
211 } else {
212 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
213 key_mgmt);
214 return -1;
215 }
216 pos += RSN_SELECTOR_LEN;
217
218 /* RSN Capabilities */
219 capab = 0;
220 #ifdef CONFIG_IEEE80211W
221 if (sm->mfp)
222 capab |= WPA_CAPABILITY_MFPC;
223 if (sm->mfp == 2)
224 capab |= WPA_CAPABILITY_MFPR;
225 #endif /* CONFIG_IEEE80211W */
226 if (sm->ocv)
227 capab |= WPA_CAPABILITY_OCVC;
228 WPA_PUT_LE16(pos, capab);
229 pos += 2;
230
231 if (sm->cur_pmksa) {
232 /* PMKID Count (2 octets, little endian) */
233 *pos++ = 1;
234 *pos++ = 0;
235 /* PMKID */
236 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
237 pos += PMKID_LEN;
238 }
239
240 #ifdef CONFIG_IEEE80211W
241 if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
242 if (!sm->cur_pmksa) {
243 /* PMKID Count */
244 WPA_PUT_LE16(pos, 0);
245 pos += 2;
246 }
247
248 /* Management Group Cipher Suite */
249 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
250 mgmt_group_cipher));
251 pos += RSN_SELECTOR_LEN;
252 }
253 #endif /* CONFIG_IEEE80211W */
254
255 hdr->len = (pos - rsn_ie) - 2;
256
257 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
258
259 return pos - rsn_ie;
260 }
261
262
263 #ifdef CONFIG_HS20
264 static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
265 int pairwise_cipher, int group_cipher,
266 int key_mgmt)
267 {
268 u8 *pos, *len;
269 u32 suite;
270
271 if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
272 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
273 return -1;
274
275 pos = wpa_ie;
276 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
277 len = pos++; /* to be filled */
278 WPA_PUT_BE24(pos, OUI_WFA);
279 pos += 3;
280 *pos++ = HS20_OSEN_OUI_TYPE;
281
282 /* Group Data Cipher Suite */
283 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
284 if (suite == 0) {
285 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
286 group_cipher);
287 return -1;
288 }
289 RSN_SELECTOR_PUT(pos, suite);
290 pos += RSN_SELECTOR_LEN;
291
292 /* Pairwise Cipher Suite Count and List */
293 WPA_PUT_LE16(pos, 1);
294 pos += 2;
295 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
296 if (suite == 0 ||
297 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
298 pairwise_cipher != WPA_CIPHER_NONE)) {
299 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
300 pairwise_cipher);
301 return -1;
302 }
303 RSN_SELECTOR_PUT(pos, suite);
304 pos += RSN_SELECTOR_LEN;
305
306 /* AKM Suite Count and List */
307 WPA_PUT_LE16(pos, 1);
308 pos += 2;
309 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
310 pos += RSN_SELECTOR_LEN;
311
312 *len = pos - len - 1;
313
314 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
315
316 return pos - wpa_ie;
317 }
318 #endif /* CONFIG_HS20 */
319
320
321 /**
322 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
323 * @sm: Pointer to WPA state machine data from wpa_sm_init()
324 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
325 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
326 * Returns: Length of the generated WPA/RSN IE or -1 on failure
327 */
328 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
329 {
330 if (sm->proto == WPA_PROTO_RSN)
331 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
332 sm->pairwise_cipher,
333 sm->group_cipher,
334 sm->key_mgmt, sm->mgmt_group_cipher,
335 sm);
336 #ifdef CONFIG_HS20
337 else if (sm->proto == WPA_PROTO_OSEN)
338 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
339 sm->pairwise_cipher,
340 sm->group_cipher,
341 sm->key_mgmt);
342 #endif /* CONFIG_HS20 */
343 else
344 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
345 sm->pairwise_cipher,
346 sm->group_cipher,
347 sm->key_mgmt);
348 }
349
350
351 /**
352 * wpa_parse_vendor_specific - Parse Vendor Specific IEs
353 * @pos: Pointer to the IE header
354 * @end: Pointer to the end of the Key Data buffer
355 * @ie: Pointer to parsed IE data
356 * Returns: 0 on success, 1 if end mark is found, -1 on failure
357 */
358 static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
359 struct wpa_eapol_ie_parse *ie)
360 {
361 unsigned int oui;
362
363 if (pos[1] < 4) {
364 wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
365 pos[1]);
366 return 1;
367 }
368
369 oui = WPA_GET_BE24(&pos[2]);
370 if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
371 if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
372 ie->wmm = &pos[2];
373 ie->wmm_len = pos[1];
374 wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
375 ie->wmm, ie->wmm_len);
376 } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
377 ie->wmm = &pos[2];
378 ie->wmm_len = pos[1];
379 wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
380 ie->wmm, ie->wmm_len);
381 }
382 }
383 return 0;
384 }
385
386
387 /**
388 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
389 * @pos: Pointer to the IE header
390 * @end: Pointer to the end of the Key Data buffer
391 * @ie: Pointer to parsed IE data
392 * Returns: 0 on success, 1 if end mark is found, -1 on failure
393 */
394 static int wpa_parse_generic(const u8 *pos, const u8 *end,
395 struct wpa_eapol_ie_parse *ie)
396 {
397 if (pos[1] == 0)
398 return 1;
399
400 if (pos[1] >= 6 &&
401 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
402 pos[2 + WPA_SELECTOR_LEN] == 1 &&
403 pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
404 ie->wpa_ie = pos;
405 ie->wpa_ie_len = pos[1] + 2;
406 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
407 ie->wpa_ie, ie->wpa_ie_len);
408 return 0;
409 }
410
411 if (1 + RSN_SELECTOR_LEN < end - pos &&
412 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
413 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
414 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
415 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
416 pos, pos[1] + 2);
417 return 0;
418 }
419
420 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
421 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
422 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
423 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
424 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
425 pos, pos[1] + 2);
426 return 0;
427 }
428
429 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
430 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
431 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
432 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
433 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
434 pos, pos[1] + 2);
435 return 0;
436 }
437
438 #ifdef CONFIG_IEEE80211W
439 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
440 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
441 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
442 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
443 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
444 pos, pos[1] + 2);
445 return 0;
446 }
447 #endif /* CONFIG_IEEE80211W */
448
449 #ifdef CONFIG_P2P
450 if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
451 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
452 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
453 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
454 ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
455 return 0;
456 }
457
458 if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
459 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
460 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
461 wpa_hexdump(MSG_DEBUG,
462 "WPA: IP Address Allocation in EAPOL-Key",
463 ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
464 return 0;
465 }
466 #endif /* CONFIG_P2P */
467
468 #ifdef CONFIG_OCV
469 if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
470 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
471 ie->oci = pos + 2 + RSN_SELECTOR_LEN;
472 ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
473 wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
474 pos, pos[1] + 2);
475 return 0;
476 }
477 #endif /* CONFIG_OCV */
478
479 return 0;
480 }
481
482
483 /**
484 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
485 * @buf: Pointer to the Key Data buffer
486 * @len: Key Data Length
487 * @ie: Pointer to parsed IE data
488 * Returns: 0 on success, -1 on failure
489 */
490 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
491 struct wpa_eapol_ie_parse *ie)
492 {
493 const u8 *pos, *end;
494 int ret = 0;
495
496 os_memset(ie, 0, sizeof(*ie));
497 for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
498 if (pos[0] == 0xdd &&
499 ((pos == buf + len - 1) || pos[1] == 0)) {
500 /* Ignore padding */
501 break;
502 }
503 if (2 + pos[1] > end - pos) {
504 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
505 "underflow (ie=%d len=%d pos=%d)",
506 pos[0], pos[1], (int) (pos - buf));
507 wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
508 buf, len);
509 ret = -1;
510 break;
511 }
512 if (*pos == WLAN_EID_RSN) {
513 ie->rsn_ie = pos;
514 ie->rsn_ie_len = pos[1] + 2;
515 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
516 ie->rsn_ie, ie->rsn_ie_len);
517 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
518 pos[1] >= sizeof(struct rsn_mdie)) {
519 ie->mdie = pos;
520 ie->mdie_len = pos[1] + 2;
521 wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
522 ie->mdie, ie->mdie_len);
523 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
524 pos[1] >= sizeof(struct rsn_ftie)) {
525 ie->ftie = pos;
526 ie->ftie_len = pos[1] + 2;
527 wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
528 ie->ftie, ie->ftie_len);
529 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
530 if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
531 ie->reassoc_deadline = pos;
532 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
533 "in EAPOL-Key",
534 ie->reassoc_deadline, pos[1] + 2);
535 } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
536 ie->key_lifetime = pos;
537 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
538 "in EAPOL-Key",
539 ie->key_lifetime, pos[1] + 2);
540 } else {
541 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
542 "EAPOL-Key Key Data IE",
543 pos, 2 + pos[1]);
544 }
545 } else if (*pos == WLAN_EID_LINK_ID) {
546 if (pos[1] >= 18) {
547 ie->lnkid = pos;
548 ie->lnkid_len = pos[1] + 2;
549 }
550 } else if (*pos == WLAN_EID_EXT_CAPAB) {
551 ie->ext_capab = pos;
552 ie->ext_capab_len = pos[1] + 2;
553 } else if (*pos == WLAN_EID_SUPP_RATES) {
554 ie->supp_rates = pos;
555 ie->supp_rates_len = pos[1] + 2;
556 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
557 ie->ext_supp_rates = pos;
558 ie->ext_supp_rates_len = pos[1] + 2;
559 } else if (*pos == WLAN_EID_HT_CAP &&
560 pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
561 ie->ht_capabilities = pos + 2;
562 } else if (*pos == WLAN_EID_VHT_AID) {
563 if (pos[1] >= 2)
564 ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
565 } else if (*pos == WLAN_EID_VHT_CAP &&
566 pos[1] >= sizeof(struct ieee80211_vht_capabilities))
567 {
568 ie->vht_capabilities = pos + 2;
569 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
570 ie->qosinfo = pos[2];
571 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
572 ie->supp_channels = pos + 2;
573 ie->supp_channels_len = pos[1];
574 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
575 /*
576 * The value of the Length field of the Supported
577 * Operating Classes element is between 2 and 253.
578 * Silently skip invalid elements to avoid interop
579 * issues when trying to use the value.
580 */
581 if (pos[1] >= 2 && pos[1] <= 253) {
582 ie->supp_oper_classes = pos + 2;
583 ie->supp_oper_classes_len = pos[1];
584 }
585 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
586 ret = wpa_parse_generic(pos, end, ie);
587 if (ret < 0)
588 break;
589 if (ret > 0) {
590 ret = 0;
591 break;
592 }
593
594 ret = wpa_parse_vendor_specific(pos, end, ie);
595 if (ret < 0)
596 break;
597 if (ret > 0) {
598 ret = 0;
599 break;
600 }
601 } else {
602 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
603 "Key Data IE", pos, 2 + pos[1]);
604 }
605 }
606
607 return ret;
608 }