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