139beb93cSSam Leffler /* 239beb93cSSam Leffler * Wi-Fi Protected Setup - attribute parsing 339beb93cSSam Leffler * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 12f05cddf9SRui Paulo #include "wps_defs.h" 13f05cddf9SRui Paulo #include "wps_attr_parse.h" 1439beb93cSSam Leffler 15f05cddf9SRui Paulo #ifndef CONFIG_WPS_STRICT 16e28a4053SRui Paulo #define WPS_WORKAROUNDS 17f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 18f05cddf9SRui Paulo 19f05cddf9SRui Paulo 20f05cddf9SRui Paulo static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr, 21f05cddf9SRui Paulo u8 id, u8 len, const u8 *pos) 22f05cddf9SRui Paulo { 23f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u", 24f05cddf9SRui Paulo id, len); 25f05cddf9SRui Paulo switch (id) { 26f05cddf9SRui Paulo case WFA_ELEM_VERSION2: 27f05cddf9SRui Paulo if (len != 1) { 28f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length " 29f05cddf9SRui Paulo "%u", len); 30f05cddf9SRui Paulo return -1; 31f05cddf9SRui Paulo } 32f05cddf9SRui Paulo attr->version2 = pos; 33f05cddf9SRui Paulo break; 34f05cddf9SRui Paulo case WFA_ELEM_AUTHORIZEDMACS: 35f05cddf9SRui Paulo attr->authorized_macs = pos; 36f05cddf9SRui Paulo attr->authorized_macs_len = len; 37f05cddf9SRui Paulo break; 38f05cddf9SRui Paulo case WFA_ELEM_NETWORK_KEY_SHAREABLE: 39f05cddf9SRui Paulo if (len != 1) { 40f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key " 41f05cddf9SRui Paulo "Shareable length %u", len); 42f05cddf9SRui Paulo return -1; 43f05cddf9SRui Paulo } 44f05cddf9SRui Paulo attr->network_key_shareable = pos; 45f05cddf9SRui Paulo break; 46f05cddf9SRui Paulo case WFA_ELEM_REQUEST_TO_ENROLL: 47f05cddf9SRui Paulo if (len != 1) { 48f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll " 49f05cddf9SRui Paulo "length %u", len); 50f05cddf9SRui Paulo return -1; 51f05cddf9SRui Paulo } 52f05cddf9SRui Paulo attr->request_to_enroll = pos; 53f05cddf9SRui Paulo break; 54f05cddf9SRui Paulo case WFA_ELEM_SETTINGS_DELAY_TIME: 55f05cddf9SRui Paulo if (len != 1) { 56f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay " 57f05cddf9SRui Paulo "Time length %u", len); 58f05cddf9SRui Paulo return -1; 59f05cddf9SRui Paulo } 60f05cddf9SRui Paulo attr->settings_delay_time = pos; 61f05cddf9SRui Paulo break; 62*5b9c547cSRui Paulo case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS: 63*5b9c547cSRui Paulo if (len != 2) { 64*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Configuration Methods length %u", 65*5b9c547cSRui Paulo len); 66*5b9c547cSRui Paulo return -1; 67*5b9c547cSRui Paulo } 68*5b9c547cSRui Paulo attr->registrar_configuration_methods = pos; 69*5b9c547cSRui Paulo break; 70f05cddf9SRui Paulo default: 71f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor " 72f05cddf9SRui Paulo "Extension subelement %u", id); 73f05cddf9SRui Paulo break; 74f05cddf9SRui Paulo } 75f05cddf9SRui Paulo 76f05cddf9SRui Paulo return 0; 77f05cddf9SRui Paulo } 78f05cddf9SRui Paulo 79f05cddf9SRui Paulo 80f05cddf9SRui Paulo static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos, 81f05cddf9SRui Paulo u16 len) 82f05cddf9SRui Paulo { 83f05cddf9SRui Paulo const u8 *end = pos + len; 84f05cddf9SRui Paulo u8 id, elen; 85f05cddf9SRui Paulo 86*5b9c547cSRui Paulo while (pos + 2 <= end) { 87f05cddf9SRui Paulo id = *pos++; 88f05cddf9SRui Paulo elen = *pos++; 89f05cddf9SRui Paulo if (pos + elen > end) 90f05cddf9SRui Paulo break; 91f05cddf9SRui Paulo if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0) 92f05cddf9SRui Paulo return -1; 93f05cddf9SRui Paulo pos += elen; 94f05cddf9SRui Paulo } 95f05cddf9SRui Paulo 96f05cddf9SRui Paulo return 0; 97f05cddf9SRui Paulo } 98f05cddf9SRui Paulo 99f05cddf9SRui Paulo 100f05cddf9SRui Paulo static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos, 101f05cddf9SRui Paulo u16 len) 102f05cddf9SRui Paulo { 103f05cddf9SRui Paulo u32 vendor_id; 104f05cddf9SRui Paulo 105f05cddf9SRui Paulo if (len < 3) { 106f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension"); 107f05cddf9SRui Paulo return 0; 108f05cddf9SRui Paulo } 109f05cddf9SRui Paulo 110f05cddf9SRui Paulo vendor_id = WPA_GET_BE24(pos); 111f05cddf9SRui Paulo switch (vendor_id) { 112f05cddf9SRui Paulo case WPS_VENDOR_ID_WFA: 113f05cddf9SRui Paulo return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3); 114f05cddf9SRui Paulo } 115f05cddf9SRui Paulo 116f05cddf9SRui Paulo /* Handle unknown vendor extensions */ 117f05cddf9SRui Paulo 118f05cddf9SRui Paulo wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)", 119f05cddf9SRui Paulo vendor_id); 120f05cddf9SRui Paulo 121f05cddf9SRui Paulo if (len > WPS_MAX_VENDOR_EXT_LEN) { 122f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)", 123f05cddf9SRui Paulo len); 124f05cddf9SRui Paulo return -1; 125f05cddf9SRui Paulo } 126f05cddf9SRui Paulo 127f05cddf9SRui Paulo if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) { 128f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension " 129f05cddf9SRui Paulo "attribute (max %d vendor extensions)", 130f05cddf9SRui Paulo MAX_WPS_PARSE_VENDOR_EXT); 131f05cddf9SRui Paulo return -1; 132f05cddf9SRui Paulo } 133f05cddf9SRui Paulo attr->vendor_ext[attr->num_vendor_ext] = pos; 134f05cddf9SRui Paulo attr->vendor_ext_len[attr->num_vendor_ext] = len; 135f05cddf9SRui Paulo attr->num_vendor_ext++; 136f05cddf9SRui Paulo 137f05cddf9SRui Paulo return 0; 138f05cddf9SRui Paulo } 139e28a4053SRui Paulo 14039beb93cSSam Leffler 14139beb93cSSam Leffler static int wps_set_attr(struct wps_parse_attr *attr, u16 type, 14239beb93cSSam Leffler const u8 *pos, u16 len) 14339beb93cSSam Leffler { 14439beb93cSSam Leffler switch (type) { 14539beb93cSSam Leffler case ATTR_VERSION: 14639beb93cSSam Leffler if (len != 1) { 14739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", 14839beb93cSSam Leffler len); 14939beb93cSSam Leffler return -1; 15039beb93cSSam Leffler } 15139beb93cSSam Leffler attr->version = pos; 15239beb93cSSam Leffler break; 15339beb93cSSam Leffler case ATTR_MSG_TYPE: 15439beb93cSSam Leffler if (len != 1) { 15539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " 15639beb93cSSam Leffler "length %u", len); 15739beb93cSSam Leffler return -1; 15839beb93cSSam Leffler } 15939beb93cSSam Leffler attr->msg_type = pos; 16039beb93cSSam Leffler break; 16139beb93cSSam Leffler case ATTR_ENROLLEE_NONCE: 16239beb93cSSam Leffler if (len != WPS_NONCE_LEN) { 16339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " 16439beb93cSSam Leffler "length %u", len); 16539beb93cSSam Leffler return -1; 16639beb93cSSam Leffler } 16739beb93cSSam Leffler attr->enrollee_nonce = pos; 16839beb93cSSam Leffler break; 16939beb93cSSam Leffler case ATTR_REGISTRAR_NONCE: 17039beb93cSSam Leffler if (len != WPS_NONCE_LEN) { 17139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " 17239beb93cSSam Leffler "length %u", len); 17339beb93cSSam Leffler return -1; 17439beb93cSSam Leffler } 17539beb93cSSam Leffler attr->registrar_nonce = pos; 17639beb93cSSam Leffler break; 17739beb93cSSam Leffler case ATTR_UUID_E: 17839beb93cSSam Leffler if (len != WPS_UUID_LEN) { 17939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", 18039beb93cSSam Leffler len); 18139beb93cSSam Leffler return -1; 18239beb93cSSam Leffler } 18339beb93cSSam Leffler attr->uuid_e = pos; 18439beb93cSSam Leffler break; 18539beb93cSSam Leffler case ATTR_UUID_R: 18639beb93cSSam Leffler if (len != WPS_UUID_LEN) { 18739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", 18839beb93cSSam Leffler len); 18939beb93cSSam Leffler return -1; 19039beb93cSSam Leffler } 19139beb93cSSam Leffler attr->uuid_r = pos; 19239beb93cSSam Leffler break; 19339beb93cSSam Leffler case ATTR_AUTH_TYPE_FLAGS: 19439beb93cSSam Leffler if (len != 2) { 19539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 19639beb93cSSam Leffler "Type Flags length %u", len); 19739beb93cSSam Leffler return -1; 19839beb93cSSam Leffler } 19939beb93cSSam Leffler attr->auth_type_flags = pos; 20039beb93cSSam Leffler break; 20139beb93cSSam Leffler case ATTR_ENCR_TYPE_FLAGS: 20239beb93cSSam Leffler if (len != 2) { 20339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " 20439beb93cSSam Leffler "Flags length %u", len); 20539beb93cSSam Leffler return -1; 20639beb93cSSam Leffler } 20739beb93cSSam Leffler attr->encr_type_flags = pos; 20839beb93cSSam Leffler break; 20939beb93cSSam Leffler case ATTR_CONN_TYPE_FLAGS: 21039beb93cSSam Leffler if (len != 1) { 21139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " 21239beb93cSSam Leffler "Flags length %u", len); 21339beb93cSSam Leffler return -1; 21439beb93cSSam Leffler } 21539beb93cSSam Leffler attr->conn_type_flags = pos; 21639beb93cSSam Leffler break; 21739beb93cSSam Leffler case ATTR_CONFIG_METHODS: 21839beb93cSSam Leffler if (len != 2) { 21939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " 22039beb93cSSam Leffler "length %u", len); 22139beb93cSSam Leffler return -1; 22239beb93cSSam Leffler } 22339beb93cSSam Leffler attr->config_methods = pos; 22439beb93cSSam Leffler break; 22539beb93cSSam Leffler case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: 22639beb93cSSam Leffler if (len != 2) { 22739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " 22839beb93cSSam Leffler "Registrar Config Methods length %u", len); 22939beb93cSSam Leffler return -1; 23039beb93cSSam Leffler } 23139beb93cSSam Leffler attr->sel_reg_config_methods = pos; 23239beb93cSSam Leffler break; 23339beb93cSSam Leffler case ATTR_PRIMARY_DEV_TYPE: 234e28a4053SRui Paulo if (len != WPS_DEV_TYPE_LEN) { 23539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " 23639beb93cSSam Leffler "Type length %u", len); 23739beb93cSSam Leffler return -1; 23839beb93cSSam Leffler } 23939beb93cSSam Leffler attr->primary_dev_type = pos; 24039beb93cSSam Leffler break; 24139beb93cSSam Leffler case ATTR_RF_BANDS: 24239beb93cSSam Leffler if (len != 1) { 24339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " 24439beb93cSSam Leffler "%u", len); 24539beb93cSSam Leffler return -1; 24639beb93cSSam Leffler } 24739beb93cSSam Leffler attr->rf_bands = pos; 24839beb93cSSam Leffler break; 24939beb93cSSam Leffler case ATTR_ASSOC_STATE: 25039beb93cSSam Leffler if (len != 2) { 25139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " 25239beb93cSSam Leffler "length %u", len); 25339beb93cSSam Leffler return -1; 25439beb93cSSam Leffler } 25539beb93cSSam Leffler attr->assoc_state = pos; 25639beb93cSSam Leffler break; 25739beb93cSSam Leffler case ATTR_CONFIG_ERROR: 25839beb93cSSam Leffler if (len != 2) { 25939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " 26039beb93cSSam Leffler "Error length %u", len); 26139beb93cSSam Leffler return -1; 26239beb93cSSam Leffler } 26339beb93cSSam Leffler attr->config_error = pos; 26439beb93cSSam Leffler break; 26539beb93cSSam Leffler case ATTR_DEV_PASSWORD_ID: 26639beb93cSSam Leffler if (len != 2) { 26739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " 26839beb93cSSam Leffler "ID length %u", len); 26939beb93cSSam Leffler return -1; 27039beb93cSSam Leffler } 27139beb93cSSam Leffler attr->dev_password_id = pos; 27239beb93cSSam Leffler break; 273e28a4053SRui Paulo case ATTR_OOB_DEVICE_PASSWORD: 274*5b9c547cSRui Paulo if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 || 275f05cddf9SRui Paulo len > WPS_OOB_PUBKEY_HASH_LEN + 2 + 276*5b9c547cSRui Paulo WPS_OOB_DEVICE_PASSWORD_LEN || 277*5b9c547cSRui Paulo (len < WPS_OOB_PUBKEY_HASH_LEN + 2 + 278*5b9c547cSRui Paulo WPS_OOB_DEVICE_PASSWORD_MIN_LEN && 279*5b9c547cSRui Paulo WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) != 280*5b9c547cSRui Paulo DEV_PW_NFC_CONNECTION_HANDOVER)) { 281e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device " 282e28a4053SRui Paulo "Password length %u", len); 283e28a4053SRui Paulo return -1; 284e28a4053SRui Paulo } 285e28a4053SRui Paulo attr->oob_dev_password = pos; 286f05cddf9SRui Paulo attr->oob_dev_password_len = len; 287e28a4053SRui Paulo break; 28839beb93cSSam Leffler case ATTR_OS_VERSION: 28939beb93cSSam Leffler if (len != 4) { 29039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " 29139beb93cSSam Leffler "%u", len); 29239beb93cSSam Leffler return -1; 29339beb93cSSam Leffler } 29439beb93cSSam Leffler attr->os_version = pos; 29539beb93cSSam Leffler break; 29639beb93cSSam Leffler case ATTR_WPS_STATE: 29739beb93cSSam Leffler if (len != 1) { 29839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " 29939beb93cSSam Leffler "Setup State length %u", len); 30039beb93cSSam Leffler return -1; 30139beb93cSSam Leffler } 30239beb93cSSam Leffler attr->wps_state = pos; 30339beb93cSSam Leffler break; 30439beb93cSSam Leffler case ATTR_AUTHENTICATOR: 30539beb93cSSam Leffler if (len != WPS_AUTHENTICATOR_LEN) { 30639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " 30739beb93cSSam Leffler "length %u", len); 30839beb93cSSam Leffler return -1; 30939beb93cSSam Leffler } 31039beb93cSSam Leffler attr->authenticator = pos; 31139beb93cSSam Leffler break; 31239beb93cSSam Leffler case ATTR_R_HASH1: 31339beb93cSSam Leffler if (len != WPS_HASH_LEN) { 31439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", 31539beb93cSSam Leffler len); 31639beb93cSSam Leffler return -1; 31739beb93cSSam Leffler } 31839beb93cSSam Leffler attr->r_hash1 = pos; 31939beb93cSSam Leffler break; 32039beb93cSSam Leffler case ATTR_R_HASH2: 32139beb93cSSam Leffler if (len != WPS_HASH_LEN) { 32239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", 32339beb93cSSam Leffler len); 32439beb93cSSam Leffler return -1; 32539beb93cSSam Leffler } 32639beb93cSSam Leffler attr->r_hash2 = pos; 32739beb93cSSam Leffler break; 32839beb93cSSam Leffler case ATTR_E_HASH1: 32939beb93cSSam Leffler if (len != WPS_HASH_LEN) { 33039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", 33139beb93cSSam Leffler len); 33239beb93cSSam Leffler return -1; 33339beb93cSSam Leffler } 33439beb93cSSam Leffler attr->e_hash1 = pos; 33539beb93cSSam Leffler break; 33639beb93cSSam Leffler case ATTR_E_HASH2: 33739beb93cSSam Leffler if (len != WPS_HASH_LEN) { 33839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", 33939beb93cSSam Leffler len); 34039beb93cSSam Leffler return -1; 34139beb93cSSam Leffler } 34239beb93cSSam Leffler attr->e_hash2 = pos; 34339beb93cSSam Leffler break; 34439beb93cSSam Leffler case ATTR_R_SNONCE1: 34539beb93cSSam Leffler if (len != WPS_SECRET_NONCE_LEN) { 34639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " 34739beb93cSSam Leffler "%u", len); 34839beb93cSSam Leffler return -1; 34939beb93cSSam Leffler } 35039beb93cSSam Leffler attr->r_snonce1 = pos; 35139beb93cSSam Leffler break; 35239beb93cSSam Leffler case ATTR_R_SNONCE2: 35339beb93cSSam Leffler if (len != WPS_SECRET_NONCE_LEN) { 35439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " 35539beb93cSSam Leffler "%u", len); 35639beb93cSSam Leffler return -1; 35739beb93cSSam Leffler } 35839beb93cSSam Leffler attr->r_snonce2 = pos; 35939beb93cSSam Leffler break; 36039beb93cSSam Leffler case ATTR_E_SNONCE1: 36139beb93cSSam Leffler if (len != WPS_SECRET_NONCE_LEN) { 36239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " 36339beb93cSSam Leffler "%u", len); 36439beb93cSSam Leffler return -1; 36539beb93cSSam Leffler } 36639beb93cSSam Leffler attr->e_snonce1 = pos; 36739beb93cSSam Leffler break; 36839beb93cSSam Leffler case ATTR_E_SNONCE2: 36939beb93cSSam Leffler if (len != WPS_SECRET_NONCE_LEN) { 37039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " 37139beb93cSSam Leffler "%u", len); 37239beb93cSSam Leffler return -1; 37339beb93cSSam Leffler } 37439beb93cSSam Leffler attr->e_snonce2 = pos; 37539beb93cSSam Leffler break; 37639beb93cSSam Leffler case ATTR_KEY_WRAP_AUTH: 37739beb93cSSam Leffler if (len != WPS_KWA_LEN) { 37839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " 37939beb93cSSam Leffler "Authenticator length %u", len); 38039beb93cSSam Leffler return -1; 38139beb93cSSam Leffler } 38239beb93cSSam Leffler attr->key_wrap_auth = pos; 38339beb93cSSam Leffler break; 38439beb93cSSam Leffler case ATTR_AUTH_TYPE: 38539beb93cSSam Leffler if (len != 2) { 38639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 38739beb93cSSam Leffler "Type length %u", len); 38839beb93cSSam Leffler return -1; 38939beb93cSSam Leffler } 39039beb93cSSam Leffler attr->auth_type = pos; 39139beb93cSSam Leffler break; 39239beb93cSSam Leffler case ATTR_ENCR_TYPE: 39339beb93cSSam Leffler if (len != 2) { 39439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " 39539beb93cSSam Leffler "Type length %u", len); 39639beb93cSSam Leffler return -1; 39739beb93cSSam Leffler } 39839beb93cSSam Leffler attr->encr_type = pos; 39939beb93cSSam Leffler break; 40039beb93cSSam Leffler case ATTR_NETWORK_INDEX: 40139beb93cSSam Leffler if (len != 1) { 40239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " 40339beb93cSSam Leffler "length %u", len); 40439beb93cSSam Leffler return -1; 40539beb93cSSam Leffler } 40639beb93cSSam Leffler attr->network_idx = pos; 40739beb93cSSam Leffler break; 40839beb93cSSam Leffler case ATTR_NETWORK_KEY_INDEX: 40939beb93cSSam Leffler if (len != 1) { 41039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " 41139beb93cSSam Leffler "length %u", len); 41239beb93cSSam Leffler return -1; 41339beb93cSSam Leffler } 41439beb93cSSam Leffler attr->network_key_idx = pos; 41539beb93cSSam Leffler break; 41639beb93cSSam Leffler case ATTR_MAC_ADDR: 41739beb93cSSam Leffler if (len != ETH_ALEN) { 41839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " 41939beb93cSSam Leffler "length %u", len); 42039beb93cSSam Leffler return -1; 42139beb93cSSam Leffler } 42239beb93cSSam Leffler attr->mac_addr = pos; 42339beb93cSSam Leffler break; 42439beb93cSSam Leffler case ATTR_SELECTED_REGISTRAR: 42539beb93cSSam Leffler if (len != 1) { 42639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" 42739beb93cSSam Leffler " length %u", len); 42839beb93cSSam Leffler return -1; 42939beb93cSSam Leffler } 43039beb93cSSam Leffler attr->selected_registrar = pos; 43139beb93cSSam Leffler break; 43239beb93cSSam Leffler case ATTR_REQUEST_TYPE: 43339beb93cSSam Leffler if (len != 1) { 43439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " 43539beb93cSSam Leffler "length %u", len); 43639beb93cSSam Leffler return -1; 43739beb93cSSam Leffler } 43839beb93cSSam Leffler attr->request_type = pos; 43939beb93cSSam Leffler break; 44039beb93cSSam Leffler case ATTR_RESPONSE_TYPE: 44139beb93cSSam Leffler if (len != 1) { 44239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " 44339beb93cSSam Leffler "length %u", len); 44439beb93cSSam Leffler return -1; 44539beb93cSSam Leffler } 446e28a4053SRui Paulo attr->response_type = pos; 44739beb93cSSam Leffler break; 44839beb93cSSam Leffler case ATTR_MANUFACTURER: 44939beb93cSSam Leffler attr->manufacturer = pos; 45039beb93cSSam Leffler attr->manufacturer_len = len; 45139beb93cSSam Leffler break; 45239beb93cSSam Leffler case ATTR_MODEL_NAME: 45339beb93cSSam Leffler attr->model_name = pos; 45439beb93cSSam Leffler attr->model_name_len = len; 45539beb93cSSam Leffler break; 45639beb93cSSam Leffler case ATTR_MODEL_NUMBER: 45739beb93cSSam Leffler attr->model_number = pos; 45839beb93cSSam Leffler attr->model_number_len = len; 45939beb93cSSam Leffler break; 46039beb93cSSam Leffler case ATTR_SERIAL_NUMBER: 46139beb93cSSam Leffler attr->serial_number = pos; 46239beb93cSSam Leffler attr->serial_number_len = len; 46339beb93cSSam Leffler break; 46439beb93cSSam Leffler case ATTR_DEV_NAME: 46539beb93cSSam Leffler attr->dev_name = pos; 46639beb93cSSam Leffler attr->dev_name_len = len; 46739beb93cSSam Leffler break; 46839beb93cSSam Leffler case ATTR_PUBLIC_KEY: 46939beb93cSSam Leffler attr->public_key = pos; 47039beb93cSSam Leffler attr->public_key_len = len; 47139beb93cSSam Leffler break; 47239beb93cSSam Leffler case ATTR_ENCR_SETTINGS: 47339beb93cSSam Leffler attr->encr_settings = pos; 47439beb93cSSam Leffler attr->encr_settings_len = len; 47539beb93cSSam Leffler break; 47639beb93cSSam Leffler case ATTR_CRED: 47739beb93cSSam Leffler if (attr->num_cred >= MAX_CRED_COUNT) { 47839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " 47939beb93cSSam Leffler "attribute (max %d credentials)", 48039beb93cSSam Leffler MAX_CRED_COUNT); 48139beb93cSSam Leffler break; 48239beb93cSSam Leffler } 48339beb93cSSam Leffler attr->cred[attr->num_cred] = pos; 48439beb93cSSam Leffler attr->cred_len[attr->num_cred] = len; 48539beb93cSSam Leffler attr->num_cred++; 48639beb93cSSam Leffler break; 48739beb93cSSam Leffler case ATTR_SSID: 48839beb93cSSam Leffler attr->ssid = pos; 48939beb93cSSam Leffler attr->ssid_len = len; 49039beb93cSSam Leffler break; 49139beb93cSSam Leffler case ATTR_NETWORK_KEY: 49239beb93cSSam Leffler attr->network_key = pos; 49339beb93cSSam Leffler attr->network_key_len = len; 49439beb93cSSam Leffler break; 4953157ba21SRui Paulo case ATTR_AP_SETUP_LOCKED: 4963157ba21SRui Paulo if (len != 1) { 4973157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked " 4983157ba21SRui Paulo "length %u", len); 4993157ba21SRui Paulo return -1; 5003157ba21SRui Paulo } 5013157ba21SRui Paulo attr->ap_setup_locked = pos; 5023157ba21SRui Paulo break; 503f05cddf9SRui Paulo case ATTR_REQUESTED_DEV_TYPE: 504f05cddf9SRui Paulo if (len != WPS_DEV_TYPE_LEN) { 505f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device " 506f05cddf9SRui Paulo "Type length %u", len); 507f05cddf9SRui Paulo return -1; 508f05cddf9SRui Paulo } 509f05cddf9SRui Paulo if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) { 510f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device " 511f05cddf9SRui Paulo "Type attribute (max %u types)", 512f05cddf9SRui Paulo MAX_REQ_DEV_TYPE_COUNT); 513f05cddf9SRui Paulo break; 514f05cddf9SRui Paulo } 515f05cddf9SRui Paulo attr->req_dev_type[attr->num_req_dev_type] = pos; 516f05cddf9SRui Paulo attr->num_req_dev_type++; 517f05cddf9SRui Paulo break; 518f05cddf9SRui Paulo case ATTR_SECONDARY_DEV_TYPE_LIST: 519f05cddf9SRui Paulo if (len > WPS_SEC_DEV_TYPE_MAX_LEN || 520f05cddf9SRui Paulo (len % WPS_DEV_TYPE_LEN) > 0) { 521f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device " 522f05cddf9SRui Paulo "Type length %u", len); 523f05cddf9SRui Paulo return -1; 524f05cddf9SRui Paulo } 525f05cddf9SRui Paulo attr->sec_dev_type_list = pos; 526f05cddf9SRui Paulo attr->sec_dev_type_list_len = len; 527f05cddf9SRui Paulo break; 528f05cddf9SRui Paulo case ATTR_VENDOR_EXT: 529f05cddf9SRui Paulo if (wps_parse_vendor_ext(attr, pos, len) < 0) 530f05cddf9SRui Paulo return -1; 531f05cddf9SRui Paulo break; 532f05cddf9SRui Paulo case ATTR_AP_CHANNEL: 533f05cddf9SRui Paulo if (len != 2) { 534f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel " 535f05cddf9SRui Paulo "length %u", len); 536f05cddf9SRui Paulo return -1; 537f05cddf9SRui Paulo } 538f05cddf9SRui Paulo attr->ap_channel = pos; 539f05cddf9SRui Paulo break; 54039beb93cSSam Leffler default: 54139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " 54239beb93cSSam Leffler "len=%u", type, len); 54339beb93cSSam Leffler break; 54439beb93cSSam Leffler } 54539beb93cSSam Leffler 54639beb93cSSam Leffler return 0; 54739beb93cSSam Leffler } 54839beb93cSSam Leffler 54939beb93cSSam Leffler 55039beb93cSSam Leffler int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) 55139beb93cSSam Leffler { 55239beb93cSSam Leffler const u8 *pos, *end; 55339beb93cSSam Leffler u16 type, len; 554f05cddf9SRui Paulo #ifdef WPS_WORKAROUNDS 555f05cddf9SRui Paulo u16 prev_type = 0; 556f05cddf9SRui Paulo #endif /* WPS_WORKAROUNDS */ 55739beb93cSSam Leffler 55839beb93cSSam Leffler os_memset(attr, 0, sizeof(*attr)); 55939beb93cSSam Leffler pos = wpabuf_head(msg); 56039beb93cSSam Leffler end = pos + wpabuf_len(msg); 56139beb93cSSam Leffler 56239beb93cSSam Leffler while (pos < end) { 56339beb93cSSam Leffler if (end - pos < 4) { 56439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid message - " 56539beb93cSSam Leffler "%lu bytes remaining", 56639beb93cSSam Leffler (unsigned long) (end - pos)); 56739beb93cSSam Leffler return -1; 56839beb93cSSam Leffler } 56939beb93cSSam Leffler 57039beb93cSSam Leffler type = WPA_GET_BE16(pos); 57139beb93cSSam Leffler pos += 2; 57239beb93cSSam Leffler len = WPA_GET_BE16(pos); 57339beb93cSSam Leffler pos += 2; 574f05cddf9SRui Paulo wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u", 57539beb93cSSam Leffler type, len); 57639beb93cSSam Leffler if (len > end - pos) { 57739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); 578f05cddf9SRui Paulo wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg); 579f05cddf9SRui Paulo #ifdef WPS_WORKAROUNDS 580f05cddf9SRui Paulo /* 581f05cddf9SRui Paulo * Some deployed APs seem to have a bug in encoding of 582f05cddf9SRui Paulo * Network Key attribute in the Credential attribute 583f05cddf9SRui Paulo * where they add an extra octet after the Network Key 584f05cddf9SRui Paulo * attribute at least when open network is being 585f05cddf9SRui Paulo * provisioned. 586f05cddf9SRui Paulo */ 587f05cddf9SRui Paulo if ((type & 0xff00) != 0x1000 && 588f05cddf9SRui Paulo prev_type == ATTR_NETWORK_KEY) { 589f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - try " 590f05cddf9SRui Paulo "to skip unexpected octet after " 591f05cddf9SRui Paulo "Network Key"); 592f05cddf9SRui Paulo pos -= 3; 593f05cddf9SRui Paulo continue; 594f05cddf9SRui Paulo } 595f05cddf9SRui Paulo #endif /* WPS_WORKAROUNDS */ 59639beb93cSSam Leffler return -1; 59739beb93cSSam Leffler } 59839beb93cSSam Leffler 599e28a4053SRui Paulo #ifdef WPS_WORKAROUNDS 600e28a4053SRui Paulo if (type == 0 && len == 0) { 601e28a4053SRui Paulo /* 602e28a4053SRui Paulo * Mac OS X 10.6 seems to be adding 0x00 padding to the 603e28a4053SRui Paulo * end of M1. Skip those to avoid interop issues. 604e28a4053SRui Paulo */ 605e28a4053SRui Paulo int i; 606e28a4053SRui Paulo for (i = 0; i < end - pos; i++) { 607e28a4053SRui Paulo if (pos[i]) 608e28a4053SRui Paulo break; 609e28a4053SRui Paulo } 610e28a4053SRui Paulo if (i == end - pos) { 611e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " 612e28a4053SRui Paulo "unexpected message padding"); 613e28a4053SRui Paulo break; 614e28a4053SRui Paulo } 615e28a4053SRui Paulo } 616e28a4053SRui Paulo #endif /* WPS_WORKAROUNDS */ 617e28a4053SRui Paulo 61839beb93cSSam Leffler if (wps_set_attr(attr, type, pos, len) < 0) 61939beb93cSSam Leffler return -1; 62039beb93cSSam Leffler 621f05cddf9SRui Paulo #ifdef WPS_WORKAROUNDS 622f05cddf9SRui Paulo prev_type = type; 623f05cddf9SRui Paulo #endif /* WPS_WORKAROUNDS */ 62439beb93cSSam Leffler pos += len; 62539beb93cSSam Leffler } 62639beb93cSSam Leffler 62739beb93cSSam Leffler return 0; 62839beb93cSSam Leffler } 629