• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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