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