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