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