]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/wps/wps_attr_parse.c
WPS: Fix off-by-one check in vendor extension parsing
[thirdparty/hostap.git] / src / wps / wps_attr_parse.c
1 /*
2 * Wi-Fi Protected Setup - attribute parsing
3 * Copyright (c) 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
15 #include "includes.h"
16
17 #include "common.h"
18 #include "wps_i.h"
19
20 #ifndef CONFIG_WPS_STRICT
21 #define WPS_WORKAROUNDS
22 #endif /* CONFIG_WPS_STRICT */
23
24
25 static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
26 u8 id, u8 len, const u8 *pos)
27 {
28 wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
29 id, len);
30 switch (id) {
31 case WFA_ELEM_VERSION2:
32 if (len != 1) {
33 wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
34 "%u", len);
35 return -1;
36 }
37 attr->version2 = pos;
38 break;
39 case WFA_ELEM_AUTHORIZEDMACS:
40 attr->authorized_macs = pos;
41 attr->authorized_macs_len = len;
42 break;
43 case WFA_ELEM_NETWORK_KEY_SHAREABLE:
44 if (len != 1) {
45 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
46 "Shareable length %u", len);
47 return -1;
48 }
49 attr->network_key_shareable = pos;
50 break;
51 case WFA_ELEM_REQUEST_TO_ENROLL:
52 if (len != 1) {
53 wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
54 "length %u", len);
55 return -1;
56 }
57 attr->request_to_enroll = pos;
58 break;
59 case WFA_ELEM_SETTINGS_DELAY_TIME:
60 if (len != 1) {
61 wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
62 "Time length %u", len);
63 return -1;
64 }
65 attr->settings_delay_time = pos;
66 break;
67 default:
68 wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
69 "Extension subelement %u", id);
70 break;
71 }
72
73 return 0;
74 }
75
76
77 static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
78 u16 len)
79 {
80 const u8 *end = pos + len;
81 u8 id, elen;
82
83 while (pos + 2 < end) {
84 id = *pos++;
85 elen = *pos++;
86 if (pos + elen > end)
87 break;
88 if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
89 return -1;
90 pos += elen;
91 }
92
93 return 0;
94 }
95
96
97 static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
98 u16 len)
99 {
100 u32 vendor_id;
101
102 if (len < 3) {
103 wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
104 return 0;
105 }
106
107 vendor_id = WPA_GET_BE24(pos);
108 switch (vendor_id) {
109 case WPS_VENDOR_ID_WFA:
110 return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
111 }
112
113 /* Handle unknown vendor extensions */
114
115 wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
116 vendor_id);
117
118 if (len > WPS_MAX_VENDOR_EXT_LEN) {
119 wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
120 len);
121 return -1;
122 }
123
124 if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
125 wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
126 "attribute (max %d vendor extensions)",
127 MAX_WPS_PARSE_VENDOR_EXT);
128 return -1;
129 }
130 attr->vendor_ext[attr->num_vendor_ext] = pos;
131 attr->vendor_ext_len[attr->num_vendor_ext] = len;
132 attr->num_vendor_ext++;
133
134 return 0;
135 }
136
137
138 static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
139 const u8 *pos, u16 len)
140 {
141 switch (type) {
142 case ATTR_VERSION:
143 if (len != 1) {
144 wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
145 len);
146 return -1;
147 }
148 attr->version = pos;
149 break;
150 case ATTR_MSG_TYPE:
151 if (len != 1) {
152 wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
153 "length %u", len);
154 return -1;
155 }
156 attr->msg_type = pos;
157 break;
158 case ATTR_ENROLLEE_NONCE:
159 if (len != WPS_NONCE_LEN) {
160 wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
161 "length %u", len);
162 return -1;
163 }
164 attr->enrollee_nonce = pos;
165 break;
166 case ATTR_REGISTRAR_NONCE:
167 if (len != WPS_NONCE_LEN) {
168 wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
169 "length %u", len);
170 return -1;
171 }
172 attr->registrar_nonce = pos;
173 break;
174 case ATTR_UUID_E:
175 if (len != WPS_UUID_LEN) {
176 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
177 len);
178 return -1;
179 }
180 attr->uuid_e = pos;
181 break;
182 case ATTR_UUID_R:
183 if (len != WPS_UUID_LEN) {
184 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
185 len);
186 return -1;
187 }
188 attr->uuid_r = pos;
189 break;
190 case ATTR_AUTH_TYPE_FLAGS:
191 if (len != 2) {
192 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
193 "Type Flags length %u", len);
194 return -1;
195 }
196 attr->auth_type_flags = pos;
197 break;
198 case ATTR_ENCR_TYPE_FLAGS:
199 if (len != 2) {
200 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
201 "Flags length %u", len);
202 return -1;
203 }
204 attr->encr_type_flags = pos;
205 break;
206 case ATTR_CONN_TYPE_FLAGS:
207 if (len != 1) {
208 wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
209 "Flags length %u", len);
210 return -1;
211 }
212 attr->conn_type_flags = pos;
213 break;
214 case ATTR_CONFIG_METHODS:
215 if (len != 2) {
216 wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
217 "length %u", len);
218 return -1;
219 }
220 attr->config_methods = pos;
221 break;
222 case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
223 if (len != 2) {
224 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
225 "Registrar Config Methods length %u", len);
226 return -1;
227 }
228 attr->sel_reg_config_methods = pos;
229 break;
230 case ATTR_PRIMARY_DEV_TYPE:
231 if (len != WPS_DEV_TYPE_LEN) {
232 wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
233 "Type length %u", len);
234 return -1;
235 }
236 attr->primary_dev_type = pos;
237 break;
238 case ATTR_RF_BANDS:
239 if (len != 1) {
240 wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
241 "%u", len);
242 return -1;
243 }
244 attr->rf_bands = pos;
245 break;
246 case ATTR_ASSOC_STATE:
247 if (len != 2) {
248 wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
249 "length %u", len);
250 return -1;
251 }
252 attr->assoc_state = pos;
253 break;
254 case ATTR_CONFIG_ERROR:
255 if (len != 2) {
256 wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
257 "Error length %u", len);
258 return -1;
259 }
260 attr->config_error = pos;
261 break;
262 case ATTR_DEV_PASSWORD_ID:
263 if (len != 2) {
264 wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
265 "ID length %u", len);
266 return -1;
267 }
268 attr->dev_password_id = pos;
269 break;
270 case ATTR_OOB_DEVICE_PASSWORD:
271 if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
272 wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
273 "Password length %u", len);
274 return -1;
275 }
276 attr->oob_dev_password = pos;
277 break;
278 case ATTR_OS_VERSION:
279 if (len != 4) {
280 wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
281 "%u", len);
282 return -1;
283 }
284 attr->os_version = pos;
285 break;
286 case ATTR_WPS_STATE:
287 if (len != 1) {
288 wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
289 "Setup State length %u", len);
290 return -1;
291 }
292 attr->wps_state = pos;
293 break;
294 case ATTR_AUTHENTICATOR:
295 if (len != WPS_AUTHENTICATOR_LEN) {
296 wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
297 "length %u", len);
298 return -1;
299 }
300 attr->authenticator = pos;
301 break;
302 case ATTR_R_HASH1:
303 if (len != WPS_HASH_LEN) {
304 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
305 len);
306 return -1;
307 }
308 attr->r_hash1 = pos;
309 break;
310 case ATTR_R_HASH2:
311 if (len != WPS_HASH_LEN) {
312 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
313 len);
314 return -1;
315 }
316 attr->r_hash2 = pos;
317 break;
318 case ATTR_E_HASH1:
319 if (len != WPS_HASH_LEN) {
320 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
321 len);
322 return -1;
323 }
324 attr->e_hash1 = pos;
325 break;
326 case ATTR_E_HASH2:
327 if (len != WPS_HASH_LEN) {
328 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
329 len);
330 return -1;
331 }
332 attr->e_hash2 = pos;
333 break;
334 case ATTR_R_SNONCE1:
335 if (len != WPS_SECRET_NONCE_LEN) {
336 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
337 "%u", len);
338 return -1;
339 }
340 attr->r_snonce1 = pos;
341 break;
342 case ATTR_R_SNONCE2:
343 if (len != WPS_SECRET_NONCE_LEN) {
344 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
345 "%u", len);
346 return -1;
347 }
348 attr->r_snonce2 = pos;
349 break;
350 case ATTR_E_SNONCE1:
351 if (len != WPS_SECRET_NONCE_LEN) {
352 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
353 "%u", len);
354 return -1;
355 }
356 attr->e_snonce1 = pos;
357 break;
358 case ATTR_E_SNONCE2:
359 if (len != WPS_SECRET_NONCE_LEN) {
360 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
361 "%u", len);
362 return -1;
363 }
364 attr->e_snonce2 = pos;
365 break;
366 case ATTR_KEY_WRAP_AUTH:
367 if (len != WPS_KWA_LEN) {
368 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
369 "Authenticator length %u", len);
370 return -1;
371 }
372 attr->key_wrap_auth = pos;
373 break;
374 case ATTR_AUTH_TYPE:
375 if (len != 2) {
376 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
377 "Type length %u", len);
378 return -1;
379 }
380 attr->auth_type = pos;
381 break;
382 case ATTR_ENCR_TYPE:
383 if (len != 2) {
384 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
385 "Type length %u", len);
386 return -1;
387 }
388 attr->encr_type = pos;
389 break;
390 case ATTR_NETWORK_INDEX:
391 if (len != 1) {
392 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
393 "length %u", len);
394 return -1;
395 }
396 attr->network_idx = pos;
397 break;
398 case ATTR_NETWORK_KEY_INDEX:
399 if (len != 1) {
400 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
401 "length %u", len);
402 return -1;
403 }
404 attr->network_key_idx = pos;
405 break;
406 case ATTR_MAC_ADDR:
407 if (len != ETH_ALEN) {
408 wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
409 "length %u", len);
410 return -1;
411 }
412 attr->mac_addr = pos;
413 break;
414 case ATTR_KEY_PROVIDED_AUTO:
415 if (len != 1) {
416 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
417 "Automatically length %u", len);
418 return -1;
419 }
420 attr->key_prov_auto = pos;
421 break;
422 case ATTR_802_1X_ENABLED:
423 if (len != 1) {
424 wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
425 "length %u", len);
426 return -1;
427 }
428 attr->dot1x_enabled = pos;
429 break;
430 case ATTR_SELECTED_REGISTRAR:
431 if (len != 1) {
432 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
433 " length %u", len);
434 return -1;
435 }
436 attr->selected_registrar = pos;
437 break;
438 case ATTR_REQUEST_TYPE:
439 if (len != 1) {
440 wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
441 "length %u", len);
442 return -1;
443 }
444 attr->request_type = pos;
445 break;
446 case ATTR_RESPONSE_TYPE:
447 if (len != 1) {
448 wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
449 "length %u", len);
450 return -1;
451 }
452 attr->response_type = pos;
453 break;
454 case ATTR_MANUFACTURER:
455 attr->manufacturer = pos;
456 attr->manufacturer_len = len;
457 break;
458 case ATTR_MODEL_NAME:
459 attr->model_name = pos;
460 attr->model_name_len = len;
461 break;
462 case ATTR_MODEL_NUMBER:
463 attr->model_number = pos;
464 attr->model_number_len = len;
465 break;
466 case ATTR_SERIAL_NUMBER:
467 attr->serial_number = pos;
468 attr->serial_number_len = len;
469 break;
470 case ATTR_DEV_NAME:
471 attr->dev_name = pos;
472 attr->dev_name_len = len;
473 break;
474 case ATTR_PUBLIC_KEY:
475 attr->public_key = pos;
476 attr->public_key_len = len;
477 break;
478 case ATTR_ENCR_SETTINGS:
479 attr->encr_settings = pos;
480 attr->encr_settings_len = len;
481 break;
482 case ATTR_CRED:
483 if (attr->num_cred >= MAX_CRED_COUNT) {
484 wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
485 "attribute (max %d credentials)",
486 MAX_CRED_COUNT);
487 break;
488 }
489 attr->cred[attr->num_cred] = pos;
490 attr->cred_len[attr->num_cred] = len;
491 attr->num_cred++;
492 break;
493 case ATTR_SSID:
494 attr->ssid = pos;
495 attr->ssid_len = len;
496 break;
497 case ATTR_NETWORK_KEY:
498 attr->network_key = pos;
499 attr->network_key_len = len;
500 break;
501 case ATTR_EAP_TYPE:
502 attr->eap_type = pos;
503 attr->eap_type_len = len;
504 break;
505 case ATTR_EAP_IDENTITY:
506 attr->eap_identity = pos;
507 attr->eap_identity_len = len;
508 break;
509 case ATTR_AP_SETUP_LOCKED:
510 if (len != 1) {
511 wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
512 "length %u", len);
513 return -1;
514 }
515 attr->ap_setup_locked = pos;
516 break;
517 case ATTR_REQUESTED_DEV_TYPE:
518 if (len != WPS_DEV_TYPE_LEN) {
519 wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
520 "Type length %u", len);
521 return -1;
522 }
523 if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
524 wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
525 "Type attribute (max %u types)",
526 MAX_REQ_DEV_TYPE_COUNT);
527 break;
528 }
529 attr->req_dev_type[attr->num_req_dev_type] = pos;
530 attr->num_req_dev_type++;
531 break;
532 case ATTR_SECONDARY_DEV_TYPE_LIST:
533 if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
534 (len % WPS_DEV_TYPE_LEN) > 0) {
535 wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
536 "Type length %u", len);
537 return -1;
538 }
539 attr->sec_dev_type_list = pos;
540 attr->sec_dev_type_list_len = len;
541 break;
542 case ATTR_VENDOR_EXT:
543 if (wps_parse_vendor_ext(attr, pos, len) < 0)
544 return -1;
545 break;
546 default:
547 wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
548 "len=%u", type, len);
549 break;
550 }
551
552 return 0;
553 }
554
555
556 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
557 {
558 const u8 *pos, *end;
559 u16 type, len;
560 u16 prev_type = 0;
561
562 os_memset(attr, 0, sizeof(*attr));
563 pos = wpabuf_head(msg);
564 end = pos + wpabuf_len(msg);
565
566 while (pos < end) {
567 if (end - pos < 4) {
568 wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
569 "%lu bytes remaining",
570 (unsigned long) (end - pos));
571 return -1;
572 }
573
574 type = WPA_GET_BE16(pos);
575 pos += 2;
576 len = WPA_GET_BE16(pos);
577 pos += 2;
578 wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
579 type, len);
580 if (len > end - pos) {
581 wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
582 wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
583 #ifdef WPS_WORKAROUNDS
584 /*
585 * Some deployed APs seem to have a bug in encoding of
586 * Network Key attribute in the Credential attribute
587 * where they add an extra octet after the Network Key
588 * attribute at least when open network is being
589 * provisioned.
590 */
591 if ((type & 0xff00) != 0x1000 &&
592 prev_type == ATTR_NETWORK_KEY) {
593 wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
594 "to skip unexpected octet after "
595 "Network Key");
596 pos -= 3;
597 continue;
598 }
599 #endif /* WPS_WORKAROUNDS */
600 return -1;
601 }
602
603 #ifdef WPS_WORKAROUNDS
604 if (type == 0 && len == 0) {
605 /*
606 * Mac OS X 10.6 seems to be adding 0x00 padding to the
607 * end of M1. Skip those to avoid interop issues.
608 */
609 int i;
610 for (i = 0; i < end - pos; i++) {
611 if (pos[i])
612 break;
613 }
614 if (i == end - pos) {
615 wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
616 "unexpected message padding");
617 break;
618 }
619 }
620 #endif /* WPS_WORKAROUNDS */
621
622 if (wps_set_attr(attr, type, pos, len) < 0)
623 return -1;
624
625 prev_type = type;
626 pos += len;
627 }
628
629 return 0;
630 }