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