wps_attr_parse.c revision 337817
1117395Skan/*
2132718Skan * Wi-Fi Protected Setup - attribute parsing
3117395Skan * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4132718Skan *
5117395Skan * This software may be distributed under the terms of the BSD license.
6117395Skan * See README for more details.
7117395Skan */
8117395Skan
9117395Skan#include "includes.h"
10117395Skan
11117395Skan#include "common.h"
12117395Skan#include "wps_defs.h"
13117395Skan#include "wps_attr_parse.h"
14117395Skan
15117395Skan#ifndef CONFIG_WPS_STRICT
16117395Skan#define WPS_WORKAROUNDS
17117395Skan#endif /* CONFIG_WPS_STRICT */
18117395Skan
19117395Skan
20117395Skanstatic int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
21117395Skan					  u8 id, u8 len, const u8 *pos)
22117395Skan{
23169689Skan	wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
24169689Skan		   id, len);
25117395Skan	switch (id) {
26117395Skan	case WFA_ELEM_VERSION2:
27117395Skan		if (len != 1) {
28117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
29117395Skan				   "%u", len);
30117395Skan			return -1;
31117395Skan		}
32117395Skan		attr->version2 = pos;
33117395Skan		break;
34146895Skan	case WFA_ELEM_AUTHORIZEDMACS:
35117395Skan		attr->authorized_macs = pos;
36119256Skan		attr->authorized_macs_len = len;
37117395Skan		break;
38146895Skan	case WFA_ELEM_NETWORK_KEY_SHAREABLE:
39146895Skan		if (len != 1) {
40117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
41117395Skan				   "Shareable length %u", len);
42117395Skan			return -1;
43117395Skan		}
44117395Skan		attr->network_key_shareable = pos;
45117395Skan		break;
46117395Skan	case WFA_ELEM_REQUEST_TO_ENROLL:
47117395Skan		if (len != 1) {
48117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
49117395Skan				   "length %u", len);
50117395Skan			return -1;
51117395Skan		}
52117395Skan		attr->request_to_enroll = pos;
53117395Skan		break;
54117395Skan	case WFA_ELEM_SETTINGS_DELAY_TIME:
55117395Skan		if (len != 1) {
56117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
57117395Skan				   "Time length %u", len);
58117395Skan			return -1;
59117395Skan		}
60117395Skan		attr->settings_delay_time = pos;
61117395Skan		break;
62117395Skan	case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS:
63117395Skan		if (len != 2) {
64117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u",
65117395Skan				   len);
66146895Skan			return -1;
67146895Skan		}
68146895Skan		attr->registrar_configuration_methods = pos;
69117395Skan		break;
70117395Skan	default:
71117395Skan		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
72117395Skan			   "Extension subelement %u", id);
73117395Skan		break;
74117395Skan	}
75117395Skan
76117395Skan	return 0;
77117395Skan}
78117395Skan
79117395Skan
80117395Skanstatic int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
81117395Skan				    u16 len)
82117395Skan{
83117395Skan	const u8 *end = pos + len;
84117395Skan	u8 id, elen;
85117395Skan
86117395Skan	while (end - pos >= 2) {
87117395Skan		id = *pos++;
88117395Skan		elen = *pos++;
89117395Skan		if (elen > end - pos)
90117395Skan			break;
91117395Skan		if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
92117395Skan			return -1;
93117395Skan		pos += elen;
94117395Skan	}
95117395Skan
96117395Skan	return 0;
97117395Skan}
98117395Skan
99117395Skan
100117395Skanstatic int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
101117395Skan				u16 len)
102117395Skan{
103117395Skan	u32 vendor_id;
104117395Skan
105117395Skan	if (len < 3) {
106117395Skan		wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
107117395Skan		return 0;
108117395Skan	}
109117395Skan
110117395Skan	vendor_id = WPA_GET_BE24(pos);
111117395Skan	switch (vendor_id) {
112117395Skan	case WPS_VENDOR_ID_WFA:
113117395Skan		return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
114117395Skan	}
115117395Skan
116117395Skan	/* Handle unknown vendor extensions */
117117395Skan
118117395Skan	wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
119117395Skan		   vendor_id);
120117395Skan
121117395Skan	if (len > WPS_MAX_VENDOR_EXT_LEN) {
122117395Skan		wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
123117395Skan			   len);
124117395Skan		return -1;
125117395Skan	}
126117395Skan
127117395Skan	if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
128117395Skan		wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
129117395Skan			   "attribute (max %d vendor extensions)",
130117395Skan			   MAX_WPS_PARSE_VENDOR_EXT);
131117395Skan		return -1;
132117395Skan	}
133117395Skan	attr->vendor_ext[attr->num_vendor_ext] = pos;
134117395Skan	attr->vendor_ext_len[attr->num_vendor_ext] = len;
135117395Skan	attr->num_vendor_ext++;
136117395Skan
137117395Skan	return 0;
138117395Skan}
139117395Skan
140117395Skan
141117395Skanstatic int wps_set_attr(struct wps_parse_attr *attr, u16 type,
142117395Skan			const u8 *pos, u16 len)
143117395Skan{
144117395Skan	switch (type) {
145117395Skan	case ATTR_VERSION:
146117395Skan		if (len != 1) {
147117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
148117395Skan				   len);
149146895Skan			return -1;
150146895Skan		}
151117395Skan		attr->version = pos;
152117395Skan		break;
153117395Skan	case ATTR_MSG_TYPE:
154117395Skan		if (len != 1) {
155117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
156146895Skan				   "length %u", len);
157146895Skan			return -1;
158117395Skan		}
159117395Skan		attr->msg_type = pos;
160146895Skan		break;
161146895Skan	case ATTR_ENROLLEE_NONCE:
162146895Skan		if (len != WPS_NONCE_LEN) {
163146895Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
164146895Skan				   "length %u", len);
165146895Skan			return -1;
166117395Skan		}
167117395Skan		attr->enrollee_nonce = pos;
168117395Skan		break;
169117395Skan	case ATTR_REGISTRAR_NONCE:
170117395Skan		if (len != WPS_NONCE_LEN) {
171146895Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
172117395Skan				   "length %u", len);
173117395Skan			return -1;
174117395Skan		}
175117395Skan		attr->registrar_nonce = pos;
176117395Skan		break;
177117395Skan	case ATTR_UUID_E:
178117395Skan		if (len != WPS_UUID_LEN) {
179117395Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
180146895Skan				   len);
181146895Skan			return -1;
182146895Skan		}
183146895Skan		attr->uuid_e = pos;
184117395Skan		break;
185169689Skan	case ATTR_UUID_R:
186169689Skan		if (len != WPS_UUID_LEN) {
187169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
188169689Skan				   len);
189169689Skan			return -1;
190169689Skan		}
191169689Skan		attr->uuid_r = pos;
192169689Skan		break;
193169689Skan	case ATTR_AUTH_TYPE_FLAGS:
194169689Skan		if (len != 2) {
195169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
196169689Skan				   "Type Flags length %u", len);
197169689Skan			return -1;
198169689Skan		}
199169689Skan		attr->auth_type_flags = pos;
200169689Skan		break;
201169689Skan	case ATTR_ENCR_TYPE_FLAGS:
202169689Skan		if (len != 2) {
203169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
204169689Skan				   "Flags length %u", len);
205169689Skan			return -1;
206169689Skan		}
207169689Skan		attr->encr_type_flags = pos;
208169689Skan		break;
209169689Skan	case ATTR_CONN_TYPE_FLAGS:
210169689Skan		if (len != 1) {
211169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
212169689Skan				   "Flags length %u", len);
213169689Skan			return -1;
214169689Skan		}
215169689Skan		attr->conn_type_flags = pos;
216169689Skan		break;
217169689Skan	case ATTR_CONFIG_METHODS:
218169689Skan		if (len != 2) {
219169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
220169689Skan				   "length %u", len);
221169689Skan			return -1;
222169689Skan		}
223169689Skan		attr->config_methods = pos;
224169689Skan		break;
225169689Skan	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
226169689Skan		if (len != 2) {
227169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
228169689Skan				   "Registrar Config Methods length %u", len);
229169689Skan			return -1;
230169689Skan		}
231169689Skan		attr->sel_reg_config_methods = pos;
232169689Skan		break;
233169689Skan	case ATTR_PRIMARY_DEV_TYPE:
234169689Skan		if (len != WPS_DEV_TYPE_LEN) {
235169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
236169689Skan				   "Type length %u", len);
237169689Skan			return -1;
238169689Skan		}
239169689Skan		attr->primary_dev_type = pos;
240169689Skan		break;
241169689Skan	case ATTR_RF_BANDS:
242169689Skan		if (len != 1) {
243169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
244169689Skan				   "%u", len);
245169689Skan			return -1;
246169689Skan		}
247169689Skan		attr->rf_bands = pos;
248169689Skan		break;
249169689Skan	case ATTR_ASSOC_STATE:
250169689Skan		if (len != 2) {
251169689Skan			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
252169689Skan				   "length %u", len);
253169689Skan			return -1;
254169689Skan		}
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
585int 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