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 /** 25 * wps_init - Initialize WPS Registration protocol data 26 * @cfg: WPS configuration 27 * Returns: Pointer to allocated data or %NULL on failure 28 * 29 * This function is used to initialize WPS data for a registration protocol 30 * instance (i.e., each run of registration protocol as a Registrar of 31 * Enrollee. The caller is responsible for freeing this data after the 32 * registration run has been completed by calling wps_deinit(). 33 */ 34 struct wps_data * wps_init(const struct wps_config *cfg) 35 { 36 struct wps_data *data = os_zalloc(sizeof(*data)); 37 if (data == NULL) 38 return NULL; 39 data->wps = cfg->wps; 40 data->registrar = cfg->registrar; 41 if (cfg->registrar) { 42 os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 43 } else { 44 os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 45 os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 46 } 47 if (cfg->pin) { 48 data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ? 49 DEV_PW_DEFAULT : data->wps->oob_dev_pw_id; 50 data->dev_password = os_malloc(cfg->pin_len); 51 if (data->dev_password == NULL) { 52 os_free(data); 53 return NULL; 54 } 55 os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); 56 data->dev_password_len = cfg->pin_len; 57 } 58 59 data->pbc = cfg->pbc; 60 if (cfg->pbc) { 61 /* Use special PIN '00000000' for PBC */ 62 data->dev_pw_id = DEV_PW_PUSHBUTTON; 63 os_free(data->dev_password); 64 data->dev_password = os_malloc(8); 65 if (data->dev_password == NULL) { 66 os_free(data); 67 return NULL; 68 } 69 os_memset(data->dev_password, '0', 8); 70 data->dev_password_len = 8; 71 } 72 73 data->state = data->registrar ? RECV_M1 : SEND_M1; 74 75 if (cfg->assoc_wps_ie) { 76 struct wps_parse_attr attr; 77 wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 78 cfg->assoc_wps_ie); 79 if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 80 wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 81 "from (Re)AssocReq"); 82 } else if (attr.request_type == NULL) { 83 wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 84 "in (Re)AssocReq WPS IE"); 85 } else { 86 wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 87 "in (Re)AssocReq WPS IE): %d", 88 *attr.request_type); 89 data->request_type = *attr.request_type; 90 } 91 } 92 93 if (cfg->new_ap_settings) { 94 data->new_ap_settings = 95 os_malloc(sizeof(*data->new_ap_settings)); 96 if (data->new_ap_settings == NULL) { 97 os_free(data); 98 return NULL; 99 } 100 os_memcpy(data->new_ap_settings, cfg->new_ap_settings, 101 sizeof(*data->new_ap_settings)); 102 } 103 104 if (cfg->peer_addr) 105 os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); 106 107 data->use_psk_key = cfg->use_psk_key; 108 109 return data; 110 } 111 112 113 /** 114 * wps_deinit - Deinitialize WPS Registration protocol data 115 * @data: WPS Registration protocol data from wps_init() 116 */ 117 void wps_deinit(struct wps_data *data) 118 { 119 if (data->wps_pin_revealed) { 120 wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 121 "negotiation failed"); 122 if (data->registrar) 123 wps_registrar_invalidate_pin(data->wps->registrar, 124 data->uuid_e); 125 } else if (data->registrar) 126 wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 127 128 wpabuf_free(data->dh_privkey); 129 wpabuf_free(data->dh_pubkey_e); 130 wpabuf_free(data->dh_pubkey_r); 131 wpabuf_free(data->last_msg); 132 os_free(data->dev_password); 133 os_free(data->new_psk); 134 wps_device_data_free(&data->peer_dev); 135 os_free(data->new_ap_settings); 136 dh5_free(data->dh_ctx); 137 os_free(data); 138 } 139 140 141 /** 142 * wps_process_msg - Process a WPS message 143 * @wps: WPS Registration protocol data from wps_init() 144 * @op_code: Message OP Code 145 * @msg: Message data 146 * Returns: Processing result 147 * 148 * This function is used to process WPS messages with OP Codes WSC_ACK, 149 * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 150 * responsible for reassembling the messages before calling this function. 151 * Response to this message is built by calling wps_get_msg(). 152 */ 153 enum wps_process_res wps_process_msg(struct wps_data *wps, 154 enum wsc_op_code op_code, 155 const struct wpabuf *msg) 156 { 157 if (wps->registrar) 158 return wps_registrar_process_msg(wps, op_code, msg); 159 else 160 return wps_enrollee_process_msg(wps, op_code, msg); 161 } 162 163 164 /** 165 * wps_get_msg - Build a WPS message 166 * @wps: WPS Registration protocol data from wps_init() 167 * @op_code: Buffer for returning message OP Code 168 * Returns: The generated WPS message or %NULL on failure 169 * 170 * This function is used to build a response to a message processed by calling 171 * wps_process_msg(). The caller is responsible for freeing the buffer. 172 */ 173 struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 174 { 175 if (wps->registrar) 176 return wps_registrar_get_msg(wps, op_code); 177 else 178 return wps_enrollee_get_msg(wps, op_code); 179 } 180 181 182 /** 183 * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 184 * @msg: WPS IE contents from Beacon or Probe Response frame 185 * Returns: 1 if PBC Registrar is active, 0 if not 186 */ 187 int wps_is_selected_pbc_registrar(const struct wpabuf *msg) 188 { 189 struct wps_parse_attr attr; 190 191 /* 192 * In theory, this could also verify that attr.sel_reg_config_methods 193 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 194 * do not set Selected Registrar Config Methods attribute properly, so 195 * it is safer to just use Device Password ID here. 196 */ 197 198 if (wps_parse_msg(msg, &attr) < 0 || 199 !attr.selected_registrar || *attr.selected_registrar == 0 || 200 !attr.dev_password_id || 201 WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 202 return 0; 203 204 return 1; 205 } 206 207 208 /** 209 * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 210 * @msg: WPS IE contents from Beacon or Probe Response frame 211 * Returns: 1 if PIN Registrar is active, 0 if not 212 */ 213 int wps_is_selected_pin_registrar(const struct wpabuf *msg) 214 { 215 struct wps_parse_attr attr; 216 217 /* 218 * In theory, this could also verify that attr.sel_reg_config_methods 219 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 220 * but some deployed AP implementations do not set Selected Registrar 221 * Config Methods attribute properly, so it is safer to just use 222 * Device Password ID here. 223 */ 224 225 if (wps_parse_msg(msg, &attr) < 0) 226 return 0; 227 228 if (!attr.selected_registrar || *attr.selected_registrar == 0) 229 return 0; 230 231 if (attr.dev_password_id != NULL && 232 WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON) 233 return 0; 234 235 return 1; 236 } 237 238 239 /** 240 * wps_get_uuid_e - Get UUID-E from WPS IE 241 * @msg: WPS IE contents from Beacon or Probe Response frame 242 * Returns: Pointer to UUID-E or %NULL if not included 243 * 244 * The returned pointer is to the msg contents and it remains valid only as 245 * long as the msg buffer is valid. 246 */ 247 const u8 * wps_get_uuid_e(const struct wpabuf *msg) 248 { 249 struct wps_parse_attr attr; 250 251 if (wps_parse_msg(msg, &attr) < 0) 252 return NULL; 253 return attr.uuid_e; 254 } 255 256 257 /** 258 * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 259 * @req_type: Value for Request Type attribute 260 * Returns: WPS IE or %NULL on failure 261 * 262 * The caller is responsible for freeing the buffer. 263 */ 264 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 265 { 266 struct wpabuf *ie; 267 u8 *len; 268 269 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 270 "Request"); 271 ie = wpabuf_alloc(100); 272 if (ie == NULL) 273 return NULL; 274 275 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 276 len = wpabuf_put(ie, 1); 277 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 278 279 if (wps_build_version(ie) || 280 wps_build_req_type(ie, req_type)) { 281 wpabuf_free(ie); 282 return NULL; 283 } 284 285 *len = wpabuf_len(ie) - 2; 286 287 return ie; 288 } 289 290 291 /** 292 * wps_build_probe_req_ie - Build WPS IE for Probe Request 293 * @pbc: Whether searching for PBC mode APs 294 * @dev: Device attributes 295 * @uuid: Own UUID 296 * @req_type: Value for Request Type attribute 297 * Returns: WPS IE or %NULL on failure 298 * 299 * The caller is responsible for freeing the buffer. 300 */ 301 struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 302 const u8 *uuid, 303 enum wps_request_type req_type) 304 { 305 struct wpabuf *ie; 306 u8 *len; 307 u16 methods; 308 309 wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 310 311 ie = wpabuf_alloc(200); 312 if (ie == NULL) 313 return NULL; 314 315 wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 316 len = wpabuf_put(ie, 1); 317 wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 318 319 if (pbc) 320 methods = WPS_CONFIG_PUSHBUTTON; 321 else { 322 methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | 323 WPS_CONFIG_KEYPAD; 324 #ifdef CONFIG_WPS_UFD 325 methods |= WPS_CONFIG_USBA; 326 #endif /* CONFIG_WPS_UFD */ 327 #ifdef CONFIG_WPS_NFC 328 methods |= WPS_CONFIG_NFC_INTERFACE; 329 #endif /* CONFIG_WPS_NFC */ 330 } 331 332 if (wps_build_version(ie) || 333 wps_build_req_type(ie, req_type) || 334 wps_build_config_methods(ie, methods) || 335 wps_build_uuid_e(ie, uuid) || 336 wps_build_primary_dev_type(dev, ie) || 337 wps_build_rf_bands(dev, ie) || 338 wps_build_assoc_state(NULL, ie) || 339 wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 340 wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 341 DEV_PW_DEFAULT)) { 342 wpabuf_free(ie); 343 return NULL; 344 } 345 346 *len = wpabuf_len(ie) - 2; 347 348 return ie; 349 } 350 351 352 void wps_free_pending_msgs(struct upnp_pending_message *msgs) 353 { 354 struct upnp_pending_message *p, *prev; 355 p = msgs; 356 while (p) { 357 prev = p; 358 p = p->next; 359 wpabuf_free(prev->msg); 360 os_free(prev); 361 } 362 } 363 364 365 int wps_attr_text(struct wpabuf *data, char *buf, char *end) 366 { 367 struct wps_parse_attr attr; 368 char *pos = buf; 369 int ret; 370 371 if (wps_parse_msg(data, &attr) < 0) 372 return -1; 373 374 if (attr.wps_state) { 375 if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED) 376 ret = os_snprintf(pos, end - pos, 377 "wps_state=unconfigured\n"); 378 else if (*attr.wps_state == WPS_STATE_CONFIGURED) 379 ret = os_snprintf(pos, end - pos, 380 "wps_state=configured\n"); 381 else 382 ret = 0; 383 if (ret < 0 || ret >= end - pos) 384 return pos - buf; 385 pos += ret; 386 } 387 388 if (attr.ap_setup_locked && *attr.ap_setup_locked) { 389 ret = os_snprintf(pos, end - pos, 390 "wps_ap_setup_locked=1\n"); 391 if (ret < 0 || ret >= end - pos) 392 return pos - buf; 393 pos += ret; 394 } 395 396 if (attr.selected_registrar && *attr.selected_registrar) { 397 ret = os_snprintf(pos, end - pos, 398 "wps_selected_registrar=1\n"); 399 if (ret < 0 || ret >= end - pos) 400 return pos - buf; 401 pos += ret; 402 } 403 404 if (attr.dev_password_id) { 405 ret = os_snprintf(pos, end - pos, 406 "wps_device_password_id=%u\n", 407 WPA_GET_BE16(attr.dev_password_id)); 408 if (ret < 0 || ret >= end - pos) 409 return pos - buf; 410 pos += ret; 411 } 412 413 if (attr.sel_reg_config_methods) { 414 ret = os_snprintf(pos, end - pos, 415 "wps_selected_registrar_config_methods=" 416 "0x%04x\n", 417 WPA_GET_BE16(attr.sel_reg_config_methods)); 418 if (ret < 0 || ret >= end - pos) 419 return pos - buf; 420 pos += ret; 421 } 422 423 if (attr.primary_dev_type) { 424 char devtype[WPS_DEV_TYPE_BUFSIZE]; 425 ret = os_snprintf(pos, end - pos, 426 "wps_primary_device_type=%s\n", 427 wps_dev_type_bin2str(attr.primary_dev_type, 428 devtype, 429 sizeof(devtype))); 430 if (ret < 0 || ret >= end - pos) 431 return pos - buf; 432 pos += ret; 433 } 434 435 if (attr.dev_name) { 436 char *str = os_malloc(attr.dev_name_len + 1); 437 size_t i; 438 if (str == NULL) 439 return pos - buf; 440 for (i = 0; i < attr.dev_name_len; i++) { 441 if (attr.dev_name[i] < 32) 442 str[i] = '_'; 443 else 444 str[i] = attr.dev_name[i]; 445 } 446 str[i] = '\0'; 447 ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str); 448 os_free(str); 449 if (ret < 0 || ret >= end - pos) 450 return pos - buf; 451 pos += ret; 452 } 453 454 if (attr.config_methods) { 455 ret = os_snprintf(pos, end - pos, 456 "wps_config_methods=0x%04x\n", 457 WPA_GET_BE16(attr.config_methods)); 458 if (ret < 0 || ret >= end - pos) 459 return pos - buf; 460 pos += ret; 461 } 462 463 return pos - buf; 464 } 465