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