123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /*
- * 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.
- */
- #include "includes.h"
- #include "common.h"
- #include "wps_i.h"
- #ifndef CONFIG_WPS_STRICT
- #define WPS_WORKAROUNDS
- #endif /* CONFIG_WPS_STRICT */
- static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
- const u8 *pos, u16 len)
- {
- switch (type) {
- case ATTR_VERSION:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
- len);
- return -1;
- }
- attr->version = pos;
- break;
- case ATTR_VERSION2:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
- "%u", len);
- return -1;
- }
- attr->version2 = pos;
- break;
- case ATTR_MSG_TYPE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
- "length %u", len);
- return -1;
- }
- attr->msg_type = pos;
- break;
- case ATTR_ENROLLEE_NONCE:
- if (len != WPS_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
- "length %u", len);
- return -1;
- }
- attr->enrollee_nonce = pos;
- break;
- case ATTR_REGISTRAR_NONCE:
- if (len != WPS_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
- "length %u", len);
- return -1;
- }
- attr->registrar_nonce = pos;
- break;
- case ATTR_UUID_E:
- if (len != WPS_UUID_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
- len);
- return -1;
- }
- attr->uuid_e = pos;
- break;
- case ATTR_UUID_R:
- if (len != WPS_UUID_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
- len);
- return -1;
- }
- attr->uuid_r = pos;
- break;
- case ATTR_AUTH_TYPE_FLAGS:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
- "Type Flags length %u", len);
- return -1;
- }
- attr->auth_type_flags = pos;
- break;
- case ATTR_ENCR_TYPE_FLAGS:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
- "Flags length %u", len);
- return -1;
- }
- attr->encr_type_flags = pos;
- break;
- case ATTR_CONN_TYPE_FLAGS:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
- "Flags length %u", len);
- return -1;
- }
- attr->conn_type_flags = pos;
- break;
- case ATTR_CONFIG_METHODS:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
- "length %u", len);
- return -1;
- }
- attr->config_methods = pos;
- break;
- case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
- "Registrar Config Methods length %u", len);
- return -1;
- }
- attr->sel_reg_config_methods = pos;
- break;
- case ATTR_PRIMARY_DEV_TYPE:
- if (len != WPS_DEV_TYPE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
- "Type length %u", len);
- return -1;
- }
- attr->primary_dev_type = pos;
- break;
- case ATTR_RF_BANDS:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
- "%u", len);
- return -1;
- }
- attr->rf_bands = pos;
- break;
- case ATTR_ASSOC_STATE:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
- "length %u", len);
- return -1;
- }
- attr->assoc_state = pos;
- break;
- case ATTR_CONFIG_ERROR:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
- "Error length %u", len);
- return -1;
- }
- attr->config_error = pos;
- break;
- case ATTR_DEV_PASSWORD_ID:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
- "ID length %u", len);
- return -1;
- }
- attr->dev_password_id = pos;
- break;
- case ATTR_OOB_DEVICE_PASSWORD:
- if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
- "Password length %u", len);
- return -1;
- }
- attr->oob_dev_password = pos;
- break;
- case ATTR_OS_VERSION:
- if (len != 4) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
- "%u", len);
- return -1;
- }
- attr->os_version = pos;
- break;
- case ATTR_WPS_STATE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
- "Setup State length %u", len);
- return -1;
- }
- attr->wps_state = pos;
- break;
- case ATTR_AUTHENTICATOR:
- if (len != WPS_AUTHENTICATOR_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
- "length %u", len);
- return -1;
- }
- attr->authenticator = pos;
- break;
- case ATTR_R_HASH1:
- if (len != WPS_HASH_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
- len);
- return -1;
- }
- attr->r_hash1 = pos;
- break;
- case ATTR_R_HASH2:
- if (len != WPS_HASH_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
- len);
- return -1;
- }
- attr->r_hash2 = pos;
- break;
- case ATTR_E_HASH1:
- if (len != WPS_HASH_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
- len);
- return -1;
- }
- attr->e_hash1 = pos;
- break;
- case ATTR_E_HASH2:
- if (len != WPS_HASH_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
- len);
- return -1;
- }
- attr->e_hash2 = pos;
- break;
- case ATTR_R_SNONCE1:
- if (len != WPS_SECRET_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
- "%u", len);
- return -1;
- }
- attr->r_snonce1 = pos;
- break;
- case ATTR_R_SNONCE2:
- if (len != WPS_SECRET_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
- "%u", len);
- return -1;
- }
- attr->r_snonce2 = pos;
- break;
- case ATTR_E_SNONCE1:
- if (len != WPS_SECRET_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
- "%u", len);
- return -1;
- }
- attr->e_snonce1 = pos;
- break;
- case ATTR_E_SNONCE2:
- if (len != WPS_SECRET_NONCE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
- "%u", len);
- return -1;
- }
- attr->e_snonce2 = pos;
- break;
- case ATTR_KEY_WRAP_AUTH:
- if (len != WPS_KWA_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
- "Authenticator length %u", len);
- return -1;
- }
- attr->key_wrap_auth = pos;
- break;
- case ATTR_AUTH_TYPE:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
- "Type length %u", len);
- return -1;
- }
- attr->auth_type = pos;
- break;
- case ATTR_ENCR_TYPE:
- if (len != 2) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
- "Type length %u", len);
- return -1;
- }
- attr->encr_type = pos;
- break;
- case ATTR_NETWORK_INDEX:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
- "length %u", len);
- return -1;
- }
- attr->network_idx = pos;
- break;
- case ATTR_NETWORK_KEY_INDEX:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
- "length %u", len);
- return -1;
- }
- attr->network_key_idx = pos;
- break;
- case ATTR_MAC_ADDR:
- if (len != ETH_ALEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
- "length %u", len);
- return -1;
- }
- 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"
- " length %u", len);
- return -1;
- }
- attr->selected_registrar = pos;
- break;
- case ATTR_REQUEST_TYPE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
- "length %u", len);
- return -1;
- }
- attr->request_type = pos;
- break;
- case ATTR_RESPONSE_TYPE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
- "length %u", len);
- return -1;
- }
- attr->response_type = pos;
- break;
- case ATTR_MANUFACTURER:
- attr->manufacturer = pos;
- attr->manufacturer_len = len;
- break;
- case ATTR_MODEL_NAME:
- attr->model_name = pos;
- attr->model_name_len = len;
- break;
- case ATTR_MODEL_NUMBER:
- attr->model_number = pos;
- attr->model_number_len = len;
- break;
- case ATTR_SERIAL_NUMBER:
- attr->serial_number = pos;
- attr->serial_number_len = len;
- break;
- case ATTR_DEV_NAME:
- attr->dev_name = pos;
- attr->dev_name_len = len;
- break;
- case ATTR_PUBLIC_KEY:
- attr->public_key = pos;
- attr->public_key_len = len;
- break;
- case ATTR_ENCR_SETTINGS:
- attr->encr_settings = pos;
- attr->encr_settings_len = len;
- break;
- case ATTR_CRED:
- if (attr->num_cred >= MAX_CRED_COUNT) {
- wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
- "attribute (max %d credentials)",
- MAX_CRED_COUNT);
- break;
- }
- attr->cred[attr->num_cred] = pos;
- attr->cred_len[attr->num_cred] = len;
- attr->num_cred++;
- break;
- case ATTR_SSID:
- attr->ssid = pos;
- attr->ssid_len = len;
- break;
- case ATTR_NETWORK_KEY:
- 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 "
- "length %u", len);
- return -1;
- }
- attr->ap_setup_locked = pos;
- break;
- case ATTR_SETTINGS_DELAY_TIME:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
- "Time length %u", len);
- return -1;
- }
- attr->settings_delay_time = pos;
- break;
- case ATTR_NETWORK_KEY_SHAREABLE:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
- "Shareable length %u", len);
- return -1;
- }
- attr->network_key_shareable = pos;
- break;
- case ATTR_REQUEST_TO_ENROLL:
- if (len != 1) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
- "length %u", len);
- return -1;
- }
- attr->request_to_enroll = pos;
- break;
- case ATTR_AUTHORIZED_MACS:
- attr->authorized_macs = pos;
- attr->authorized_macs_len = len;
- break;
- case ATTR_REQUESTED_DEV_TYPE:
- if (len != WPS_DEV_TYPE_LEN) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
- "Type length %u", len);
- return -1;
- }
- if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
- wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
- "Type attribute (max %u types)",
- MAX_REQ_DEV_TYPE_COUNT);
- break;
- }
- attr->req_dev_type[attr->num_req_dev_type] = pos;
- attr->num_req_dev_type++;
- break;
- default:
- wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
- "len=%u", type, len);
- break;
- }
- return 0;
- }
- int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
- {
- const u8 *pos, *end;
- u16 type, len;
- os_memset(attr, 0, sizeof(*attr));
- pos = wpabuf_head(msg);
- end = pos + wpabuf_len(msg);
- while (pos < end) {
- if (end - pos < 4) {
- wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
- "%lu bytes remaining",
- (unsigned long) (end - pos));
- return -1;
- }
- type = WPA_GET_BE16(pos);
- pos += 2;
- len = WPA_GET_BE16(pos);
- pos += 2;
- wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
- type, len);
- if (len > end - pos) {
- wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
- return -1;
- }
- #ifdef WPS_WORKAROUNDS
- if (type == 0 && len == 0) {
- /*
- * Mac OS X 10.6 seems to be adding 0x00 padding to the
- * end of M1. Skip those to avoid interop issues.
- */
- int i;
- for (i = 0; i < end - pos; i++) {
- if (pos[i])
- break;
- }
- if (i == end - pos) {
- wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
- "unexpected message padding");
- break;
- }
- }
- #endif /* WPS_WORKAROUNDS */
- if (wps_set_attr(attr, type, pos, len) < 0)
- return -1;
- pos += len;
- }
- return 0;
- }
|