xref: /dragonfly/contrib/wpa_supplicant/src/wps/wps.c (revision b58f1e66)
1 /*
2  * Wi-Fi Protected Setup
3  * Copyright (c) 2007-2008, 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 "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