1*6d49e1aeSJan Lentfer /* 2*6d49e1aeSJan Lentfer * Wi-Fi Protected Setup 3*6d49e1aeSJan Lentfer * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 4*6d49e1aeSJan Lentfer * 5*6d49e1aeSJan Lentfer * This program is free software; you can redistribute it and/or modify 6*6d49e1aeSJan Lentfer * it under the terms of the GNU General Public License version 2 as 7*6d49e1aeSJan Lentfer * published by the Free Software Foundation. 8*6d49e1aeSJan Lentfer * 9*6d49e1aeSJan Lentfer * Alternatively, this software may be distributed under the terms of BSD 10*6d49e1aeSJan Lentfer * license. 11*6d49e1aeSJan Lentfer * 12*6d49e1aeSJan Lentfer * See README and COPYING for more details. 13*6d49e1aeSJan Lentfer */ 14*6d49e1aeSJan Lentfer 15*6d49e1aeSJan Lentfer #include "includes.h" 16*6d49e1aeSJan Lentfer 17*6d49e1aeSJan Lentfer #include "common.h" 18*6d49e1aeSJan Lentfer #include "wps_i.h" 19*6d49e1aeSJan Lentfer #include "wps_dev_attr.h" 20*6d49e1aeSJan Lentfer #include "ieee802_11_defs.h" 21*6d49e1aeSJan Lentfer 22*6d49e1aeSJan Lentfer 23*6d49e1aeSJan Lentfer /** 24*6d49e1aeSJan Lentfer * wps_init - Initialize WPS Registration protocol data 25*6d49e1aeSJan Lentfer * @cfg: WPS configuration 26*6d49e1aeSJan Lentfer * Returns: Pointer to allocated data or %NULL on failure 27*6d49e1aeSJan Lentfer * 28*6d49e1aeSJan Lentfer * This function is used to initialize WPS data for a registration protocol 29*6d49e1aeSJan Lentfer * instance (i.e., each run of registration protocol as a Registrar of 30*6d49e1aeSJan Lentfer * Enrollee. The caller is responsible for freeing this data after the 31*6d49e1aeSJan Lentfer * registration run has been completed by calling wps_deinit(). 32*6d49e1aeSJan Lentfer */ 33*6d49e1aeSJan Lentfer struct wps_data * wps_init(const struct wps_config *cfg) 34*6d49e1aeSJan Lentfer { 35*6d49e1aeSJan Lentfer struct wps_data *data = os_zalloc(sizeof(*data)); 36*6d49e1aeSJan Lentfer if (data == NULL) 37*6d49e1aeSJan Lentfer return NULL; 38*6d49e1aeSJan Lentfer data->wps = cfg->wps; 39*6d49e1aeSJan Lentfer data->registrar = cfg->registrar; 40*6d49e1aeSJan Lentfer if (cfg->registrar) { 41*6d49e1aeSJan Lentfer os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN); 42*6d49e1aeSJan Lentfer } else { 43*6d49e1aeSJan Lentfer os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN); 44*6d49e1aeSJan Lentfer os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN); 45*6d49e1aeSJan Lentfer } 46*6d49e1aeSJan Lentfer if (cfg->pin) { 47*6d49e1aeSJan Lentfer data->dev_pw_id = DEV_PW_DEFAULT; 48*6d49e1aeSJan Lentfer data->dev_password = os_malloc(cfg->pin_len); 49*6d49e1aeSJan Lentfer if (data->dev_password == NULL) { 50*6d49e1aeSJan Lentfer os_free(data); 51*6d49e1aeSJan Lentfer return NULL; 52*6d49e1aeSJan Lentfer } 53*6d49e1aeSJan Lentfer os_memcpy(data->dev_password, cfg->pin, cfg->pin_len); 54*6d49e1aeSJan Lentfer data->dev_password_len = cfg->pin_len; 55*6d49e1aeSJan Lentfer } 56*6d49e1aeSJan Lentfer 57*6d49e1aeSJan Lentfer data->pbc = cfg->pbc; 58*6d49e1aeSJan Lentfer if (cfg->pbc) { 59*6d49e1aeSJan Lentfer /* Use special PIN '00000000' for PBC */ 60*6d49e1aeSJan Lentfer data->dev_pw_id = DEV_PW_PUSHBUTTON; 61*6d49e1aeSJan Lentfer os_free(data->dev_password); 62*6d49e1aeSJan Lentfer data->dev_password = os_malloc(8); 63*6d49e1aeSJan Lentfer if (data->dev_password == NULL) { 64*6d49e1aeSJan Lentfer os_free(data); 65*6d49e1aeSJan Lentfer return NULL; 66*6d49e1aeSJan Lentfer } 67*6d49e1aeSJan Lentfer os_memset(data->dev_password, '0', 8); 68*6d49e1aeSJan Lentfer data->dev_password_len = 8; 69*6d49e1aeSJan Lentfer } 70*6d49e1aeSJan Lentfer 71*6d49e1aeSJan Lentfer data->state = data->registrar ? RECV_M1 : SEND_M1; 72*6d49e1aeSJan Lentfer 73*6d49e1aeSJan Lentfer if (cfg->assoc_wps_ie) { 74*6d49e1aeSJan Lentfer struct wps_parse_attr attr; 75*6d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq", 76*6d49e1aeSJan Lentfer cfg->assoc_wps_ie); 77*6d49e1aeSJan Lentfer if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) { 78*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE " 79*6d49e1aeSJan Lentfer "from (Re)AssocReq"); 80*6d49e1aeSJan Lentfer } else if (attr.request_type == NULL) { 81*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute " 82*6d49e1aeSJan Lentfer "in (Re)AssocReq WPS IE"); 83*6d49e1aeSJan Lentfer } else { 84*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE " 85*6d49e1aeSJan Lentfer "in (Re)AssocReq WPS IE): %d", 86*6d49e1aeSJan Lentfer *attr.request_type); 87*6d49e1aeSJan Lentfer data->request_type = *attr.request_type; 88*6d49e1aeSJan Lentfer } 89*6d49e1aeSJan Lentfer } 90*6d49e1aeSJan Lentfer 91*6d49e1aeSJan Lentfer return data; 92*6d49e1aeSJan Lentfer } 93*6d49e1aeSJan Lentfer 94*6d49e1aeSJan Lentfer 95*6d49e1aeSJan Lentfer /** 96*6d49e1aeSJan Lentfer * wps_deinit - Deinitialize WPS Registration protocol data 97*6d49e1aeSJan Lentfer * @data: WPS Registration protocol data from wps_init() 98*6d49e1aeSJan Lentfer */ 99*6d49e1aeSJan Lentfer void wps_deinit(struct wps_data *data) 100*6d49e1aeSJan Lentfer { 101*6d49e1aeSJan Lentfer if (data->wps_pin_revealed) { 102*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " 103*6d49e1aeSJan Lentfer "negotiation failed"); 104*6d49e1aeSJan Lentfer if (data->registrar) 105*6d49e1aeSJan Lentfer wps_registrar_invalidate_pin(data->wps->registrar, 106*6d49e1aeSJan Lentfer data->uuid_e); 107*6d49e1aeSJan Lentfer } else if (data->registrar) 108*6d49e1aeSJan Lentfer wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e); 109*6d49e1aeSJan Lentfer 110*6d49e1aeSJan Lentfer wpabuf_free(data->dh_privkey); 111*6d49e1aeSJan Lentfer wpabuf_free(data->dh_pubkey_e); 112*6d49e1aeSJan Lentfer wpabuf_free(data->dh_pubkey_r); 113*6d49e1aeSJan Lentfer wpabuf_free(data->last_msg); 114*6d49e1aeSJan Lentfer os_free(data->dev_password); 115*6d49e1aeSJan Lentfer os_free(data->new_psk); 116*6d49e1aeSJan Lentfer wps_device_data_free(&data->peer_dev); 117*6d49e1aeSJan Lentfer os_free(data); 118*6d49e1aeSJan Lentfer } 119*6d49e1aeSJan Lentfer 120*6d49e1aeSJan Lentfer 121*6d49e1aeSJan Lentfer /** 122*6d49e1aeSJan Lentfer * wps_process_msg - Process a WPS message 123*6d49e1aeSJan Lentfer * @wps: WPS Registration protocol data from wps_init() 124*6d49e1aeSJan Lentfer * @op_code: Message OP Code 125*6d49e1aeSJan Lentfer * @msg: Message data 126*6d49e1aeSJan Lentfer * Returns: Processing result 127*6d49e1aeSJan Lentfer * 128*6d49e1aeSJan Lentfer * This function is used to process WPS messages with OP Codes WSC_ACK, 129*6d49e1aeSJan Lentfer * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is 130*6d49e1aeSJan Lentfer * responsible for reassembling the messages before calling this function. 131*6d49e1aeSJan Lentfer * Response to this message is built by calling wps_get_msg(). 132*6d49e1aeSJan Lentfer */ 133*6d49e1aeSJan Lentfer enum wps_process_res wps_process_msg(struct wps_data *wps, 134*6d49e1aeSJan Lentfer enum wsc_op_code op_code, 135*6d49e1aeSJan Lentfer const struct wpabuf *msg) 136*6d49e1aeSJan Lentfer { 137*6d49e1aeSJan Lentfer if (wps->registrar) 138*6d49e1aeSJan Lentfer return wps_registrar_process_msg(wps, op_code, msg); 139*6d49e1aeSJan Lentfer else 140*6d49e1aeSJan Lentfer return wps_enrollee_process_msg(wps, op_code, msg); 141*6d49e1aeSJan Lentfer } 142*6d49e1aeSJan Lentfer 143*6d49e1aeSJan Lentfer 144*6d49e1aeSJan Lentfer /** 145*6d49e1aeSJan Lentfer * wps_get_msg - Build a WPS message 146*6d49e1aeSJan Lentfer * @wps: WPS Registration protocol data from wps_init() 147*6d49e1aeSJan Lentfer * @op_code: Buffer for returning message OP Code 148*6d49e1aeSJan Lentfer * Returns: The generated WPS message or %NULL on failure 149*6d49e1aeSJan Lentfer * 150*6d49e1aeSJan Lentfer * This function is used to build a response to a message processed by calling 151*6d49e1aeSJan Lentfer * wps_process_msg(). The caller is responsible for freeing the buffer. 152*6d49e1aeSJan Lentfer */ 153*6d49e1aeSJan Lentfer struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code) 154*6d49e1aeSJan Lentfer { 155*6d49e1aeSJan Lentfer if (wps->registrar) 156*6d49e1aeSJan Lentfer return wps_registrar_get_msg(wps, op_code); 157*6d49e1aeSJan Lentfer else 158*6d49e1aeSJan Lentfer return wps_enrollee_get_msg(wps, op_code); 159*6d49e1aeSJan Lentfer } 160*6d49e1aeSJan Lentfer 161*6d49e1aeSJan Lentfer 162*6d49e1aeSJan Lentfer /** 163*6d49e1aeSJan Lentfer * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC 164*6d49e1aeSJan Lentfer * @msg: WPS IE contents from Beacon or Probe Response frame 165*6d49e1aeSJan Lentfer * Returns: 1 if PBC Registrar is active, 0 if not 166*6d49e1aeSJan Lentfer */ 167*6d49e1aeSJan Lentfer int wps_is_selected_pbc_registrar(const struct wpabuf *msg) 168*6d49e1aeSJan Lentfer { 169*6d49e1aeSJan Lentfer struct wps_parse_attr attr; 170*6d49e1aeSJan Lentfer 171*6d49e1aeSJan Lentfer /* 172*6d49e1aeSJan Lentfer * In theory, this could also verify that attr.sel_reg_config_methods 173*6d49e1aeSJan Lentfer * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations 174*6d49e1aeSJan Lentfer * do not set Selected Registrar Config Methods attribute properly, so 175*6d49e1aeSJan Lentfer * it is safer to just use Device Password ID here. 176*6d49e1aeSJan Lentfer */ 177*6d49e1aeSJan Lentfer 178*6d49e1aeSJan Lentfer if (wps_parse_msg(msg, &attr) < 0 || 179*6d49e1aeSJan Lentfer !attr.selected_registrar || *attr.selected_registrar == 0 || 180*6d49e1aeSJan Lentfer !attr.dev_password_id || 181*6d49e1aeSJan Lentfer WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 182*6d49e1aeSJan Lentfer return 0; 183*6d49e1aeSJan Lentfer 184*6d49e1aeSJan Lentfer return 1; 185*6d49e1aeSJan Lentfer } 186*6d49e1aeSJan Lentfer 187*6d49e1aeSJan Lentfer 188*6d49e1aeSJan Lentfer /** 189*6d49e1aeSJan Lentfer * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN 190*6d49e1aeSJan Lentfer * @msg: WPS IE contents from Beacon or Probe Response frame 191*6d49e1aeSJan Lentfer * Returns: 1 if PIN Registrar is active, 0 if not 192*6d49e1aeSJan Lentfer */ 193*6d49e1aeSJan Lentfer int wps_is_selected_pin_registrar(const struct wpabuf *msg) 194*6d49e1aeSJan Lentfer { 195*6d49e1aeSJan Lentfer struct wps_parse_attr attr; 196*6d49e1aeSJan Lentfer 197*6d49e1aeSJan Lentfer /* 198*6d49e1aeSJan Lentfer * In theory, this could also verify that attr.sel_reg_config_methods 199*6d49e1aeSJan Lentfer * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD, 200*6d49e1aeSJan Lentfer * but some deployed AP implementations do not set Selected Registrar 201*6d49e1aeSJan Lentfer * Config Methods attribute properly, so it is safer to just use 202*6d49e1aeSJan Lentfer * Device Password ID here. 203*6d49e1aeSJan Lentfer */ 204*6d49e1aeSJan Lentfer 205*6d49e1aeSJan Lentfer if (wps_parse_msg(msg, &attr) < 0) 206*6d49e1aeSJan Lentfer return 0; 207*6d49e1aeSJan Lentfer 208*6d49e1aeSJan Lentfer if (!attr.selected_registrar || *attr.selected_registrar == 0) 209*6d49e1aeSJan Lentfer return 0; 210*6d49e1aeSJan Lentfer 211*6d49e1aeSJan Lentfer if (attr.dev_password_id != NULL && 212*6d49e1aeSJan Lentfer WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON) 213*6d49e1aeSJan Lentfer return 0; 214*6d49e1aeSJan Lentfer 215*6d49e1aeSJan Lentfer return 1; 216*6d49e1aeSJan Lentfer } 217*6d49e1aeSJan Lentfer 218*6d49e1aeSJan Lentfer 219*6d49e1aeSJan Lentfer /** 220*6d49e1aeSJan Lentfer * wps_get_uuid_e - Get UUID-E from WPS IE 221*6d49e1aeSJan Lentfer * @msg: WPS IE contents from Beacon or Probe Response frame 222*6d49e1aeSJan Lentfer * Returns: Pointer to UUID-E or %NULL if not included 223*6d49e1aeSJan Lentfer * 224*6d49e1aeSJan Lentfer * The returned pointer is to the msg contents and it remains valid only as 225*6d49e1aeSJan Lentfer * long as the msg buffer is valid. 226*6d49e1aeSJan Lentfer */ 227*6d49e1aeSJan Lentfer const u8 * wps_get_uuid_e(const struct wpabuf *msg) 228*6d49e1aeSJan Lentfer { 229*6d49e1aeSJan Lentfer struct wps_parse_attr attr; 230*6d49e1aeSJan Lentfer 231*6d49e1aeSJan Lentfer if (wps_parse_msg(msg, &attr) < 0) 232*6d49e1aeSJan Lentfer return NULL; 233*6d49e1aeSJan Lentfer return attr.uuid_e; 234*6d49e1aeSJan Lentfer } 235*6d49e1aeSJan Lentfer 236*6d49e1aeSJan Lentfer 237*6d49e1aeSJan Lentfer /** 238*6d49e1aeSJan Lentfer * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request 239*6d49e1aeSJan Lentfer * @req_type: Value for Request Type attribute 240*6d49e1aeSJan Lentfer * Returns: WPS IE or %NULL on failure 241*6d49e1aeSJan Lentfer * 242*6d49e1aeSJan Lentfer * The caller is responsible for freeing the buffer. 243*6d49e1aeSJan Lentfer */ 244*6d49e1aeSJan Lentfer struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) 245*6d49e1aeSJan Lentfer { 246*6d49e1aeSJan Lentfer struct wpabuf *ie; 247*6d49e1aeSJan Lentfer u8 *len; 248*6d49e1aeSJan Lentfer 249*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association " 250*6d49e1aeSJan Lentfer "Request"); 251*6d49e1aeSJan Lentfer ie = wpabuf_alloc(100); 252*6d49e1aeSJan Lentfer if (ie == NULL) 253*6d49e1aeSJan Lentfer return NULL; 254*6d49e1aeSJan Lentfer 255*6d49e1aeSJan Lentfer wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 256*6d49e1aeSJan Lentfer len = wpabuf_put(ie, 1); 257*6d49e1aeSJan Lentfer wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 258*6d49e1aeSJan Lentfer 259*6d49e1aeSJan Lentfer if (wps_build_version(ie) || 260*6d49e1aeSJan Lentfer wps_build_req_type(ie, req_type)) { 261*6d49e1aeSJan Lentfer wpabuf_free(ie); 262*6d49e1aeSJan Lentfer return NULL; 263*6d49e1aeSJan Lentfer } 264*6d49e1aeSJan Lentfer 265*6d49e1aeSJan Lentfer *len = wpabuf_len(ie) - 2; 266*6d49e1aeSJan Lentfer 267*6d49e1aeSJan Lentfer return ie; 268*6d49e1aeSJan Lentfer } 269*6d49e1aeSJan Lentfer 270*6d49e1aeSJan Lentfer 271*6d49e1aeSJan Lentfer /** 272*6d49e1aeSJan Lentfer * wps_build_probe_req_ie - Build WPS IE for Probe Request 273*6d49e1aeSJan Lentfer * @pbc: Whether searching for PBC mode APs 274*6d49e1aeSJan Lentfer * @dev: Device attributes 275*6d49e1aeSJan Lentfer * @uuid: Own UUID 276*6d49e1aeSJan Lentfer * @req_type: Value for Request Type attribute 277*6d49e1aeSJan Lentfer * Returns: WPS IE or %NULL on failure 278*6d49e1aeSJan Lentfer * 279*6d49e1aeSJan Lentfer * The caller is responsible for freeing the buffer. 280*6d49e1aeSJan Lentfer */ 281*6d49e1aeSJan Lentfer struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, 282*6d49e1aeSJan Lentfer const u8 *uuid, 283*6d49e1aeSJan Lentfer enum wps_request_type req_type) 284*6d49e1aeSJan Lentfer { 285*6d49e1aeSJan Lentfer struct wpabuf *ie; 286*6d49e1aeSJan Lentfer u8 *len; 287*6d49e1aeSJan Lentfer u16 methods; 288*6d49e1aeSJan Lentfer 289*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request"); 290*6d49e1aeSJan Lentfer 291*6d49e1aeSJan Lentfer ie = wpabuf_alloc(200); 292*6d49e1aeSJan Lentfer if (ie == NULL) 293*6d49e1aeSJan Lentfer return NULL; 294*6d49e1aeSJan Lentfer 295*6d49e1aeSJan Lentfer wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 296*6d49e1aeSJan Lentfer len = wpabuf_put(ie, 1); 297*6d49e1aeSJan Lentfer wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 298*6d49e1aeSJan Lentfer 299*6d49e1aeSJan Lentfer if (pbc) 300*6d49e1aeSJan Lentfer methods = WPS_CONFIG_PUSHBUTTON; 301*6d49e1aeSJan Lentfer else 302*6d49e1aeSJan Lentfer methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | 303*6d49e1aeSJan Lentfer WPS_CONFIG_KEYPAD; 304*6d49e1aeSJan Lentfer 305*6d49e1aeSJan Lentfer if (wps_build_version(ie) || 306*6d49e1aeSJan Lentfer wps_build_req_type(ie, req_type) || 307*6d49e1aeSJan Lentfer wps_build_config_methods(ie, methods) || 308*6d49e1aeSJan Lentfer wps_build_uuid_e(ie, uuid) || 309*6d49e1aeSJan Lentfer wps_build_primary_dev_type(dev, ie) || 310*6d49e1aeSJan Lentfer wps_build_rf_bands(dev, ie) || 311*6d49e1aeSJan Lentfer wps_build_assoc_state(NULL, ie) || 312*6d49e1aeSJan Lentfer wps_build_config_error(ie, WPS_CFG_NO_ERROR) || 313*6d49e1aeSJan Lentfer wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : 314*6d49e1aeSJan Lentfer DEV_PW_DEFAULT)) { 315*6d49e1aeSJan Lentfer wpabuf_free(ie); 316*6d49e1aeSJan Lentfer return NULL; 317*6d49e1aeSJan Lentfer } 318*6d49e1aeSJan Lentfer 319*6d49e1aeSJan Lentfer *len = wpabuf_len(ie) - 2; 320*6d49e1aeSJan Lentfer 321*6d49e1aeSJan Lentfer return ie; 322*6d49e1aeSJan Lentfer } 323*6d49e1aeSJan Lentfer 324*6d49e1aeSJan Lentfer 325*6d49e1aeSJan Lentfer void wps_free_pending_msgs(struct upnp_pending_message *msgs) 326*6d49e1aeSJan Lentfer { 327*6d49e1aeSJan Lentfer struct upnp_pending_message *p, *prev; 328*6d49e1aeSJan Lentfer p = msgs; 329*6d49e1aeSJan Lentfer while (p) { 330*6d49e1aeSJan Lentfer prev = p; 331*6d49e1aeSJan Lentfer p = p->next; 332*6d49e1aeSJan Lentfer wpabuf_free(prev->msg); 333*6d49e1aeSJan Lentfer os_free(prev); 334*6d49e1aeSJan Lentfer } 335*6d49e1aeSJan Lentfer } 336