wps.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
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 = (u8 *) os_strdup("00000000"); 71 if (data->dev_password == NULL) { 72 os_free(data); 73 return NULL; 74 } 75 data->dev_password_len = 8; 76 } 77 78 data->state = data->registrar ? RECV_M1 : SEND_M1; 79 80 if (cfg->assoc_wps_ie) { 81 struct wps_parse_attr attr; 82 wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 83 cfg->assoc_wps_ie); 84 if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 85 wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 86 "from (Re)AssocReq"); 87 } else if (attr.request_type == NULL) { 88 wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 89 "in (Re)AssocReq WPS IE"); 90 } else { 91 wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 92 "in (Re)AssocReq WPS IE): %d", 93 *attr.request_type); 94 data->request_type = *attr.request_type; 95 } 96 } 97 98 if (cfg->new_ap_settings) { 99 data->new_ap_settings = 100 os_malloc(sizeof(*data->new_ap_settings)); 101 if (data->new_ap_settings == NULL) { 102 os_free(data); 103 return NULL; 104 } 105 os_memcpy(data->new_ap_settings, cfg->new_ap_settings, 106 sizeof(*data->new_ap_settings)); 107 } 108 109 if (cfg->peer_addr) 110 os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 111 if (cfg->p2p_dev_addr) 112 os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); 113 114 data->use_psk_key = cfg->use_psk_key; 115 data->pbc_in_m1 = cfg->pbc_in_m1; 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_is_20 - Check whether WPS attributes claim support for WPS 2.0 358 */ 359int wps_is_20(const struct wpabuf *msg) 360{ 361 struct wps_parse_attr attr; 362 363 if (msg == NULL || wps_parse_msg(msg, &attr) < 0) 364 return 0; 365 return attr.version2 != NULL; 366} 367 368 369/** 370 * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 371 * @req_type: Value for Request Type attribute 372 * Returns: WPS IE or %NULL on failure 373 * 374 * The caller is responsible for freeing the buffer. 375 */ 376struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 377{ 378 struct wpabuf *ie; 379 u8 *len; 380 381 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 382 "Request"); 383 ie = wpabuf_alloc(100); 384 if (ie == NULL) 385 return NULL; 386 387 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 388 len = wpabuf_put(ie, 1); 389 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 390 391 if (wps_build_version(ie) || 392 wps_build_req_type(ie, req_type) || 393 wps_build_wfa_ext(ie, 0, NULL, 0)) { 394 wpabuf_free(ie); 395 return NULL; 396 } 397 398 *len = wpabuf_len(ie) - 2; 399 400 return ie; 401} 402 403 404/** 405 * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response 406 * Returns: WPS IE or %NULL on failure 407 * 408 * The caller is responsible for freeing the buffer. 409 */ 410struct wpabuf * wps_build_assoc_resp_ie(void) 411{ 412 struct wpabuf *ie; 413 u8 *len; 414 415 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 416 "Response"); 417 ie = wpabuf_alloc(100); 418 if (ie == NULL) 419 return NULL; 420 421 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 422 len = wpabuf_put(ie, 1); 423 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 424 425 if (wps_build_version(ie) || 426 wps_build_resp_type(ie, WPS_RESP_AP) || 427 wps_build_wfa_ext(ie, 0, NULL, 0)) { 428 wpabuf_free(ie); 429 return NULL; 430 } 431 432 *len = wpabuf_len(ie) - 2; 433 434 return ie; 435} 436 437 438/** 439 * wps_build_probe_req_ie - Build WPS IE for Probe Request 440 * @pbc: Whether searching for PBC mode APs 441 * @dev: Device attributes 442 * @uuid: Own UUID 443 * @req_type: Value for Request Type attribute 444 * @num_req_dev_types: Number of requested device types 445 * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or 446 * %NULL if none 447 * Returns: WPS IE or %NULL on failure 448 * 449 * The caller is responsible for freeing the buffer. 450 */ 451struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 452 const u8 *uuid, 453 enum wps_request_type req_type, 454 unsigned int num_req_dev_types, 455 const u8 *req_dev_types) 456{ 457 struct wpabuf *ie; 458 459 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 460 461 ie = wpabuf_alloc(500); 462 if (ie == NULL) 463 return NULL; 464 465 if (wps_build_version(ie) || 466 wps_build_req_type(ie, req_type) || 467 wps_build_config_methods(ie, dev->config_methods) || 468 wps_build_uuid_e(ie, uuid) || 469 wps_build_primary_dev_type(dev, ie) || 470 wps_build_rf_bands(dev, ie) || 471 wps_build_assoc_state(NULL, ie) || 472 wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 473 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 474 DEV_PW_DEFAULT) || 475#ifdef CONFIG_WPS2 476 wps_build_manufacturer(dev, ie) || 477 wps_build_model_name(dev, ie) || 478 wps_build_model_number(dev, ie) || 479 wps_build_dev_name(dev, ie) || 480 wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || 481#endif /* CONFIG_WPS2 */ 482 wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) 483 || 484 wps_build_secondary_dev_type(dev, ie) 485 ) { 486 wpabuf_free(ie); 487 return NULL; 488 } 489 490#ifndef CONFIG_WPS2 491 if (dev->p2p && wps_build_dev_name(dev, ie)) { 492 wpabuf_free(ie); 493 return NULL; 494 } 495#endif /* CONFIG_WPS2 */ 496 497 return wps_ie_encapsulate(ie); 498} 499 500 501void wps_free_pending_msgs(struct upnp_pending_message *msgs) 502{ 503 struct upnp_pending_message *p, *prev; 504 p = msgs; 505 while (p) { 506 prev = p; 507 p = p->next; 508 wpabuf_free(prev->msg); 509 os_free(prev); 510 } 511} 512 513 514int wps_attr_text(struct wpabuf *data, char *buf, char *end) 515{ 516 struct wps_parse_attr attr; 517 char *pos = buf; 518 int ret; 519 520 if (wps_parse_msg(data, &attr) < 0) 521 return -1; 522 523 if (attr.wps_state) { 524 if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 525 ret = os_snprintf(pos, end - pos, 526 "wps_state=unconfigured\n"); 527 else if (*attr.wps_state == WPS_STATE_CONFIGURED) 528 ret = os_snprintf(pos, end - pos, 529 "wps_state=configured\n"); 530 else 531 ret = 0; 532 if (ret < 0 || ret >= end - pos) 533 return pos - buf; 534 pos += ret; 535 } 536 537 if (attr.ap_setup_locked && *attr.ap_setup_locked) { 538 ret = os_snprintf(pos, end - pos, 539 "wps_ap_setup_locked=1\n"); 540 if (ret < 0 || ret >= end - pos) 541 return pos - buf; 542 pos += ret; 543 } 544 545 if (attr.selected_registrar && *attr.selected_registrar) { 546 ret = os_snprintf(pos, end - pos, 547 "wps_selected_registrar=1\n"); 548 if (ret < 0 || ret >= end - pos) 549 return pos - buf; 550 pos += ret; 551 } 552 553 if (attr.dev_password_id) { 554 ret = os_snprintf(pos, end - pos, 555 "wps_device_password_id=%u\n", 556 WPA_GET_BE16(attr.dev_password_id)); 557 if (ret < 0 || ret >= end - pos) 558 return pos - buf; 559 pos += ret; 560 } 561 562 if (attr.sel_reg_config_methods) { 563 ret = os_snprintf(pos, end - pos, 564 "wps_selected_registrar_config_methods=" 565 "0x%04x\n", 566 WPA_GET_BE16(attr.sel_reg_config_methods)); 567 if (ret < 0 || ret >= end - pos) 568 return pos - buf; 569 pos += ret; 570 } 571 572 if (attr.primary_dev_type) { 573 char devtype[WPS_DEV_TYPE_BUFSIZE]; 574 ret = os_snprintf(pos, end - pos, 575 "wps_primary_device_type=%s\n", 576 wps_dev_type_bin2str(attr.primary_dev_type, 577 devtype, 578 sizeof(devtype))); 579 if (ret < 0 || ret >= end - pos) 580 return pos - buf; 581 pos += ret; 582 } 583 584 if (attr.dev_name) { 585 char *str = os_malloc(attr.dev_name_len + 1); 586 size_t i; 587 if (str == NULL) 588 return pos - buf; 589 for (i = 0; i < attr.dev_name_len; i++) { 590 if (attr.dev_name[i] < 32) 591 str[i] = '_'; 592 else 593 str[i] = attr.dev_name[i]; 594 } 595 str[i] = '\0'; 596 ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 597 os_free(str); 598 if (ret < 0 || ret >= end - pos) 599 return pos - buf; 600 pos += ret; 601 } 602 603 if (attr.config_methods) { 604 ret = os_snprintf(pos, end - pos, 605 "wps_config_methods=0x%04x\n", 606 WPA_GET_BE16(attr.config_methods)); 607 if (ret < 0 || ret >= end - pos) 608 return pos - buf; 609 pos += ret; 610 } 611 612 return pos - buf; 613} 614