1 /* 2 * Wi-Fi Protected Setup - attribute parsing 3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "wps_i.h" 19 20 #define WPS_WORKAROUNDS 21 22 23 static int wps_set_attr(struct wps_parse_attr *attr, u16 type, 24 const u8 *pos, u16 len) 25 { 26 switch (type) { 27 case ATTR_VERSION: 28 if (len != 1) { 29 wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", 30 len); 31 return -1; 32 } 33 attr->version = pos; 34 break; 35 case ATTR_MSG_TYPE: 36 if (len != 1) { 37 wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " 38 "length %u", len); 39 return -1; 40 } 41 attr->msg_type = pos; 42 break; 43 case ATTR_ENROLLEE_NONCE: 44 if (len != WPS_NONCE_LEN) { 45 wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " 46 "length %u", len); 47 return -1; 48 } 49 attr->enrollee_nonce = pos; 50 break; 51 case ATTR_REGISTRAR_NONCE: 52 if (len != WPS_NONCE_LEN) { 53 wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " 54 "length %u", len); 55 return -1; 56 } 57 attr->registrar_nonce = pos; 58 break; 59 case ATTR_UUID_E: 60 if (len != WPS_UUID_LEN) { 61 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", 62 len); 63 return -1; 64 } 65 attr->uuid_e = pos; 66 break; 67 case ATTR_UUID_R: 68 if (len != WPS_UUID_LEN) { 69 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", 70 len); 71 return -1; 72 } 73 attr->uuid_r = pos; 74 break; 75 case ATTR_AUTH_TYPE_FLAGS: 76 if (len != 2) { 77 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 78 "Type Flags length %u", len); 79 return -1; 80 } 81 attr->auth_type_flags = pos; 82 break; 83 case ATTR_ENCR_TYPE_FLAGS: 84 if (len != 2) { 85 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " 86 "Flags length %u", len); 87 return -1; 88 } 89 attr->encr_type_flags = pos; 90 break; 91 case ATTR_CONN_TYPE_FLAGS: 92 if (len != 1) { 93 wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " 94 "Flags length %u", len); 95 return -1; 96 } 97 attr->conn_type_flags = pos; 98 break; 99 case ATTR_CONFIG_METHODS: 100 if (len != 2) { 101 wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " 102 "length %u", len); 103 return -1; 104 } 105 attr->config_methods = pos; 106 break; 107 case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: 108 if (len != 2) { 109 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " 110 "Registrar Config Methods length %u", len); 111 return -1; 112 } 113 attr->sel_reg_config_methods = pos; 114 break; 115 case ATTR_PRIMARY_DEV_TYPE: 116 if (len != WPS_DEV_TYPE_LEN) { 117 wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " 118 "Type length %u", len); 119 return -1; 120 } 121 attr->primary_dev_type = pos; 122 break; 123 case ATTR_RF_BANDS: 124 if (len != 1) { 125 wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " 126 "%u", len); 127 return -1; 128 } 129 attr->rf_bands = pos; 130 break; 131 case ATTR_ASSOC_STATE: 132 if (len != 2) { 133 wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " 134 "length %u", len); 135 return -1; 136 } 137 attr->assoc_state = pos; 138 break; 139 case ATTR_CONFIG_ERROR: 140 if (len != 2) { 141 wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " 142 "Error length %u", len); 143 return -1; 144 } 145 attr->config_error = pos; 146 break; 147 case ATTR_DEV_PASSWORD_ID: 148 if (len != 2) { 149 wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " 150 "ID length %u", len); 151 return -1; 152 } 153 attr->dev_password_id = pos; 154 break; 155 case ATTR_OOB_DEVICE_PASSWORD: 156 if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) { 157 wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device " 158 "Password length %u", len); 159 return -1; 160 } 161 attr->oob_dev_password = pos; 162 break; 163 case ATTR_OS_VERSION: 164 if (len != 4) { 165 wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " 166 "%u", len); 167 return -1; 168 } 169 attr->os_version = pos; 170 break; 171 case ATTR_WPS_STATE: 172 if (len != 1) { 173 wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " 174 "Setup State length %u", len); 175 return -1; 176 } 177 attr->wps_state = pos; 178 break; 179 case ATTR_AUTHENTICATOR: 180 if (len != WPS_AUTHENTICATOR_LEN) { 181 wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " 182 "length %u", len); 183 return -1; 184 } 185 attr->authenticator = pos; 186 break; 187 case ATTR_R_HASH1: 188 if (len != WPS_HASH_LEN) { 189 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", 190 len); 191 return -1; 192 } 193 attr->r_hash1 = pos; 194 break; 195 case ATTR_R_HASH2: 196 if (len != WPS_HASH_LEN) { 197 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", 198 len); 199 return -1; 200 } 201 attr->r_hash2 = pos; 202 break; 203 case ATTR_E_HASH1: 204 if (len != WPS_HASH_LEN) { 205 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", 206 len); 207 return -1; 208 } 209 attr->e_hash1 = pos; 210 break; 211 case ATTR_E_HASH2: 212 if (len != WPS_HASH_LEN) { 213 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", 214 len); 215 return -1; 216 } 217 attr->e_hash2 = pos; 218 break; 219 case ATTR_R_SNONCE1: 220 if (len != WPS_SECRET_NONCE_LEN) { 221 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " 222 "%u", len); 223 return -1; 224 } 225 attr->r_snonce1 = pos; 226 break; 227 case ATTR_R_SNONCE2: 228 if (len != WPS_SECRET_NONCE_LEN) { 229 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " 230 "%u", len); 231 return -1; 232 } 233 attr->r_snonce2 = pos; 234 break; 235 case ATTR_E_SNONCE1: 236 if (len != WPS_SECRET_NONCE_LEN) { 237 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " 238 "%u", len); 239 return -1; 240 } 241 attr->e_snonce1 = pos; 242 break; 243 case ATTR_E_SNONCE2: 244 if (len != WPS_SECRET_NONCE_LEN) { 245 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " 246 "%u", len); 247 return -1; 248 } 249 attr->e_snonce2 = pos; 250 break; 251 case ATTR_KEY_WRAP_AUTH: 252 if (len != WPS_KWA_LEN) { 253 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " 254 "Authenticator length %u", len); 255 return -1; 256 } 257 attr->key_wrap_auth = pos; 258 break; 259 case ATTR_AUTH_TYPE: 260 if (len != 2) { 261 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 262 "Type length %u", len); 263 return -1; 264 } 265 attr->auth_type = pos; 266 break; 267 case ATTR_ENCR_TYPE: 268 if (len != 2) { 269 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " 270 "Type length %u", len); 271 return -1; 272 } 273 attr->encr_type = pos; 274 break; 275 case ATTR_NETWORK_INDEX: 276 if (len != 1) { 277 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " 278 "length %u", len); 279 return -1; 280 } 281 attr->network_idx = pos; 282 break; 283 case ATTR_NETWORK_KEY_INDEX: 284 if (len != 1) { 285 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " 286 "length %u", len); 287 return -1; 288 } 289 attr->network_key_idx = pos; 290 break; 291 case ATTR_MAC_ADDR: 292 if (len != ETH_ALEN) { 293 wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " 294 "length %u", len); 295 return -1; 296 } 297 attr->mac_addr = pos; 298 break; 299 case ATTR_KEY_PROVIDED_AUTO: 300 if (len != 1) { 301 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided " 302 "Automatically length %u", len); 303 return -1; 304 } 305 attr->key_prov_auto = pos; 306 break; 307 case ATTR_802_1X_ENABLED: 308 if (len != 1) { 309 wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled " 310 "length %u", len); 311 return -1; 312 } 313 attr->dot1x_enabled = pos; 314 break; 315 case ATTR_SELECTED_REGISTRAR: 316 if (len != 1) { 317 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" 318 " length %u", len); 319 return -1; 320 } 321 attr->selected_registrar = pos; 322 break; 323 case ATTR_REQUEST_TYPE: 324 if (len != 1) { 325 wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " 326 "length %u", len); 327 return -1; 328 } 329 attr->request_type = pos; 330 break; 331 case ATTR_RESPONSE_TYPE: 332 if (len != 1) { 333 wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " 334 "length %u", len); 335 return -1; 336 } 337 attr->response_type = pos; 338 break; 339 case ATTR_MANUFACTURER: 340 attr->manufacturer = pos; 341 attr->manufacturer_len = len; 342 break; 343 case ATTR_MODEL_NAME: 344 attr->model_name = pos; 345 attr->model_name_len = len; 346 break; 347 case ATTR_MODEL_NUMBER: 348 attr->model_number = pos; 349 attr->model_number_len = len; 350 break; 351 case ATTR_SERIAL_NUMBER: 352 attr->serial_number = pos; 353 attr->serial_number_len = len; 354 break; 355 case ATTR_DEV_NAME: 356 attr->dev_name = pos; 357 attr->dev_name_len = len; 358 break; 359 case ATTR_PUBLIC_KEY: 360 attr->public_key = pos; 361 attr->public_key_len = len; 362 break; 363 case ATTR_ENCR_SETTINGS: 364 attr->encr_settings = pos; 365 attr->encr_settings_len = len; 366 break; 367 case ATTR_CRED: 368 if (attr->num_cred >= MAX_CRED_COUNT) { 369 wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " 370 "attribute (max %d credentials)", 371 MAX_CRED_COUNT); 372 break; 373 } 374 attr->cred[attr->num_cred] = pos; 375 attr->cred_len[attr->num_cred] = len; 376 attr->num_cred++; 377 break; 378 case ATTR_SSID: 379 attr->ssid = pos; 380 attr->ssid_len = len; 381 break; 382 case ATTR_NETWORK_KEY: 383 attr->network_key = pos; 384 attr->network_key_len = len; 385 break; 386 case ATTR_EAP_TYPE: 387 attr->eap_type = pos; 388 attr->eap_type_len = len; 389 break; 390 case ATTR_EAP_IDENTITY: 391 attr->eap_identity = pos; 392 attr->eap_identity_len = len; 393 break; 394 case ATTR_AP_SETUP_LOCKED: 395 if (len != 1) { 396 wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked " 397 "length %u", len); 398 return -1; 399 } 400 attr->ap_setup_locked = pos; 401 break; 402 default: 403 wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " 404 "len=%u", type, len); 405 break; 406 } 407 408 return 0; 409 } 410 411 412 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) 413 { 414 const u8 *pos, *end; 415 u16 type, len; 416 417 os_memset(attr, 0, sizeof(*attr)); 418 pos = wpabuf_head(msg); 419 end = pos + wpabuf_len(msg); 420 421 while (pos < end) { 422 if (end - pos < 4) { 423 wpa_printf(MSG_DEBUG, "WPS: Invalid message - " 424 "%lu bytes remaining", 425 (unsigned long) (end - pos)); 426 return -1; 427 } 428 429 type = WPA_GET_BE16(pos); 430 pos += 2; 431 len = WPA_GET_BE16(pos); 432 pos += 2; 433 wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u", 434 type, len); 435 if (len > end - pos) { 436 wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); 437 return -1; 438 } 439 440 #ifdef WPS_WORKAROUNDS 441 if (type == 0 && len == 0) { 442 /* 443 * Mac OS X 10.6 seems to be adding 0x00 padding to the 444 * end of M1. Skip those to avoid interop issues. 445 */ 446 int i; 447 for (i = 0; i < end - pos; i++) { 448 if (pos[i]) 449 break; 450 } 451 if (i == end - pos) { 452 wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " 453 "unexpected message padding"); 454 break; 455 } 456 } 457 #endif /* WPS_WORKAROUNDS */ 458 459 if (wps_set_attr(attr, type, pos, len) < 0) 460 return -1; 461 462 pos += len; 463 } 464 465 return 0; 466 } 467