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