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