wps.c revision 87fd279308af3f806848c8f2ab65ef18c6ac4c30
1/* 2 * Wi-Fi Protected Setup 3 * Copyright (c) 2007-2009, 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 "crypto/dh_group5.h" 19#include "common/ieee802_11_defs.h" 20#include "wps_i.h" 21#include "wps_dev_attr.h" 22 23 24#ifdef CONFIG_WPS_TESTING 25int wps_version_number = 0x20; 26int wps_testing_dummy_cred = 0; 27#endif /* CONFIG_WPS_TESTING */ 28 29 30/** 31 * wps_init - Initialize WPS Registration protocol data 32 * @cfg: WPS configuration 33 * Returns: Pointer to allocated data or %NULL on failure 34 * 35 * This function is used to initialize WPS data for a registration protocol 36 * instance (i.e., each run of registration protocol as a Registrar of 37 * Enrollee. The caller is responsible for freeing this data after the 38 * registration run has been completed by calling wps_deinit(). 39 */ 40struct wps_data * wps_init(const struct wps_config *cfg) 41{ 42 struct wps_data *data = os_zalloc(sizeof(*data)); 43 if (data == NULL) 44 return NULL; 45 data->wps = cfg->wps; 46 data->registrar = cfg->registrar; 47 if (cfg->registrar) { 48 os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 49 } else { 50 os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 51 os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 52 } 53 if (cfg->pin) { 54 data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ? 55 cfg->dev_pw_id : data->wps->oob_dev_pw_id; 56 data->dev_password = os_malloc(cfg->pin_len); 57 if (data->dev_password == NULL) { 58 os_free(data); 59 return NULL; 60 } 61 os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); 62 data->dev_password_len = cfg->pin_len; 63 } 64 65 data->pbc = cfg->pbc; 66 if (cfg->pbc) { 67 /* Use special PIN '00000000' for PBC */ 68 data->dev_pw_id = DEV_PW_PUSHBUTTON; 69 os_free(data->dev_password); 70 data->dev_password = os_malloc(8); 71 if (data->dev_password == NULL) { 72 os_free(data); 73 return NULL; 74 } 75 os_memset(data->dev_password, '0', 8); 76 data->dev_password_len = 8; 77 } 78 79 data->state = data->registrar ? RECV_M1 : SEND_M1; 80 81 if (cfg->assoc_wps_ie) { 82 struct wps_parse_attr attr; 83 wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 84 cfg->assoc_wps_ie); 85 if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 86 wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 87 "from (Re)AssocReq"); 88 } else if (attr.request_type == NULL) { 89 wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 90 "in (Re)AssocReq WPS IE"); 91 } else { 92 wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 93 "in (Re)AssocReq WPS IE): %d", 94 *attr.request_type); 95 data->request_type = *attr.request_type; 96 } 97 } 98 99 if (cfg->new_ap_settings) { 100 data->new_ap_settings = 101 os_malloc(sizeof(*data->new_ap_settings)); 102 if (data->new_ap_settings == NULL) { 103 os_free(data); 104 return NULL; 105 } 106 os_memcpy(data->new_ap_settings, cfg->new_ap_settings, 107 sizeof(*data->new_ap_settings)); 108 } 109 110 if (cfg->peer_addr) 111 os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 112 if (cfg->p2p_dev_addr) 113 os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); 114 115 data->use_psk_key = cfg->use_psk_key; 116 data->pbc_in_m1 = cfg->pbc_in_m1; 117 118 return data; 119} 120 121 122/** 123 * wps_deinit - Deinitialize WPS Registration protocol data 124 * @data: WPS Registration protocol data from wps_init() 125 */ 126void wps_deinit(struct wps_data *data) 127{ 128 if (data->wps_pin_revealed) { 129 wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 130 "negotiation failed"); 131 if (data->registrar) 132 wps_registrar_invalidate_pin(data->wps->registrar, 133 data->uuid_e); 134 } else if (data->registrar) 135 wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 136 137 wpabuf_free(data->dh_privkey); 138 wpabuf_free(data->dh_pubkey_e); 139 wpabuf_free(data->dh_pubkey_r); 140 wpabuf_free(data->last_msg); 141 os_free(data->dev_password); 142 os_free(data->new_psk); 143 wps_device_data_free(&data->peer_dev); 144 os_free(data->new_ap_settings); 145 dh5_free(data->dh_ctx); 146 os_free(data); 147} 148 149 150/** 151 * wps_process_msg - Process a WPS message 152 * @wps: WPS Registration protocol data from wps_init() 153 * @op_code: Message OP Code 154 * @msg: Message data 155 * Returns: Processing result 156 * 157 * This function is used to process WPS messages with OP Codes WSC_ACK, 158 * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 159 * responsible for reassembling the messages before calling this function. 160 * Response to this message is built by calling wps_get_msg(). 161 */ 162enum wps_process_res wps_process_msg(struct wps_data *wps, 163 enum wsc_op_code op_code, 164 const struct wpabuf *msg) 165{ 166 if (wps->registrar) 167 return wps_registrar_process_msg(wps, op_code, msg); 168 else 169 return wps_enrollee_process_msg(wps, op_code, msg); 170} 171 172 173/** 174 * wps_get_msg - Build a WPS message 175 * @wps: WPS Registration protocol data from wps_init() 176 * @op_code: Buffer for returning message OP Code 177 * Returns: The generated WPS message or %NULL on failure 178 * 179 * This function is used to build a response to a message processed by calling 180 * wps_process_msg(). The caller is responsible for freeing the buffer. 181 */ 182struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 183{ 184 if (wps->registrar) 185 return wps_registrar_get_msg(wps, op_code); 186 else 187 return wps_enrollee_get_msg(wps, op_code); 188} 189 190 191/** 192 * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 193 * @msg: WPS IE contents from Beacon or Probe Response frame 194 * Returns: 1 if PBC Registrar is active, 0 if not 195 */ 196int wps_is_selected_pbc_registrar(const struct wpabuf *msg) 197{ 198 struct wps_parse_attr attr; 199 200 /* 201 * In theory, this could also verify that attr.sel_reg_config_methods 202 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 203 * do not set Selected Registrar Config Methods attribute properly, so 204 * it is safer to just use Device Password ID here. 205 */ 206 207 if (wps_parse_msg(msg, &attr) < 0 || 208 !attr.selected_registrar || *attr.selected_registrar == 0 || 209 !attr.dev_password_id || 210 WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 211 return 0; 212 213#ifdef CONFIG_WPS_STRICT 214 if (!attr.sel_reg_config_methods || 215 !(WPA_GET_BE16(attr.sel_reg_config_methods) & 216 WPS_CONFIG_PUSHBUTTON)) 217 return 0; 218#endif /* CONFIG_WPS_STRICT */ 219 220 return 1; 221} 222 223 224static int is_selected_pin_registrar(struct wps_parse_attr *attr) 225{ 226 /* 227 * In theory, this could also verify that attr.sel_reg_config_methods 228 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 229 * but some deployed AP implementations do not set Selected Registrar 230 * Config Methods attribute properly, so it is safer to just use 231 * Device Password ID here. 232 */ 233 234 if (!attr->selected_registrar || *attr->selected_registrar == 0) 235 return 0; 236 237 if (attr->dev_password_id != NULL && 238 WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) 239 return 0; 240 241#ifdef CONFIG_WPS_STRICT 242 if (!attr->sel_reg_config_methods || 243 !(WPA_GET_BE16(attr->sel_reg_config_methods) & 244 (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) 245 return 0; 246#endif /* CONFIG_WPS_STRICT */ 247 248 return 1; 249} 250 251 252/** 253 * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 254 * @msg: WPS IE contents from Beacon or Probe Response frame 255 * Returns: 1 if PIN Registrar is active, 0 if not 256 */ 257int wps_is_selected_pin_registrar(const struct wpabuf *msg) 258{ 259 struct wps_parse_attr attr; 260 261 if (wps_parse_msg(msg, &attr) < 0) 262 return 0; 263 264 return is_selected_pin_registrar(&attr); 265} 266 267 268/** 269 * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address 270 * @msg: WPS IE contents from Beacon or Probe Response frame 271 * @addr: MAC address to search for 272 * @ver1_compat: Whether to use version 1 compatibility mode 273 * Returns: 1 if address is authorized, 0 if not 274 */ 275int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, 276 int ver1_compat) 277{ 278 struct wps_parse_attr attr; 279 unsigned int i; 280 const u8 *pos; 281 const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 282 283 if (wps_parse_msg(msg, &attr) < 0) 284 return 0; 285 286 if (!attr.version2 && ver1_compat) { 287 /* 288 * Version 1.0 AP - AuthorizedMACs not used, so revert back to 289 * old mechanism of using SelectedRegistrar. 290 */ 291 return is_selected_pin_registrar(&attr); 292 } 293 294 if (!attr.authorized_macs) 295 return 0; 296 297 pos = attr.authorized_macs; 298 for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { 299 if (os_memcmp(pos, addr, ETH_ALEN) == 0 || 300 os_memcmp(pos, bcast, ETH_ALEN) == 0) 301 return 1; 302 pos += ETH_ALEN; 303 } 304 305 return 0; 306} 307 308 309/** 310 * wps_ap_priority_compar - Prioritize WPS IE from two APs 311 * @wps_a: WPS IE contents from Beacon or Probe Response frame 312 * @wps_b: WPS IE contents from Beacon or Probe Response frame 313 * Returns: 1 if wps_b is considered more likely selection for WPS 314 * provisioning, -1 if wps_a is considered more like, or 0 if no preference 315 */ 316int wps_ap_priority_compar(const struct wpabuf *wps_a, 317 const struct wpabuf *wps_b) 318{ 319 struct wps_parse_attr attr_a, attr_b; 320 int sel_a, sel_b; 321 322 if (wps_a == NULL || wps_parse_msg(wps_a, &attr_a) < 0) 323 return 1; 324 if (wps_b == NULL || wps_parse_msg(wps_b, &attr_b) < 0) 325 return -1; 326 327 sel_a = attr_a.selected_registrar && *attr_a.selected_registrar != 0; 328 sel_b = attr_b.selected_registrar && *attr_b.selected_registrar != 0; 329 330 if (sel_a && !sel_b) 331 return -1; 332 if (!sel_a && sel_b) 333 return 1; 334 335 return 0; 336} 337 338 339/** 340 * wps_get_uuid_e - Get UUID-E from WPS IE 341 * @msg: WPS IE contents from Beacon or Probe Response frame 342 * Returns: Pointer to UUID-E or %NULL if not included 343 * 344 * The returned pointer is to the msg contents and it remains valid only as 345 * long as the msg buffer is valid. 346 */ 347const u8 * wps_get_uuid_e(const struct wpabuf *msg) 348{ 349 struct wps_parse_attr attr; 350 351 if (wps_parse_msg(msg, &attr) < 0) 352 return NULL; 353 return attr.uuid_e; 354} 355 356 357/** 358 * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 359 * @req_type: Value for Request Type attribute 360 * Returns: WPS IE or %NULL on failure 361 * 362 * The caller is responsible for freeing the buffer. 363 */ 364struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 365{ 366 struct wpabuf *ie; 367 u8 *len; 368 369 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 370 "Request"); 371 ie = wpabuf_alloc(100); 372 if (ie == NULL) 373 return NULL; 374 375 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 376 len = wpabuf_put(ie, 1); 377 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 378 379 if (wps_build_version(ie) || 380 wps_build_req_type(ie, req_type) || 381 wps_build_wfa_ext(ie, 0, NULL, 0)) { 382 wpabuf_free(ie); 383 return NULL; 384 } 385 386 *len = wpabuf_len(ie) - 2; 387 388 return ie; 389} 390 391 392/** 393 * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response 394 * Returns: WPS IE or %NULL on failure 395 * 396 * The caller is responsible for freeing the buffer. 397 */ 398struct wpabuf * wps_build_assoc_resp_ie(void) 399{ 400 struct wpabuf *ie; 401 u8 *len; 402 403 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 404 "Response"); 405 ie = wpabuf_alloc(100); 406 if (ie == NULL) 407 return NULL; 408 409 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 410 len = wpabuf_put(ie, 1); 411 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 412 413 if (wps_build_version(ie) || 414 wps_build_resp_type(ie, WPS_RESP_AP) || 415 wps_build_wfa_ext(ie, 0, NULL, 0)) { 416 wpabuf_free(ie); 417 return NULL; 418 } 419 420 *len = wpabuf_len(ie) - 2; 421 422 return ie; 423} 424 425 426/** 427 * wps_build_probe_req_ie - Build WPS IE for Probe Request 428 * @pbc: Whether searching for PBC mode APs 429 * @dev: Device attributes 430 * @uuid: Own UUID 431 * @req_type: Value for Request Type attribute 432 * @num_req_dev_types: Number of requested device types 433 * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or 434 * %NULL if none 435 * Returns: WPS IE or %NULL on failure 436 * 437 * The caller is responsible for freeing the buffer. 438 */ 439struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 440 const u8 *uuid, 441 enum wps_request_type req_type, 442 unsigned int num_req_dev_types, 443 const u8 *req_dev_types) 444{ 445 struct wpabuf *ie; 446 u16 methods = 0; 447 448 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 449 450 ie = wpabuf_alloc(500); 451 if (ie == NULL) 452 return NULL; 453 454 methods |= WPS_CONFIG_PUSHBUTTON; 455#ifdef CONFIG_WPS2 456 /* 457 * TODO: Should figure out whether this device has a physical or 458 * virtual pushbutton. 459 */ 460 methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 461#endif /* CONFIG_WPS2 */ 462 463 /* 464 * TODO: Should figure out whether this Probe Request was triggered 465 * using physical or virtual display. Also, if the device has a PIN on 466 * a label, that should be indicated here. 467 */ 468 methods |= WPS_CONFIG_DISPLAY | 469#ifdef CONFIG_WPS2 470 WPS_CONFIG_VIRT_DISPLAY | 471#endif /* CONFIG_WPS2 */ 472 WPS_CONFIG_KEYPAD; 473#ifdef CONFIG_WPS_UFD 474 methods |= WPS_CONFIG_USBA; 475#endif /* CONFIG_WPS_UFD */ 476#ifdef CONFIG_WPS_NFC 477 methods |= WPS_CONFIG_NFC_INTERFACE; 478#endif /* CONFIG_WPS_NFC */ 479 480 if (wps_build_version(ie) || 481 wps_build_req_type(ie, req_type) || 482 wps_build_config_methods(ie, methods) || 483 wps_build_uuid_e(ie, uuid) || 484 wps_build_primary_dev_type(dev, ie) || 485 wps_build_rf_bands(dev, ie) || 486 wps_build_assoc_state(NULL, ie) || 487 wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 488 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 489 DEV_PW_DEFAULT) || 490#ifdef CONFIG_WPS2 491 wps_build_manufacturer(dev, ie) || 492 wps_build_model_name(dev, ie) || 493 wps_build_model_number(dev, ie) || 494 wps_build_dev_name(dev, ie) || 495 wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || 496#endif /* CONFIG_WPS2 */ 497 wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) 498 || 499 wps_build_secondary_dev_type(dev, ie) 500 ) { 501 wpabuf_free(ie); 502 return NULL; 503 } 504 505#ifndef CONFIG_WPS2 506 if (dev->p2p && wps_build_dev_name(dev, ie)) { 507 wpabuf_free(ie); 508 return NULL; 509 } 510#endif /* CONFIG_WPS2 */ 511 512 return wps_ie_encapsulate(ie); 513} 514 515 516void wps_free_pending_msgs(struct upnp_pending_message *msgs) 517{ 518 struct upnp_pending_message *p, *prev; 519 p = msgs; 520 while (p) { 521 prev = p; 522 p = p->next; 523 wpabuf_free(prev->msg); 524 os_free(prev); 525 } 526} 527 528 529int wps_attr_text(struct wpabuf *data, char *buf, char *end) 530{ 531 struct wps_parse_attr attr; 532 char *pos = buf; 533 int ret; 534 535 if (wps_parse_msg(data, &attr) < 0) 536 return -1; 537 538 if (attr.wps_state) { 539 if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 540 ret = os_snprintf(pos, end - pos, 541 "wps_state=unconfigured\n"); 542 else if (*attr.wps_state == WPS_STATE_CONFIGURED) 543 ret = os_snprintf(pos, end - pos, 544 "wps_state=configured\n"); 545 else 546 ret = 0; 547 if (ret < 0 || ret >= end - pos) 548 return pos - buf; 549 pos += ret; 550 } 551 552 if (attr.ap_setup_locked && *attr.ap_setup_locked) { 553 ret = os_snprintf(pos, end - pos, 554 "wps_ap_setup_locked=1\n"); 555 if (ret < 0 || ret >= end - pos) 556 return pos - buf; 557 pos += ret; 558 } 559 560 if (attr.selected_registrar && *attr.selected_registrar) { 561 ret = os_snprintf(pos, end - pos, 562 "wps_selected_registrar=1\n"); 563 if (ret < 0 || ret >= end - pos) 564 return pos - buf; 565 pos += ret; 566 } 567 568 if (attr.dev_password_id) { 569 ret = os_snprintf(pos, end - pos, 570 "wps_device_password_id=%u\n", 571 WPA_GET_BE16(attr.dev_password_id)); 572 if (ret < 0 || ret >= end - pos) 573 return pos - buf; 574 pos += ret; 575 } 576 577 if (attr.sel_reg_config_methods) { 578 ret = os_snprintf(pos, end - pos, 579 "wps_selected_registrar_config_methods=" 580 "0x%04x\n", 581 WPA_GET_BE16(attr.sel_reg_config_methods)); 582 if (ret < 0 || ret >= end - pos) 583 return pos - buf; 584 pos += ret; 585 } 586 587 if (attr.primary_dev_type) { 588 char devtype[WPS_DEV_TYPE_BUFSIZE]; 589 ret = os_snprintf(pos, end - pos, 590 "wps_primary_device_type=%s\n", 591 wps_dev_type_bin2str(attr.primary_dev_type, 592 devtype, 593 sizeof(devtype))); 594 if (ret < 0 || ret >= end - pos) 595 return pos - buf; 596 pos += ret; 597 } 598 599 if (attr.dev_name) { 600 char *str = os_malloc(attr.dev_name_len + 1); 601 size_t i; 602 if (str == NULL) 603 return pos - buf; 604 for (i = 0; i < attr.dev_name_len; i++) { 605 if (attr.dev_name[i] < 32) 606 str[i] = '_'; 607 else 608 str[i] = attr.dev_name[i]; 609 } 610 str[i] = '\0'; 611 ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 612 os_free(str); 613 if (ret < 0 || ret >= end - pos) 614 return pos - buf; 615 pos += ret; 616 } 617 618 if (attr.config_methods) { 619 ret = os_snprintf(pos, end - pos, 620 "wps_config_methods=0x%04x\n", 621 WPA_GET_BE16(attr.config_methods)); 622 if (ret < 0 || ret >= end - pos) 623 return pos - buf; 624 pos += ret; 625 } 626 627 return pos - buf; 628} 629