1295011Sandrew/* 2295011Sandrew * Wi-Fi Protected Setup 3295011Sandrew * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> 4295011Sandrew * 5295011Sandrew * This program is free software; you can redistribute it and/or modify 6295011Sandrew * it under the terms of the GNU General Public License version 2 as 7295011Sandrew * published by the Free Software Foundation. 8295011Sandrew * 9295011Sandrew * Alternatively, this software may be distributed under the terms of BSD 10295011Sandrew * license. 11295011Sandrew * 12295011Sandrew * See README and COPYING for more details. 13295011Sandrew */ 14295011Sandrew 15295011Sandrew#include "includes.h" 16295011Sandrew 17295011Sandrew#include "common.h" 18295011Sandrew#include "crypto/dh_group5.h" 19295011Sandrew#include "common/ieee802_11_defs.h" 20295011Sandrew#include "wps_i.h" 21295011Sandrew#include "wps_dev_attr.h" 22295011Sandrew 23295011Sandrew 24295011Sandrew/** 25295011Sandrew * wps_init - Initialize WPS Registration protocol data 26295011Sandrew * @cfg: WPS configuration 27295011Sandrew * Returns: Pointer to allocated data or %NULL on failure 28295011Sandrew * 29295011Sandrew * This function is used to initialize WPS data for a registration protocol 30295011Sandrew * instance (i.e., each run of registration protocol as a Registrar of 31295011Sandrew * Enrollee. The caller is responsible for freeing this data after the 32295011Sandrew * registration run has been completed by calling wps_deinit(). 33295011Sandrew */ 34295011Sandrewstruct wps_data * wps_init(const struct wps_config *cfg) 35295011Sandrew{ 36295011Sandrew struct wps_data *data = os_zalloc(sizeof(*data)); 37295011Sandrew if (data == NULL) 38295011Sandrew return NULL; 39295011Sandrew data->wps = cfg->wps; 40295011Sandrew data->registrar = cfg->registrar; 41295011Sandrew if (cfg->registrar) { 42295011Sandrew os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 43295011Sandrew } else { 44295011Sandrew os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 45295011Sandrew os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 46295011Sandrew } 47295011Sandrew if (cfg->pin) { 48295011Sandrew data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ? 49295011Sandrew DEV_PW_DEFAULT : data->wps->oob_dev_pw_id; 50295011Sandrew data->dev_password = os_malloc(cfg->pin_len); 51295011Sandrew if (data->dev_password == NULL) { 52295011Sandrew os_free(data); 53295011Sandrew return NULL; 54295011Sandrew } 55295011Sandrew os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); 56295011Sandrew data->dev_password_len = cfg->pin_len; 57295011Sandrew } 58295011Sandrew 59295011Sandrew data->pbc = cfg->pbc; 60295011Sandrew if (cfg->pbc) { 61295011Sandrew /* Use special PIN '00000000' for PBC */ 62295011Sandrew data->dev_pw_id = DEV_PW_PUSHBUTTON; 63295011Sandrew os_free(data->dev_password); 64295011Sandrew data->dev_password = os_malloc(8); 65295011Sandrew if (data->dev_password == NULL) { 66295011Sandrew os_free(data); 67295011Sandrew return NULL; 68295011Sandrew } 69295011Sandrew os_memset(data->dev_password, '0', 8); 70295011Sandrew data->dev_password_len = 8; 71295011Sandrew } 72295011Sandrew 73295011Sandrew data->state = data->registrar ? RECV_M1 : SEND_M1; 74295011Sandrew 75295011Sandrew if (cfg->assoc_wps_ie) { 76295011Sandrew struct wps_parse_attr attr; 77295011Sandrew wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 78295011Sandrew cfg->assoc_wps_ie); 79295011Sandrew if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 80295011Sandrew wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 81295011Sandrew "from (Re)AssocReq"); 82295011Sandrew } else if (attr.request_type == NULL) { 83295011Sandrew wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 84295011Sandrew "in (Re)AssocReq WPS IE"); 85295011Sandrew } else { 86295011Sandrew wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 87295011Sandrew "in (Re)AssocReq WPS IE): %d", 88295011Sandrew *attr.request_type); 89295011Sandrew data->request_type = *attr.request_type; 90295011Sandrew } 91295011Sandrew } 92295011Sandrew 93295011Sandrew if (cfg->new_ap_settings) { 94295011Sandrew data->new_ap_settings = 95295011Sandrew os_malloc(sizeof(*data->new_ap_settings)); 96295011Sandrew if (data->new_ap_settings == NULL) { 97295011Sandrew os_free(data); 98295011Sandrew return NULL; 99295011Sandrew } 100295011Sandrew os_memcpy(data->new_ap_settings, cfg->new_ap_settings, 101295011Sandrew sizeof(*data->new_ap_settings)); 102295011Sandrew } 103295011Sandrew 104295011Sandrew if (cfg->peer_addr) 105295011Sandrew os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 106295011Sandrew 107295011Sandrew data->use_psk_key = cfg->use_psk_key; 108295011Sandrew 109295011Sandrew return data; 110295011Sandrew} 111295011Sandrew 112295011Sandrew 113295011Sandrew/** 114295011Sandrew * wps_deinit - Deinitialize WPS Registration protocol data 115295011Sandrew * @data: WPS Registration protocol data from wps_init() 116295011Sandrew */ 117295011Sandrewvoid wps_deinit(struct wps_data *data) 118295011Sandrew{ 119295011Sandrew if (data->wps_pin_revealed) { 120295011Sandrew wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 121295011Sandrew "negotiation failed"); 122295011Sandrew if (data->registrar) 123295011Sandrew wps_registrar_invalidate_pin(data->wps->registrar, 124295011Sandrew data->uuid_e); 125295011Sandrew } else if (data->registrar) 126295011Sandrew wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 127295011Sandrew 128295011Sandrew wpabuf_free(data->dh_privkey); 129295011Sandrew wpabuf_free(data->dh_pubkey_e); 130295011Sandrew wpabuf_free(data->dh_pubkey_r); 131295011Sandrew wpabuf_free(data->last_msg); 132295011Sandrew os_free(data->dev_password); 133295011Sandrew os_free(data->new_psk); 134295011Sandrew wps_device_data_free(&data->peer_dev); 135295011Sandrew os_free(data->new_ap_settings); 136295011Sandrew dh5_free(data->dh_ctx); 137295011Sandrew os_free(data); 138295011Sandrew} 139295011Sandrew 140295011Sandrew 141295011Sandrew/** 142295011Sandrew * wps_process_msg - Process a WPS message 143295011Sandrew * @wps: WPS Registration protocol data from wps_init() 144295011Sandrew * @op_code: Message OP Code 145295011Sandrew * @msg: Message data 146295011Sandrew * Returns: Processing result 147295011Sandrew * 148295011Sandrew * This function is used to process WPS messages with OP Codes WSC_ACK, 149295011Sandrew * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 150295011Sandrew * responsible for reassembling the messages before calling this function. 151295011Sandrew * Response to this message is built by calling wps_get_msg(). 152295011Sandrew */ 153295011Sandrewenum wps_process_res wps_process_msg(struct wps_data *wps, 154295011Sandrew enum wsc_op_code op_code, 155295011Sandrew const struct wpabuf *msg) 156295011Sandrew{ 157295011Sandrew if (wps->registrar) 158295011Sandrew return wps_registrar_process_msg(wps, op_code, msg); 159295011Sandrew else 160295011Sandrew return wps_enrollee_process_msg(wps, op_code, msg); 161295011Sandrew} 162295011Sandrew 163295011Sandrew 164295011Sandrew/** 165295011Sandrew * wps_get_msg - Build a WPS message 166295011Sandrew * @wps: WPS Registration protocol data from wps_init() 167295011Sandrew * @op_code: Buffer for returning message OP Code 168295011Sandrew * Returns: The generated WPS message or %NULL on failure 169295011Sandrew * 170295011Sandrew * This function is used to build a response to a message processed by calling 171295011Sandrew * wps_process_msg(). The caller is responsible for freeing the buffer. 172295011Sandrew */ 173295011Sandrewstruct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 174295011Sandrew{ 175295011Sandrew if (wps->registrar) 176295011Sandrew return wps_registrar_get_msg(wps, op_code); 177295011Sandrew else 178295011Sandrew return wps_enrollee_get_msg(wps, op_code); 179295011Sandrew} 180295011Sandrew 181295011Sandrew 182295011Sandrew/** 183295011Sandrew * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 184295011Sandrew * @msg: WPS IE contents from Beacon or Probe Response frame 185295011Sandrew * Returns: 1 if PBC Registrar is active, 0 if not 186295011Sandrew */ 187295011Sandrewint wps_is_selected_pbc_registrar(const struct wpabuf *msg) 188295011Sandrew{ 189295011Sandrew struct wps_parse_attr attr; 190295011Sandrew 191295011Sandrew /* 192295011Sandrew * In theory, this could also verify that attr.sel_reg_config_methods 193295011Sandrew * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 194295011Sandrew * do not set Selected Registrar Config Methods attribute properly, so 195295011Sandrew * it is safer to just use Device Password ID here. 196295011Sandrew */ 197295011Sandrew 198295011Sandrew if (wps_parse_msg(msg, &attr) < 0 || 199295011Sandrew !attr.selected_registrar || *attr.selected_registrar == 0 || 200295011Sandrew !attr.dev_password_id || 201295011Sandrew WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 202295011Sandrew return 0; 203295011Sandrew 204295011Sandrew return 1; 205295011Sandrew} 206295011Sandrew 207295011Sandrew 208295011Sandrew/** 209295011Sandrew * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 210295011Sandrew * @msg: WPS IE contents from Beacon or Probe Response frame 211295011Sandrew * Returns: 1 if PIN Registrar is active, 0 if not 212295011Sandrew */ 213295011Sandrewint wps_is_selected_pin_registrar(const struct wpabuf *msg) 214295011Sandrew{ 215295011Sandrew struct wps_parse_attr attr; 216295011Sandrew 217295011Sandrew /* 218295011Sandrew * In theory, this could also verify that attr.sel_reg_config_methods 219295011Sandrew * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 220295011Sandrew * but some deployed AP implementations do not set Selected Registrar 221295011Sandrew * Config Methods attribute properly, so it is safer to just use 222295011Sandrew * Device Password ID here. 223295011Sandrew */ 224295011Sandrew 225295011Sandrew if (wps_parse_msg(msg, &attr) < 0) 226295011Sandrew return 0; 227295011Sandrew 228295011Sandrew if (!attr.selected_registrar || *attr.selected_registrar == 0) 229295011Sandrew return 0; 230295011Sandrew 231295011Sandrew if (attr.dev_password_id != NULL && 232295011Sandrew WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON) 233295011Sandrew return 0; 234295011Sandrew 235295011Sandrew return 1; 236295011Sandrew} 237295011Sandrew 238295011Sandrew 239295011Sandrew/** 240295011Sandrew * wps_get_uuid_e - Get UUID-E from WPS IE 241295011Sandrew * @msg: WPS IE contents from Beacon or Probe Response frame 242295011Sandrew * Returns: Pointer to UUID-E or %NULL if not included 243295011Sandrew * 244295011Sandrew * The returned pointer is to the msg contents and it remains valid only as 245295011Sandrew * long as the msg buffer is valid. 246295011Sandrew */ 247295011Sandrewconst u8 * wps_get_uuid_e(const struct wpabuf *msg) 248295011Sandrew{ 249295011Sandrew struct wps_parse_attr attr; 250295011Sandrew 251295011Sandrew if (wps_parse_msg(msg, &attr) < 0) 252295011Sandrew return NULL; 253295011Sandrew return attr.uuid_e; 254295011Sandrew} 255295011Sandrew 256295011Sandrew 257295011Sandrew/** 258295011Sandrew * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 259295011Sandrew * @req_type: Value for Request Type attribute 260295011Sandrew * Returns: WPS IE or %NULL on failure 261295011Sandrew * 262295011Sandrew * The caller is responsible for freeing the buffer. 263295011Sandrew */ 264295011Sandrewstruct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 265295011Sandrew{ 266295011Sandrew struct wpabuf *ie; 267295011Sandrew u8 *len; 268295011Sandrew 269295011Sandrew wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 270295011Sandrew "Request"); 271295011Sandrew ie = wpabuf_alloc(100); 272295011Sandrew if (ie == NULL) 273295011Sandrew return NULL; 274295011Sandrew 275295011Sandrew wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 276295011Sandrew len = wpabuf_put(ie, 1); 277295011Sandrew wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 278295011Sandrew 279295011Sandrew if (wps_build_version(ie) || 280295011Sandrew wps_build_req_type(ie, req_type)) { 281295011Sandrew wpabuf_free(ie); 282295011Sandrew return NULL; 283295011Sandrew } 284295011Sandrew 285295011Sandrew *len = wpabuf_len(ie) - 2; 286295011Sandrew 287295011Sandrew return ie; 288295011Sandrew} 289295011Sandrew 290295011Sandrew 291295011Sandrew/** 292295011Sandrew * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response 293295011Sandrew * Returns: WPS IE or %NULL on failure 294295011Sandrew * 295295011Sandrew * The caller is responsible for freeing the buffer. 296295011Sandrew */ 297295011Sandrewstruct wpabuf * wps_build_assoc_resp_ie(void) 298295011Sandrew{ 299295011Sandrew struct wpabuf *ie; 300295011Sandrew u8 *len; 301295011Sandrew 302295011Sandrew wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 303 "Response"); 304 ie = wpabuf_alloc(100); 305 if (ie == NULL) 306 return NULL; 307 308 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 309 len = wpabuf_put(ie, 1); 310 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 311 312 if (wps_build_version(ie) || 313 wps_build_resp_type(ie, WPS_RESP_AP)) { 314 wpabuf_free(ie); 315 return NULL; 316 } 317 318 *len = wpabuf_len(ie) - 2; 319 320 return ie; 321} 322 323 324/** 325 * wps_build_probe_req_ie - Build WPS IE for Probe Request 326 * @pbc: Whether searching for PBC mode APs 327 * @dev: Device attributes 328 * @uuid: Own UUID 329 * @req_type: Value for Request Type attribute 330 * Returns: WPS IE or %NULL on failure 331 * 332 * The caller is responsible for freeing the buffer. 333 */ 334struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 335 const u8 *uuid, 336 enum wps_request_type req_type) 337{ 338 struct wpabuf *ie; 339 u8 *len; 340 u16 methods; 341 342 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 343 344 ie = wpabuf_alloc(200); 345 if (ie == NULL) 346 return NULL; 347 348 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 349 len = wpabuf_put(ie, 1); 350 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 351 352 if (pbc) 353 methods = WPS_CONFIG_PUSHBUTTON; 354 else { 355 methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | 356 WPS_CONFIG_KEYPAD; 357#ifdef CONFIG_WPS_UFD 358 methods |= WPS_CONFIG_USBA; 359#endif /* CONFIG_WPS_UFD */ 360#ifdef CONFIG_WPS_NFC 361 methods |= WPS_CONFIG_NFC_INTERFACE; 362#endif /* CONFIG_WPS_NFC */ 363 } 364 365 if (wps_build_version(ie) || 366 wps_build_req_type(ie, req_type) || 367 wps_build_config_methods(ie, methods) || 368 wps_build_uuid_e(ie, uuid) || 369 wps_build_primary_dev_type(dev, ie) || 370 wps_build_rf_bands(dev, ie) || 371 wps_build_assoc_state(NULL, ie) || 372 wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 373 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 374 DEV_PW_DEFAULT)) { 375 wpabuf_free(ie); 376 return NULL; 377 } 378 379 *len = wpabuf_len(ie) - 2; 380 381 return ie; 382} 383 384 385void wps_free_pending_msgs(struct upnp_pending_message *msgs) 386{ 387 struct upnp_pending_message *p, *prev; 388 p = msgs; 389 while (p) { 390 prev = p; 391 p = p->next; 392 wpabuf_free(prev->msg); 393 os_free(prev); 394 } 395} 396 397 398int wps_attr_text(struct wpabuf *data, char *buf, char *end) 399{ 400 struct wps_parse_attr attr; 401 char *pos = buf; 402 int ret; 403 404 if (wps_parse_msg(data, &attr) < 0) 405 return -1; 406 407 if (attr.wps_state) { 408 if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 409 ret = os_snprintf(pos, end - pos, 410 "wps_state=unconfigured\n"); 411 else if (*attr.wps_state == WPS_STATE_CONFIGURED) 412 ret = os_snprintf(pos, end - pos, 413 "wps_state=configured\n"); 414 else 415 ret = 0; 416 if (ret < 0 || ret >= end - pos) 417 return pos - buf; 418 pos += ret; 419 } 420 421 if (attr.ap_setup_locked && *attr.ap_setup_locked) { 422 ret = os_snprintf(pos, end - pos, 423 "wps_ap_setup_locked=1\n"); 424 if (ret < 0 || ret >= end - pos) 425 return pos - buf; 426 pos += ret; 427 } 428 429 if (attr.selected_registrar && *attr.selected_registrar) { 430 ret = os_snprintf(pos, end - pos, 431 "wps_selected_registrar=1\n"); 432 if (ret < 0 || ret >= end - pos) 433 return pos - buf; 434 pos += ret; 435 } 436 437 if (attr.dev_password_id) { 438 ret = os_snprintf(pos, end - pos, 439 "wps_device_password_id=%u\n", 440 WPA_GET_BE16(attr.dev_password_id)); 441 if (ret < 0 || ret >= end - pos) 442 return pos - buf; 443 pos += ret; 444 } 445 446 if (attr.sel_reg_config_methods) { 447 ret = os_snprintf(pos, end - pos, 448 "wps_selected_registrar_config_methods=" 449 "0x%04x\n", 450 WPA_GET_BE16(attr.sel_reg_config_methods)); 451 if (ret < 0 || ret >= end - pos) 452 return pos - buf; 453 pos += ret; 454 } 455 456 if (attr.primary_dev_type) { 457 char devtype[WPS_DEV_TYPE_BUFSIZE]; 458 ret = os_snprintf(pos, end - pos, 459 "wps_primary_device_type=%s\n", 460 wps_dev_type_bin2str(attr.primary_dev_type, 461 devtype, 462 sizeof(devtype))); 463 if (ret < 0 || ret >= end - pos) 464 return pos - buf; 465 pos += ret; 466 } 467 468 if (attr.dev_name) { 469 char *str = os_malloc(attr.dev_name_len + 1); 470 size_t i; 471 if (str == NULL) 472 return pos - buf; 473 for (i = 0; i < attr.dev_name_len; i++) { 474 if (attr.dev_name[i] < 32) 475 str[i] = '_'; 476 else 477 str[i] = attr.dev_name[i]; 478 } 479 str[i] = '\0'; 480 ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 481 os_free(str); 482 if (ret < 0 || ret >= end - pos) 483 return pos - buf; 484 pos += ret; 485 } 486 487 if (attr.config_methods) { 488 ret = os_snprintf(pos, end - pos, 489 "wps_config_methods=0x%04x\n", 490 WPA_GET_BE16(attr.config_methods)); 491 if (ret < 0 || ret >= end - pos) 492 return pos - buf; 493 pos += ret; 494 } 495 496 return pos - buf; 497} 498