* Wi-Fi Protected Setup - attribute parsing
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "common.h"
-#include "wps_i.h"
+#include "wps_defs.h"
+#include "wps_attr_parse.h"
#ifndef CONFIG_WPS_STRICT
#define WPS_WORKAROUNDS
}
attr->settings_delay_time = pos;
break;
+ case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS:
+ if (len != 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u",
+ len);
+ return -1;
+ }
+ attr->registrar_configuration_methods = pos;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
"Extension subelement %u", id);
const u8 *end = pos + len;
u8 id, elen;
- while (pos + 2 < end) {
+ while (end - pos >= 2) {
id = *pos++;
elen = *pos++;
- if (pos + elen > end)
+ if (elen > end - pos)
break;
if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
return -1;
switch (vendor_id) {
case WPS_VENDOR_ID_WFA:
return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
- default:
- wpa_printf(MSG_MSGDUMP, "WPS: Skip unknown Vendor Extension "
- "(Vendor ID %u)", vendor_id);
- break;
}
+ /* Handle unknown vendor extensions */
+
+ wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
+ vendor_id);
+
+ if (len > WPS_MAX_VENDOR_EXT_LEN) {
+ wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
+ len);
+ return -1;
+ }
+
+ if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
+ wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
+ "attribute (max %d vendor extensions)",
+ MAX_WPS_PARSE_VENDOR_EXT);
+ return -1;
+ }
+ attr->vendor_ext[attr->num_vendor_ext] = pos;
+ attr->vendor_ext_len[attr->num_vendor_ext] = len;
+ attr->num_vendor_ext++;
+
return 0;
}
attr->dev_password_id = pos;
break;
case ATTR_OOB_DEVICE_PASSWORD:
- if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
+ if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
+ len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN ||
+ (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_MIN_LEN &&
+ WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) !=
+ DEV_PW_NFC_CONNECTION_HANDOVER)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
"Password length %u", len);
return -1;
}
attr->oob_dev_password = pos;
+ attr->oob_dev_password_len = len;
break;
case ATTR_OS_VERSION:
if (len != 4) {
}
attr->mac_addr = pos;
break;
- case ATTR_KEY_PROVIDED_AUTO:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
- "Automatically length %u", len);
- return -1;
- }
- attr->key_prov_auto = pos;
- break;
- case ATTR_802_1X_ENABLED:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
- "length %u", len);
- return -1;
- }
- attr->dot1x_enabled = pos;
- break;
case ATTR_SELECTED_REGISTRAR:
if (len != 1) {
wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
break;
case ATTR_MANUFACTURER:
attr->manufacturer = pos;
- attr->manufacturer_len = len;
+ if (len > WPS_MANUFACTURER_MAX_LEN)
+ attr->manufacturer_len = WPS_MANUFACTURER_MAX_LEN;
+ else
+ attr->manufacturer_len = len;
break;
case ATTR_MODEL_NAME:
attr->model_name = pos;
- attr->model_name_len = len;
+ if (len > WPS_MODEL_NAME_MAX_LEN)
+ attr->model_name_len = WPS_MODEL_NAME_MAX_LEN;
+ else
+ attr->model_name_len = len;
break;
case ATTR_MODEL_NUMBER:
attr->model_number = pos;
- attr->model_number_len = len;
+ if (len > WPS_MODEL_NUMBER_MAX_LEN)
+ attr->model_number_len = WPS_MODEL_NUMBER_MAX_LEN;
+ else
+ attr->model_number_len = len;
break;
case ATTR_SERIAL_NUMBER:
attr->serial_number = pos;
- attr->serial_number_len = len;
+ if (len > WPS_SERIAL_NUMBER_MAX_LEN)
+ attr->serial_number_len = WPS_SERIAL_NUMBER_MAX_LEN;
+ else
+ attr->serial_number_len = len;
break;
case ATTR_DEV_NAME:
+ if (len > WPS_DEV_NAME_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Ignore too long Device Name (len=%u)",
+ len);
+ break;
+ }
attr->dev_name = pos;
attr->dev_name_len = len;
break;
case ATTR_PUBLIC_KEY:
+ /*
+ * The Public Key attribute is supposed to be exactly 192 bytes
+ * in length. Allow couple of bytes shorter one to try to
+ * interoperate with implementations that do not use proper
+ * zero-padding.
+ */
+ if (len < 190 || len > 192) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Ignore Public Key with unexpected length %u",
+ len);
+ break;
+ }
attr->public_key = pos;
attr->public_key_len = len;
break;
attr->num_cred++;
break;
case ATTR_SSID:
+ if (len > SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Ignore too long SSID (len=%u)", len);
+ break;
+ }
attr->ssid = pos;
attr->ssid_len = len;
break;
attr->network_key = pos;
attr->network_key_len = len;
break;
- case ATTR_EAP_TYPE:
- attr->eap_type = pos;
- attr->eap_type_len = len;
- break;
- case ATTR_EAP_IDENTITY:
- attr->eap_identity = pos;
- attr->eap_identity_len = len;
- break;
case ATTR_AP_SETUP_LOCKED:
if (len != 1) {
wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
attr->req_dev_type[attr->num_req_dev_type] = pos;
attr->num_req_dev_type++;
break;
+ case ATTR_SECONDARY_DEV_TYPE_LIST:
+ if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
+ (len % WPS_DEV_TYPE_LEN) > 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
+ "Type length %u", len);
+ return -1;
+ }
+ attr->sec_dev_type_list = pos;
+ attr->sec_dev_type_list_len = len;
+ break;
case ATTR_VENDOR_EXT:
if (wps_parse_vendor_ext(attr, pos, len) < 0)
return -1;
break;
+ case ATTR_AP_CHANNEL:
+ if (len != 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
+ "length %u", len);
+ return -1;
+ }
+ attr->ap_channel = pos;
+ break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
"len=%u", type, len);
{
const u8 *pos, *end;
u16 type, len;
+#ifdef WPS_WORKAROUNDS
u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
os_memset(attr, 0, sizeof(*attr));
pos = wpabuf_head(msg);
if (wps_set_attr(attr, type, pos, len) < 0)
return -1;
+#ifdef WPS_WORKAROUNDS
prev_type = type;
+#endif /* WPS_WORKAROUNDS */
pos += len;
}