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