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