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