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