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