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