1/* 2 * Wi-Fi Protected Setup - attribute parsing 3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "wps_defs.h" 13#include "wps_attr_parse.h" 14 15#ifndef CONFIG_WPS_STRICT 16#define WPS_WORKAROUNDS 17#endif /* CONFIG_WPS_STRICT */ 18 19 20static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr, 21 u8 id, u8 len, const u8 *pos) 22{ 23 wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u", 24 id, len); 25 switch (id) { 26 case WFA_ELEM_VERSION2: 27 if (len != 1) { 28 wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length " 29 "%u", len); 30 return -1; 31 } 32 attr->version2 = pos; 33 break; 34 case WFA_ELEM_AUTHORIZEDMACS: 35 attr->authorized_macs = pos; 36 attr->authorized_macs_len = len; 37 break; 38 case WFA_ELEM_NETWORK_KEY_SHAREABLE: 39 if (len != 1) { 40 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key " 41 "Shareable length %u", len); 42 return -1; 43 } 44 attr->network_key_shareable = pos; 45 break; 46 case WFA_ELEM_REQUEST_TO_ENROLL: 47 if (len != 1) { 48 wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll " 49 "length %u", len); 50 return -1; 51 } 52 attr->request_to_enroll = pos; 53 break; 54 case WFA_ELEM_SETTINGS_DELAY_TIME: 55 if (len != 1) { 56 wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay " 57 "Time length %u", len); 58 return -1; 59 } 60 attr->settings_delay_time = pos; 61 break; 62 default: 63 wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor " 64 "Extension subelement %u", id); 65 break; 66 } 67 68 return 0; 69} 70 71 72static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos, 73 u16 len) 74{ 75 const u8 *end = pos + len; 76 u8 id, elen; 77 78 while (pos + 2 < end) { 79 id = *pos++; 80 elen = *pos++; 81 if (pos + elen > end) 82 break; 83 if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0) 84 return -1; 85 pos += elen; 86 } 87 88 return 0; 89} 90 91 92static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos, 93 u16 len) 94{ 95 u32 vendor_id; 96 97 if (len < 3) { 98 wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension"); 99 return 0; 100 } 101 102 vendor_id = WPA_GET_BE24(pos); 103 switch (vendor_id) { 104 case WPS_VENDOR_ID_WFA: 105 return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3); 106 } 107 108 /* Handle unknown vendor extensions */ 109 110 wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)", 111 vendor_id); 112 113 if (len > WPS_MAX_VENDOR_EXT_LEN) { 114 wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)", 115 len); 116 return -1; 117 } 118 119 if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) { 120 wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension " 121 "attribute (max %d vendor extensions)", 122 MAX_WPS_PARSE_VENDOR_EXT); 123 return -1; 124 } 125 attr->vendor_ext[attr->num_vendor_ext] = pos; 126 attr->vendor_ext_len[attr->num_vendor_ext] = len; 127 attr->num_vendor_ext++; 128 129 return 0; 130} 131 132 133static int wps_set_attr(struct wps_parse_attr *attr, u16 type, 134 const u8 *pos, u16 len) 135{ 136 switch (type) { 137 case ATTR_VERSION: 138 if (len != 1) { 139 wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u", 140 len); 141 return -1; 142 } 143 attr->version = pos; 144 break; 145 case ATTR_MSG_TYPE: 146 if (len != 1) { 147 wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " 148 "length %u", len); 149 return -1; 150 } 151 attr->msg_type = pos; 152 break; 153 case ATTR_ENROLLEE_NONCE: 154 if (len != WPS_NONCE_LEN) { 155 wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce " 156 "length %u", len); 157 return -1; 158 } 159 attr->enrollee_nonce = pos; 160 break; 161 case ATTR_REGISTRAR_NONCE: 162 if (len != WPS_NONCE_LEN) { 163 wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce " 164 "length %u", len); 165 return -1; 166 } 167 attr->registrar_nonce = pos; 168 break; 169 case ATTR_UUID_E: 170 if (len != WPS_UUID_LEN) { 171 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u", 172 len); 173 return -1; 174 } 175 attr->uuid_e = pos; 176 break; 177 case ATTR_UUID_R: 178 if (len != WPS_UUID_LEN) { 179 wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u", 180 len); 181 return -1; 182 } 183 attr->uuid_r = pos; 184 break; 185 case ATTR_AUTH_TYPE_FLAGS: 186 if (len != 2) { 187 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 188 "Type Flags length %u", len); 189 return -1; 190 } 191 attr->auth_type_flags = pos; 192 break; 193 case ATTR_ENCR_TYPE_FLAGS: 194 if (len != 2) { 195 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type " 196 "Flags length %u", len); 197 return -1; 198 } 199 attr->encr_type_flags = pos; 200 break; 201 case ATTR_CONN_TYPE_FLAGS: 202 if (len != 1) { 203 wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type " 204 "Flags length %u", len); 205 return -1; 206 } 207 attr->conn_type_flags = pos; 208 break; 209 case ATTR_CONFIG_METHODS: 210 if (len != 2) { 211 wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods " 212 "length %u", len); 213 return -1; 214 } 215 attr->config_methods = pos; 216 break; 217 case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS: 218 if (len != 2) { 219 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected " 220 "Registrar Config Methods length %u", len); 221 return -1; 222 } 223 attr->sel_reg_config_methods = pos; 224 break; 225 case ATTR_PRIMARY_DEV_TYPE: 226 if (len != WPS_DEV_TYPE_LEN) { 227 wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device " 228 "Type length %u", len); 229 return -1; 230 } 231 attr->primary_dev_type = pos; 232 break; 233 case ATTR_RF_BANDS: 234 if (len != 1) { 235 wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length " 236 "%u", len); 237 return -1; 238 } 239 attr->rf_bands = pos; 240 break; 241 case ATTR_ASSOC_STATE: 242 if (len != 2) { 243 wpa_printf(MSG_DEBUG, "WPS: Invalid Association State " 244 "length %u", len); 245 return -1; 246 } 247 attr->assoc_state = pos; 248 break; 249 case ATTR_CONFIG_ERROR: 250 if (len != 2) { 251 wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration " 252 "Error length %u", len); 253 return -1; 254 } 255 attr->config_error = pos; 256 break; 257 case ATTR_DEV_PASSWORD_ID: 258 if (len != 2) { 259 wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password " 260 "ID length %u", len); 261 return -1; 262 } 263 attr->dev_password_id = pos; 264 break; 265 case ATTR_OOB_DEVICE_PASSWORD: 266 if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 + 267 WPS_OOB_DEVICE_PASSWORD_MIN_LEN || 268 len > WPS_OOB_PUBKEY_HASH_LEN + 2 + 269 WPS_OOB_DEVICE_PASSWORD_LEN) { 270 wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device " 271 "Password length %u", len); 272 return -1; 273 } 274 attr->oob_dev_password = pos; 275 attr->oob_dev_password_len = len; 276 break; 277 case ATTR_OS_VERSION: 278 if (len != 4) { 279 wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length " 280 "%u", len); 281 return -1; 282 } 283 attr->os_version = pos; 284 break; 285 case ATTR_WPS_STATE: 286 if (len != 1) { 287 wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected " 288 "Setup State length %u", len); 289 return -1; 290 } 291 attr->wps_state = pos; 292 break; 293 case ATTR_AUTHENTICATOR: 294 if (len != WPS_AUTHENTICATOR_LEN) { 295 wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator " 296 "length %u", len); 297 return -1; 298 } 299 attr->authenticator = pos; 300 break; 301 case ATTR_R_HASH1: 302 if (len != WPS_HASH_LEN) { 303 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u", 304 len); 305 return -1; 306 } 307 attr->r_hash1 = pos; 308 break; 309 case ATTR_R_HASH2: 310 if (len != WPS_HASH_LEN) { 311 wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u", 312 len); 313 return -1; 314 } 315 attr->r_hash2 = pos; 316 break; 317 case ATTR_E_HASH1: 318 if (len != WPS_HASH_LEN) { 319 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u", 320 len); 321 return -1; 322 } 323 attr->e_hash1 = pos; 324 break; 325 case ATTR_E_HASH2: 326 if (len != WPS_HASH_LEN) { 327 wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u", 328 len); 329 return -1; 330 } 331 attr->e_hash2 = pos; 332 break; 333 case ATTR_R_SNONCE1: 334 if (len != WPS_SECRET_NONCE_LEN) { 335 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length " 336 "%u", len); 337 return -1; 338 } 339 attr->r_snonce1 = pos; 340 break; 341 case ATTR_R_SNONCE2: 342 if (len != WPS_SECRET_NONCE_LEN) { 343 wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length " 344 "%u", len); 345 return -1; 346 } 347 attr->r_snonce2 = pos; 348 break; 349 case ATTR_E_SNONCE1: 350 if (len != WPS_SECRET_NONCE_LEN) { 351 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length " 352 "%u", len); 353 return -1; 354 } 355 attr->e_snonce1 = pos; 356 break; 357 case ATTR_E_SNONCE2: 358 if (len != WPS_SECRET_NONCE_LEN) { 359 wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length " 360 "%u", len); 361 return -1; 362 } 363 attr->e_snonce2 = pos; 364 break; 365 case ATTR_KEY_WRAP_AUTH: 366 if (len != WPS_KWA_LEN) { 367 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap " 368 "Authenticator length %u", len); 369 return -1; 370 } 371 attr->key_wrap_auth = pos; 372 break; 373 case ATTR_AUTH_TYPE: 374 if (len != 2) { 375 wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication " 376 "Type length %u", len); 377 return -1; 378 } 379 attr->auth_type = pos; 380 break; 381 case ATTR_ENCR_TYPE: 382 if (len != 2) { 383 wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption " 384 "Type length %u", len); 385 return -1; 386 } 387 attr->encr_type = pos; 388 break; 389 case ATTR_NETWORK_INDEX: 390 if (len != 1) { 391 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index " 392 "length %u", len); 393 return -1; 394 } 395 attr->network_idx = pos; 396 break; 397 case ATTR_NETWORK_KEY_INDEX: 398 if (len != 1) { 399 wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index " 400 "length %u", len); 401 return -1; 402 } 403 attr->network_key_idx = pos; 404 break; 405 case ATTR_MAC_ADDR: 406 if (len != ETH_ALEN) { 407 wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address " 408 "length %u", len); 409 return -1; 410 } 411 attr->mac_addr = pos; 412 break; 413 case ATTR_KEY_PROVIDED_AUTO: 414 if (len != 1) { 415 wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided " 416 "Automatically length %u", len); 417 return -1; 418 } 419 attr->key_prov_auto = pos; 420 break; 421 case ATTR_802_1X_ENABLED: 422 if (len != 1) { 423 wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled " 424 "length %u", len); 425 return -1; 426 } 427 attr->dot1x_enabled = pos; 428 break; 429 case ATTR_SELECTED_REGISTRAR: 430 if (len != 1) { 431 wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar" 432 " length %u", len); 433 return -1; 434 } 435 attr->selected_registrar = pos; 436 break; 437 case ATTR_REQUEST_TYPE: 438 if (len != 1) { 439 wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type " 440 "length %u", len); 441 return -1; 442 } 443 attr->request_type = pos; 444 break; 445 case ATTR_RESPONSE_TYPE: 446 if (len != 1) { 447 wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type " 448 "length %u", len); 449 return -1; 450 } 451 attr->response_type = pos; 452 break; 453 case ATTR_MANUFACTURER: 454 attr->manufacturer = pos; 455 attr->manufacturer_len = len; 456 break; 457 case ATTR_MODEL_NAME: 458 attr->model_name = pos; 459 attr->model_name_len = len; 460 break; 461 case ATTR_MODEL_NUMBER: 462 attr->model_number = pos; 463 attr->model_number_len = len; 464 break; 465 case ATTR_SERIAL_NUMBER: 466 attr->serial_number = pos; 467 attr->serial_number_len = len; 468 break; 469 case ATTR_DEV_NAME: 470 attr->dev_name = pos; 471 attr->dev_name_len = len; 472 break; 473 case ATTR_PUBLIC_KEY: 474 attr->public_key = pos; 475 attr->public_key_len = len; 476 break; 477 case ATTR_ENCR_SETTINGS: 478 attr->encr_settings = pos; 479 attr->encr_settings_len = len; 480 break; 481 case ATTR_CRED: 482 if (attr->num_cred >= MAX_CRED_COUNT) { 483 wpa_printf(MSG_DEBUG, "WPS: Skipped Credential " 484 "attribute (max %d credentials)", 485 MAX_CRED_COUNT); 486 break; 487 } 488 attr->cred[attr->num_cred] = pos; 489 attr->cred_len[attr->num_cred] = len; 490 attr->num_cred++; 491 break; 492 case ATTR_SSID: 493 attr->ssid = pos; 494 attr->ssid_len = len; 495 break; 496 case ATTR_NETWORK_KEY: 497 attr->network_key = pos; 498 attr->network_key_len = len; 499 break; 500 case ATTR_EAP_TYPE: 501 attr->eap_type = pos; 502 attr->eap_type_len = len; 503 break; 504 case ATTR_EAP_IDENTITY: 505 attr->eap_identity = pos; 506 attr->eap_identity_len = len; 507 break; 508 case ATTR_AP_SETUP_LOCKED: 509 if (len != 1) { 510 wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked " 511 "length %u", len); 512 return -1; 513 } 514 attr->ap_setup_locked = pos; 515 break; 516 case ATTR_REQUESTED_DEV_TYPE: 517 if (len != WPS_DEV_TYPE_LEN) { 518 wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device " 519 "Type length %u", len); 520 return -1; 521 } 522 if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) { 523 wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device " 524 "Type attribute (max %u types)", 525 MAX_REQ_DEV_TYPE_COUNT); 526 break; 527 } 528 attr->req_dev_type[attr->num_req_dev_type] = pos; 529 attr->num_req_dev_type++; 530 break; 531 case ATTR_SECONDARY_DEV_TYPE_LIST: 532 if (len > WPS_SEC_DEV_TYPE_MAX_LEN || 533 (len % WPS_DEV_TYPE_LEN) > 0) { 534 wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device " 535 "Type length %u", len); 536 return -1; 537 } 538 attr->sec_dev_type_list = pos; 539 attr->sec_dev_type_list_len = len; 540 break; 541 case ATTR_VENDOR_EXT: 542 if (wps_parse_vendor_ext(attr, pos, len) < 0) 543 return -1; 544 break; 545 case ATTR_AP_CHANNEL: 546 if (len != 2) { 547 wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel " 548 "length %u", len); 549 return -1; 550 } 551 attr->ap_channel = pos; 552 break; 553 default: 554 wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " 555 "len=%u", type, len); 556 break; 557 } 558 559 return 0; 560} 561 562 563int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) 564{ 565 const u8 *pos, *end; 566 u16 type, len; 567#ifdef WPS_WORKAROUNDS 568 u16 prev_type = 0; 569#endif /* WPS_WORKAROUNDS */ 570 571 os_memset(attr, 0, sizeof(*attr)); 572 pos = wpabuf_head(msg); 573 end = pos + wpabuf_len(msg); 574 575 while (pos < end) { 576 if (end - pos < 4) { 577 wpa_printf(MSG_DEBUG, "WPS: Invalid message - " 578 "%lu bytes remaining", 579 (unsigned long) (end - pos)); 580 return -1; 581 } 582 583 type = WPA_GET_BE16(pos); 584 pos += 2; 585 len = WPA_GET_BE16(pos); 586 pos += 2; 587 wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u", 588 type, len); 589 if (len > end - pos) { 590 wpa_printf(MSG_DEBUG, "WPS: Attribute overflow"); 591 wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg); 592#ifdef WPS_WORKAROUNDS 593 /* 594 * Some deployed APs seem to have a bug in encoding of 595 * Network Key attribute in the Credential attribute 596 * where they add an extra octet after the Network Key 597 * attribute at least when open network is being 598 * provisioned. 599 */ 600 if ((type & 0xff00) != 0x1000 && 601 prev_type == ATTR_NETWORK_KEY) { 602 wpa_printf(MSG_DEBUG, "WPS: Workaround - try " 603 "to skip unexpected octet after " 604 "Network Key"); 605 pos -= 3; 606 continue; 607 } 608#endif /* WPS_WORKAROUNDS */ 609 return -1; 610 } 611 612#ifdef WPS_WORKAROUNDS 613 if (type == 0 && len == 0) { 614 /* 615 * Mac OS X 10.6 seems to be adding 0x00 padding to the 616 * end of M1. Skip those to avoid interop issues. 617 */ 618 int i; 619 for (i = 0; i < end - pos; i++) { 620 if (pos[i]) 621 break; 622 } 623 if (i == end - pos) { 624 wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " 625 "unexpected message padding"); 626 break; 627 } 628 } 629#endif /* WPS_WORKAROUNDS */ 630 631 if (wps_set_attr(attr, type, pos, len) < 0) 632 return -1; 633 634#ifdef WPS_WORKAROUNDS 635 prev_type = type; 636#endif /* WPS_WORKAROUNDS */ 637 pos += len; 638 } 639 640 return 0; 641} 642