wps_attr_parse.c revision 189251
1189251Ssam/* 2189251Ssam * Wi-Fi Protected Setup - attribute parsing 3189251Ssam * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18189251Ssam#include "wps_i.h" 19189251Ssam 20189251Ssam 21189251Ssamstatic int wps_set_attr(struct wps_parse_attr *attr, u16 type, 22189251Ssam const u8 *pos, u16 len) 23189251Ssam{ 24189251Ssam switch (type) { 25189251Ssam case ATTR_VERSION: 26189251Ssam if (len != 1) { 27189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", 28189251Ssam len); 29189251Ssam return -1; 30189251Ssam } 31189251Ssam attr->version = pos; 32189251Ssam break; 33189251Ssam case ATTR_MSG_TYPE: 34189251Ssam if (len != 1) { 35189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " 36189251Ssam "length %u", len); 37189251Ssam return -1; 38189251Ssam } 39189251Ssam attr->msg_type = pos; 40189251Ssam break; 41189251Ssam case ATTR_ENROLLEE_NONCE: 42189251Ssam if (len != WPS_NONCE_LEN) { 43189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " 44189251Ssam "length %u", len); 45189251Ssam return -1; 46189251Ssam } 47189251Ssam attr->enrollee_nonce = pos; 48189251Ssam break; 49189251Ssam case ATTR_REGISTRAR_NONCE: 50189251Ssam if (len != WPS_NONCE_LEN) { 51189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " 52189251Ssam "length %u", len); 53189251Ssam return -1; 54189251Ssam } 55189251Ssam attr->registrar_nonce = pos; 56189251Ssam break; 57189251Ssam case ATTR_UUID_E: 58189251Ssam if (len != WPS_UUID_LEN) { 59189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", 60189251Ssam len); 61189251Ssam return -1; 62189251Ssam } 63189251Ssam attr->uuid_e = pos; 64189251Ssam break; 65189251Ssam case ATTR_UUID_R: 66189251Ssam if (len != WPS_UUID_LEN) { 67189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", 68189251Ssam len); 69189251Ssam return -1; 70189251Ssam } 71189251Ssam attr->uuid_r = pos; 72189251Ssam break; 73189251Ssam case ATTR_AUTH_TYPE_FLAGS: 74189251Ssam if (len != 2) { 75189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 76189251Ssam "Type Flags length %u", len); 77189251Ssam return -1; 78189251Ssam } 79189251Ssam attr->auth_type_flags = pos; 80189251Ssam break; 81189251Ssam case ATTR_ENCR_TYPE_FLAGS: 82189251Ssam if (len != 2) { 83189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " 84189251Ssam "Flags length %u", len); 85189251Ssam return -1; 86189251Ssam } 87189251Ssam attr->encr_type_flags = pos; 88189251Ssam break; 89189251Ssam case ATTR_CONN_TYPE_FLAGS: 90189251Ssam if (len != 1) { 91189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " 92189251Ssam "Flags length %u", len); 93189251Ssam return -1; 94189251Ssam } 95189251Ssam attr->conn_type_flags = pos; 96189251Ssam break; 97189251Ssam case ATTR_CONFIG_METHODS: 98189251Ssam if (len != 2) { 99189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " 100189251Ssam "length %u", len); 101189251Ssam return -1; 102189251Ssam } 103189251Ssam attr->config_methods = pos; 104189251Ssam break; 105189251Ssam case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: 106189251Ssam if (len != 2) { 107189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " 108189251Ssam "Registrar Config Methods length %u", len); 109189251Ssam return -1; 110189251Ssam } 111189251Ssam attr->sel_reg_config_methods = pos; 112189251Ssam break; 113189251Ssam case ATTR_PRIMARY_DEV_TYPE: 114189251Ssam if (len != sizeof(struct wps_dev_type)) { 115189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " 116189251Ssam "Type length %u", len); 117189251Ssam return -1; 118189251Ssam } 119189251Ssam attr->primary_dev_type = pos; 120189251Ssam break; 121189251Ssam case ATTR_RF_BANDS: 122189251Ssam if (len != 1) { 123189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " 124189251Ssam "%u", len); 125189251Ssam return -1; 126189251Ssam } 127189251Ssam attr->rf_bands = pos; 128189251Ssam break; 129189251Ssam case ATTR_ASSOC_STATE: 130189251Ssam if (len != 2) { 131189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " 132189251Ssam "length %u", len); 133189251Ssam return -1; 134189251Ssam } 135189251Ssam attr->assoc_state = pos; 136189251Ssam break; 137189251Ssam case ATTR_CONFIG_ERROR: 138189251Ssam if (len != 2) { 139189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " 140189251Ssam "Error length %u", len); 141189251Ssam return -1; 142189251Ssam } 143189251Ssam attr->config_error = pos; 144189251Ssam break; 145189251Ssam case ATTR_DEV_PASSWORD_ID: 146189251Ssam if (len != 2) { 147189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " 148189251Ssam "ID length %u", len); 149189251Ssam return -1; 150189251Ssam } 151189251Ssam attr->dev_password_id = pos; 152189251Ssam break; 153189251Ssam case ATTR_OS_VERSION: 154189251Ssam if (len != 4) { 155189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " 156189251Ssam "%u", len); 157189251Ssam return -1; 158189251Ssam } 159189251Ssam attr->os_version = pos; 160189251Ssam break; 161189251Ssam case ATTR_WPS_STATE: 162189251Ssam if (len != 1) { 163189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " 164189251Ssam "Setup State length %u", len); 165189251Ssam return -1; 166189251Ssam } 167189251Ssam attr->wps_state = pos; 168189251Ssam break; 169189251Ssam case ATTR_AUTHENTICATOR: 170189251Ssam if (len != WPS_AUTHENTICATOR_LEN) { 171189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " 172189251Ssam "length %u", len); 173189251Ssam return -1; 174189251Ssam } 175189251Ssam attr->authenticator = pos; 176189251Ssam break; 177189251Ssam case ATTR_R_HASH1: 178189251Ssam if (len != WPS_HASH_LEN) { 179189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", 180189251Ssam len); 181189251Ssam return -1; 182189251Ssam } 183189251Ssam attr->r_hash1 = pos; 184189251Ssam break; 185189251Ssam case ATTR_R_HASH2: 186189251Ssam if (len != WPS_HASH_LEN) { 187189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", 188189251Ssam len); 189189251Ssam return -1; 190189251Ssam } 191189251Ssam attr->r_hash2 = pos; 192189251Ssam break; 193189251Ssam case ATTR_E_HASH1: 194189251Ssam if (len != WPS_HASH_LEN) { 195189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", 196189251Ssam len); 197189251Ssam return -1; 198189251Ssam } 199189251Ssam attr->e_hash1 = pos; 200189251Ssam break; 201189251Ssam case ATTR_E_HASH2: 202189251Ssam if (len != WPS_HASH_LEN) { 203189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", 204189251Ssam len); 205189251Ssam return -1; 206189251Ssam } 207189251Ssam attr->e_hash2 = pos; 208189251Ssam break; 209189251Ssam case ATTR_R_SNONCE1: 210189251Ssam if (len != WPS_SECRET_NONCE_LEN) { 211189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " 212189251Ssam "%u", len); 213189251Ssam return -1; 214189251Ssam } 215189251Ssam attr->r_snonce1 = pos; 216189251Ssam break; 217189251Ssam case ATTR_R_SNONCE2: 218189251Ssam if (len != WPS_SECRET_NONCE_LEN) { 219189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " 220189251Ssam "%u", len); 221189251Ssam return -1; 222189251Ssam } 223189251Ssam attr->r_snonce2 = pos; 224189251Ssam break; 225189251Ssam case ATTR_E_SNONCE1: 226189251Ssam if (len != WPS_SECRET_NONCE_LEN) { 227189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " 228189251Ssam "%u", len); 229189251Ssam return -1; 230189251Ssam } 231189251Ssam attr->e_snonce1 = pos; 232189251Ssam break; 233189251Ssam case ATTR_E_SNONCE2: 234189251Ssam if (len != WPS_SECRET_NONCE_LEN) { 235189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " 236189251Ssam "%u", len); 237189251Ssam return -1; 238189251Ssam } 239189251Ssam attr->e_snonce2 = pos; 240189251Ssam break; 241189251Ssam case ATTR_KEY_WRAP_AUTH: 242189251Ssam if (len != WPS_KWA_LEN) { 243189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " 244189251Ssam "Authenticator length %u", len); 245189251Ssam return -1; 246189251Ssam } 247189251Ssam attr->key_wrap_auth = pos; 248189251Ssam break; 249189251Ssam case ATTR_AUTH_TYPE: 250189251Ssam if (len != 2) { 251189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 252189251Ssam "Type length %u", len); 253189251Ssam return -1; 254189251Ssam } 255189251Ssam attr->auth_type = pos; 256189251Ssam break; 257189251Ssam case ATTR_ENCR_TYPE: 258189251Ssam if (len != 2) { 259189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " 260189251Ssam "Type length %u", len); 261189251Ssam return -1; 262189251Ssam } 263189251Ssam attr->encr_type = pos; 264189251Ssam break; 265189251Ssam case ATTR_NETWORK_INDEX: 266189251Ssam if (len != 1) { 267189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " 268189251Ssam "length %u", len); 269189251Ssam return -1; 270189251Ssam } 271189251Ssam attr->network_idx = pos; 272189251Ssam break; 273189251Ssam case ATTR_NETWORK_KEY_INDEX: 274189251Ssam if (len != 1) { 275189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " 276189251Ssam "length %u", len); 277189251Ssam return -1; 278189251Ssam } 279189251Ssam attr->network_key_idx = pos; 280189251Ssam break; 281189251Ssam case ATTR_MAC_ADDR: 282189251Ssam if (len != ETH_ALEN) { 283189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " 284189251Ssam "length %u", len); 285189251Ssam return -1; 286189251Ssam } 287189251Ssam attr->mac_addr = pos; 288189251Ssam break; 289189251Ssam case ATTR_KEY_PROVIDED_AUTO: 290189251Ssam if (len != 1) { 291189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided " 292189251Ssam "Automatically length %u", len); 293189251Ssam return -1; 294189251Ssam } 295189251Ssam attr->key_prov_auto = pos; 296189251Ssam break; 297189251Ssam case ATTR_802_1X_ENABLED: 298189251Ssam if (len != 1) { 299189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled " 300189251Ssam "length %u", len); 301189251Ssam return -1; 302189251Ssam } 303189251Ssam attr->dot1x_enabled = pos; 304189251Ssam break; 305189251Ssam case ATTR_SELECTED_REGISTRAR: 306189251Ssam if (len != 1) { 307189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" 308189251Ssam " length %u", len); 309189251Ssam return -1; 310189251Ssam } 311189251Ssam attr->selected_registrar = pos; 312189251Ssam break; 313189251Ssam case ATTR_REQUEST_TYPE: 314189251Ssam if (len != 1) { 315189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " 316189251Ssam "length %u", len); 317189251Ssam return -1; 318189251Ssam } 319189251Ssam attr->request_type = pos; 320189251Ssam break; 321189251Ssam case ATTR_RESPONSE_TYPE: 322189251Ssam if (len != 1) { 323189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " 324189251Ssam "length %u", len); 325189251Ssam return -1; 326189251Ssam } 327189251Ssam attr->request_type = pos; 328189251Ssam break; 329189251Ssam case ATTR_MANUFACTURER: 330189251Ssam attr->manufacturer = pos; 331189251Ssam attr->manufacturer_len = len; 332189251Ssam break; 333189251Ssam case ATTR_MODEL_NAME: 334189251Ssam attr->model_name = pos; 335189251Ssam attr->model_name_len = len; 336189251Ssam break; 337189251Ssam case ATTR_MODEL_NUMBER: 338189251Ssam attr->model_number = pos; 339189251Ssam attr->model_number_len = len; 340189251Ssam break; 341189251Ssam case ATTR_SERIAL_NUMBER: 342189251Ssam attr->serial_number = pos; 343189251Ssam attr->serial_number_len = len; 344189251Ssam break; 345189251Ssam case ATTR_DEV_NAME: 346189251Ssam attr->dev_name = pos; 347189251Ssam attr->dev_name_len = len; 348189251Ssam break; 349189251Ssam case ATTR_PUBLIC_KEY: 350189251Ssam attr->public_key = pos; 351189251Ssam attr->public_key_len = len; 352189251Ssam break; 353189251Ssam case ATTR_ENCR_SETTINGS: 354189251Ssam attr->encr_settings = pos; 355189251Ssam attr->encr_settings_len = len; 356189251Ssam break; 357189251Ssam case ATTR_CRED: 358189251Ssam if (attr->num_cred >= MAX_CRED_COUNT) { 359189251Ssam wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " 360189251Ssam "attribute (max %d credentials)", 361189251Ssam MAX_CRED_COUNT); 362189251Ssam break; 363189251Ssam } 364189251Ssam attr->cred[attr->num_cred] = pos; 365189251Ssam attr->cred_len[attr->num_cred] = len; 366189251Ssam attr->num_cred++; 367189251Ssam break; 368189251Ssam case ATTR_SSID: 369189251Ssam attr->ssid = pos; 370189251Ssam attr->ssid_len = len; 371189251Ssam break; 372189251Ssam case ATTR_NETWORK_KEY: 373189251Ssam attr->network_key = pos; 374189251Ssam attr->network_key_len = len; 375189251Ssam break; 376189251Ssam case ATTR_EAP_TYPE: 377189251Ssam attr->eap_type = pos; 378189251Ssam attr->eap_type_len = len; 379189251Ssam break; 380189251Ssam case ATTR_EAP_IDENTITY: 381189251Ssam attr->eap_identity = pos; 382189251Ssam attr->eap_identity_len = len; 383189251Ssam break; 384189251Ssam default: 385189251Ssam wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " 386189251Ssam "len=%u", type, len); 387189251Ssam break; 388189251Ssam } 389189251Ssam 390189251Ssam return 0; 391189251Ssam} 392189251Ssam 393189251Ssam 394189251Ssamint wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) 395189251Ssam{ 396189251Ssam const u8 *pos, *end; 397189251Ssam u16 type, len; 398189251Ssam 399189251Ssam os_memset(attr, 0, sizeof(*attr)); 400189251Ssam pos = wpabuf_head(msg); 401189251Ssam end = pos + wpabuf_len(msg); 402189251Ssam 403189251Ssam while (pos < end) { 404189251Ssam if (end - pos < 4) { 405189251Ssam wpa_printf(MSG_DEBUG, "WPS: Invalid message - " 406189251Ssam "%lu bytes remaining", 407189251Ssam (unsigned long) (end - pos)); 408189251Ssam return -1; 409189251Ssam } 410189251Ssam 411189251Ssam type = WPA_GET_BE16(pos); 412189251Ssam pos += 2; 413189251Ssam len = WPA_GET_BE16(pos); 414189251Ssam pos += 2; 415189251Ssam wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u", 416189251Ssam type, len); 417189251Ssam if (len > end - pos) { 418189251Ssam wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); 419189251Ssam return -1; 420189251Ssam } 421189251Ssam 422189251Ssam if (wps_set_attr(attr, type, pos, len) < 0) 423189251Ssam return -1; 424189251Ssam 425189251Ssam pos += len; 426189251Ssam } 427189251Ssam 428189251Ssam return 0; 429189251Ssam} 430