wps.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
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#ifdef CONFIG_WPS_TESTING
25int wps_version_number = 0x20;
26int wps_testing_dummy_cred = 0;
27#endif /* CONFIG_WPS_TESTING */
28
29
30/**
31 * wps_init - Initialize WPS Registration protocol data
32 * @cfg: WPS configuration
33 * Returns: Pointer to allocated data or %NULL on failure
34 *
35 * This function is used to initialize WPS data for a registration protocol
36 * instance (i.e., each run of registration protocol as a Registrar of
37 * Enrollee. The caller is responsible for freeing this data after the
38 * registration run has been completed by calling wps_deinit().
39 */
40struct wps_data * wps_init(const struct wps_config *cfg)
41{
42	struct wps_data *data = os_zalloc(sizeof(*data));
43	if (data == NULL)
44		return NULL;
45	data->wps = cfg->wps;
46	data->registrar = cfg->registrar;
47	if (cfg->registrar) {
48		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
49	} else {
50		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
51		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
52	}
53	if (cfg->pin) {
54		data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
55			cfg->dev_pw_id : data->wps->oob_dev_pw_id;
56		data->dev_password = os_malloc(cfg->pin_len);
57		if (data->dev_password == NULL) {
58			os_free(data);
59			return NULL;
60		}
61		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
62		data->dev_password_len = cfg->pin_len;
63	}
64
65	data->pbc = cfg->pbc;
66	if (cfg->pbc) {
67		/* Use special PIN '00000000' for PBC */
68		data->dev_pw_id = DEV_PW_PUSHBUTTON;
69		os_free(data->dev_password);
70		data->dev_password = (u8 *) os_strdup("00000000");
71		if (data->dev_password == NULL) {
72			os_free(data);
73			return NULL;
74		}
75		data->dev_password_len = 8;
76	}
77
78	data->state = data->registrar ? RECV_M1 : SEND_M1;
79
80	if (cfg->assoc_wps_ie) {
81		struct wps_parse_attr attr;
82		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
83				cfg->assoc_wps_ie);
84		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
85			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
86				   "from (Re)AssocReq");
87		} else if (attr.request_type == NULL) {
88			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
89				   "in (Re)AssocReq WPS IE");
90		} else {
91			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
92				   "in (Re)AssocReq WPS IE): %d",
93				   *attr.request_type);
94			data->request_type = *attr.request_type;
95		}
96	}
97
98	if (cfg->new_ap_settings) {
99		data->new_ap_settings =
100			os_malloc(sizeof(*data->new_ap_settings));
101		if (data->new_ap_settings == NULL) {
102			os_free(data);
103			return NULL;
104		}
105		os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
106			  sizeof(*data->new_ap_settings));
107	}
108
109	if (cfg->peer_addr)
110		os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
111	if (cfg->p2p_dev_addr)
112		os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN);
113
114	data->use_psk_key = cfg->use_psk_key;
115	data->pbc_in_m1 = cfg->pbc_in_m1;
116
117	return data;
118}
119
120
121/**
122 * wps_deinit - Deinitialize WPS Registration protocol data
123 * @data: WPS Registration protocol data from wps_init()
124 */
125void wps_deinit(struct wps_data *data)
126{
127	if (data->wps_pin_revealed) {
128		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
129			   "negotiation failed");
130		if (data->registrar)
131			wps_registrar_invalidate_pin(data->wps->registrar,
132						     data->uuid_e);
133	} else if (data->registrar)
134		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
135
136	wpabuf_free(data->dh_privkey);
137	wpabuf_free(data->dh_pubkey_e);
138	wpabuf_free(data->dh_pubkey_r);
139	wpabuf_free(data->last_msg);
140	os_free(data->dev_password);
141	os_free(data->new_psk);
142	wps_device_data_free(&data->peer_dev);
143	os_free(data->new_ap_settings);
144	dh5_free(data->dh_ctx);
145	os_free(data);
146}
147
148
149/**
150 * wps_process_msg - Process a WPS message
151 * @wps: WPS Registration protocol data from wps_init()
152 * @op_code: Message OP Code
153 * @msg: Message data
154 * Returns: Processing result
155 *
156 * This function is used to process WPS messages with OP Codes WSC_ACK,
157 * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
158 * responsible for reassembling the messages before calling this function.
159 * Response to this message is built by calling wps_get_msg().
160 */
161enum wps_process_res wps_process_msg(struct wps_data *wps,
162				     enum wsc_op_code op_code,
163				     const struct wpabuf *msg)
164{
165	if (wps->registrar)
166		return wps_registrar_process_msg(wps, op_code, msg);
167	else
168		return wps_enrollee_process_msg(wps, op_code, msg);
169}
170
171
172/**
173 * wps_get_msg - Build a WPS message
174 * @wps: WPS Registration protocol data from wps_init()
175 * @op_code: Buffer for returning message OP Code
176 * Returns: The generated WPS message or %NULL on failure
177 *
178 * This function is used to build a response to a message processed by calling
179 * wps_process_msg(). The caller is responsible for freeing the buffer.
180 */
181struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
182{
183	if (wps->registrar)
184		return wps_registrar_get_msg(wps, op_code);
185	else
186		return wps_enrollee_get_msg(wps, op_code);
187}
188
189
190/**
191 * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
192 * @msg: WPS IE contents from Beacon or Probe Response frame
193 * Returns: 1 if PBC Registrar is active, 0 if not
194 */
195int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
196{
197	struct wps_parse_attr attr;
198
199	/*
200	 * In theory, this could also verify that attr.sel_reg_config_methods
201	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
202	 * do not set Selected Registrar Config Methods attribute properly, so
203	 * it is safer to just use Device Password ID here.
204	 */
205
206	if (wps_parse_msg(msg, &attr) < 0 ||
207	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
208	    !attr.dev_password_id ||
209	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
210		return 0;
211
212#ifdef CONFIG_WPS_STRICT
213	if (!attr.sel_reg_config_methods ||
214	    !(WPA_GET_BE16(attr.sel_reg_config_methods) &
215	      WPS_CONFIG_PUSHBUTTON))
216		return 0;
217#endif /* CONFIG_WPS_STRICT */
218
219	return 1;
220}
221
222
223static int is_selected_pin_registrar(struct wps_parse_attr *attr)
224{
225	/*
226	 * In theory, this could also verify that attr.sel_reg_config_methods
227	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
228	 * but some deployed AP implementations do not set Selected Registrar
229	 * Config Methods attribute properly, so it is safer to just use
230	 * Device Password ID here.
231	 */
232
233	if (!attr->selected_registrar || *attr->selected_registrar == 0)
234		return 0;
235
236	if (attr->dev_password_id != NULL &&
237	    WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
238		return 0;
239
240#ifdef CONFIG_WPS_STRICT
241	if (!attr->sel_reg_config_methods ||
242	    !(WPA_GET_BE16(attr->sel_reg_config_methods) &
243	      (WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)))
244		return 0;
245#endif /* CONFIG_WPS_STRICT */
246
247	return 1;
248}
249
250
251/**
252 * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
253 * @msg: WPS IE contents from Beacon or Probe Response frame
254 * Returns: 1 if PIN Registrar is active, 0 if not
255 */
256int wps_is_selected_pin_registrar(const struct wpabuf *msg)
257{
258	struct wps_parse_attr attr;
259
260	if (wps_parse_msg(msg, &attr) < 0)
261		return 0;
262
263	return is_selected_pin_registrar(&attr);
264}
265
266
267/**
268 * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
269 * @msg: WPS IE contents from Beacon or Probe Response frame
270 * @addr: MAC address to search for
271 * @ver1_compat: Whether to use version 1 compatibility mode
272 * Returns: 1 if address is authorized, 0 if not
273 */
274int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
275			   int ver1_compat)
276{
277	struct wps_parse_attr attr;
278	unsigned int i;
279	const u8 *pos;
280	const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
281
282	if (wps_parse_msg(msg, &attr) < 0)
283		return 0;
284
285	if (!attr.version2 && ver1_compat) {
286		/*
287		 * Version 1.0 AP - AuthorizedMACs not used, so revert back to
288		 * old mechanism of using SelectedRegistrar.
289		 */
290		return is_selected_pin_registrar(&attr);
291	}
292
293	if (!attr.authorized_macs)
294		return 0;
295
296	pos = attr.authorized_macs;
297	for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
298		if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
299		    os_memcmp(pos, bcast, ETH_ALEN) == 0)
300			return 1;
301		pos += ETH_ALEN;
302	}
303
304	return 0;
305}
306
307
308/**
309 * wps_ap_priority_compar - Prioritize WPS IE from two APs
310 * @wps_a: WPS IE contents from Beacon or Probe Response frame
311 * @wps_b: WPS IE contents from Beacon or Probe Response frame
312 * Returns: 1 if wps_b is considered more likely selection for WPS
313 * provisioning, -1 if wps_a is considered more like, or 0 if no preference
314 */
315int wps_ap_priority_compar(const struct wpabuf *wps_a,
316			   const struct wpabuf *wps_b)
317{
318	struct wps_parse_attr attr_a, attr_b;
319	int sel_a, sel_b;
320
321	if (wps_a == NULL || wps_parse_msg(wps_a, &attr_a) < 0)
322		return 1;
323	if (wps_b == NULL || wps_parse_msg(wps_b, &attr_b) < 0)
324		return -1;
325
326	sel_a = attr_a.selected_registrar && *attr_a.selected_registrar != 0;
327	sel_b = attr_b.selected_registrar && *attr_b.selected_registrar != 0;
328
329	if (sel_a && !sel_b)
330		return -1;
331	if (!sel_a && sel_b)
332		return 1;
333
334	return 0;
335}
336
337
338/**
339 * wps_get_uuid_e - Get UUID-E from WPS IE
340 * @msg: WPS IE contents from Beacon or Probe Response frame
341 * Returns: Pointer to UUID-E or %NULL if not included
342 *
343 * The returned pointer is to the msg contents and it remains valid only as
344 * long as the msg buffer is valid.
345 */
346const u8 * wps_get_uuid_e(const struct wpabuf *msg)
347{
348	struct wps_parse_attr attr;
349
350	if (wps_parse_msg(msg, &attr) < 0)
351		return NULL;
352	return attr.uuid_e;
353}
354
355
356/**
357 * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
358 */
359int wps_is_20(const struct wpabuf *msg)
360{
361	struct wps_parse_attr attr;
362
363	if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
364		return 0;
365	return attr.version2 != NULL;
366}
367
368
369/**
370 * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
371 * @req_type: Value for Request Type attribute
372 * Returns: WPS IE or %NULL on failure
373 *
374 * The caller is responsible for freeing the buffer.
375 */
376struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
377{
378	struct wpabuf *ie;
379	u8 *len;
380
381	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
382		   "Request");
383	ie = wpabuf_alloc(100);
384	if (ie == NULL)
385		return NULL;
386
387	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
388	len = wpabuf_put(ie, 1);
389	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
390
391	if (wps_build_version(ie) ||
392	    wps_build_req_type(ie, req_type) ||
393	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
394		wpabuf_free(ie);
395		return NULL;
396	}
397
398	*len = wpabuf_len(ie) - 2;
399
400	return ie;
401}
402
403
404/**
405 * wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response
406 * Returns: WPS IE or %NULL on failure
407 *
408 * The caller is responsible for freeing the buffer.
409 */
410struct wpabuf * wps_build_assoc_resp_ie(void)
411{
412	struct wpabuf *ie;
413	u8 *len;
414
415	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
416		   "Response");
417	ie = wpabuf_alloc(100);
418	if (ie == NULL)
419		return NULL;
420
421	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
422	len = wpabuf_put(ie, 1);
423	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
424
425	if (wps_build_version(ie) ||
426	    wps_build_resp_type(ie, WPS_RESP_AP) ||
427	    wps_build_wfa_ext(ie, 0, NULL, 0)) {
428		wpabuf_free(ie);
429		return NULL;
430	}
431
432	*len = wpabuf_len(ie) - 2;
433
434	return ie;
435}
436
437
438/**
439 * wps_build_probe_req_ie - Build WPS IE for Probe Request
440 * @pbc: Whether searching for PBC mode APs
441 * @dev: Device attributes
442 * @uuid: Own UUID
443 * @req_type: Value for Request Type attribute
444 * @num_req_dev_types: Number of requested device types
445 * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
446 *	%NULL if none
447 * Returns: WPS IE or %NULL on failure
448 *
449 * The caller is responsible for freeing the buffer.
450 */
451struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
452				       const u8 *uuid,
453				       enum wps_request_type req_type,
454				       unsigned int num_req_dev_types,
455				       const u8 *req_dev_types)
456{
457	struct wpabuf *ie;
458
459	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
460
461	ie = wpabuf_alloc(500);
462	if (ie == NULL)
463		return NULL;
464
465	if (wps_build_version(ie) ||
466	    wps_build_req_type(ie, req_type) ||
467	    wps_build_config_methods(ie, dev->config_methods) ||
468	    wps_build_uuid_e(ie, uuid) ||
469	    wps_build_primary_dev_type(dev, ie) ||
470	    wps_build_rf_bands(dev, ie) ||
471	    wps_build_assoc_state(NULL, ie) ||
472	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
473	    wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
474				      DEV_PW_DEFAULT) ||
475#ifdef CONFIG_WPS2
476	    wps_build_manufacturer(dev, ie) ||
477	    wps_build_model_name(dev, ie) ||
478	    wps_build_model_number(dev, ie) ||
479	    wps_build_dev_name(dev, ie) ||
480	    wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
481#endif /* CONFIG_WPS2 */
482	    wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
483	    ||
484	    wps_build_secondary_dev_type(dev, ie)
485		) {
486		wpabuf_free(ie);
487		return NULL;
488	}
489
490#ifndef CONFIG_WPS2
491	if (dev->p2p && wps_build_dev_name(dev, ie)) {
492		wpabuf_free(ie);
493		return NULL;
494	}
495#endif /* CONFIG_WPS2 */
496
497	return wps_ie_encapsulate(ie);
498}
499
500
501void wps_free_pending_msgs(struct upnp_pending_message *msgs)
502{
503	struct upnp_pending_message *p, *prev;
504	p = msgs;
505	while (p) {
506		prev = p;
507		p = p->next;
508		wpabuf_free(prev->msg);
509		os_free(prev);
510	}
511}
512
513
514int wps_attr_text(struct wpabuf *data, char *buf, char *end)
515{
516	struct wps_parse_attr attr;
517	char *pos = buf;
518	int ret;
519
520	if (wps_parse_msg(data, &attr) < 0)
521		return -1;
522
523	if (attr.wps_state) {
524		if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED)
525			ret = os_snprintf(pos, end - pos,
526					  "wps_state=unconfigured\n");
527		else if (*attr.wps_state == WPS_STATE_CONFIGURED)
528			ret = os_snprintf(pos, end - pos,
529					  "wps_state=configured\n");
530		else
531			ret = 0;
532		if (ret < 0 || ret >= end - pos)
533			return pos - buf;
534		pos += ret;
535	}
536
537	if (attr.ap_setup_locked && *attr.ap_setup_locked) {
538		ret = os_snprintf(pos, end - pos,
539				  "wps_ap_setup_locked=1\n");
540		if (ret < 0 || ret >= end - pos)
541			return pos - buf;
542		pos += ret;
543	}
544
545	if (attr.selected_registrar && *attr.selected_registrar) {
546		ret = os_snprintf(pos, end - pos,
547				  "wps_selected_registrar=1\n");
548		if (ret < 0 || ret >= end - pos)
549			return pos - buf;
550		pos += ret;
551	}
552
553	if (attr.dev_password_id) {
554		ret = os_snprintf(pos, end - pos,
555				  "wps_device_password_id=%u\n",
556				  WPA_GET_BE16(attr.dev_password_id));
557		if (ret < 0 || ret >= end - pos)
558			return pos - buf;
559		pos += ret;
560	}
561
562	if (attr.sel_reg_config_methods) {
563		ret = os_snprintf(pos, end - pos,
564				  "wps_selected_registrar_config_methods="
565				  "0x%04x\n",
566				  WPA_GET_BE16(attr.sel_reg_config_methods));
567		if (ret < 0 || ret >= end - pos)
568			return pos - buf;
569		pos += ret;
570	}
571
572	if (attr.primary_dev_type) {
573		char devtype[WPS_DEV_TYPE_BUFSIZE];
574		ret = os_snprintf(pos, end - pos,
575				  "wps_primary_device_type=%s\n",
576				  wps_dev_type_bin2str(attr.primary_dev_type,
577						       devtype,
578						       sizeof(devtype)));
579		if (ret < 0 || ret >= end - pos)
580			return pos - buf;
581		pos += ret;
582	}
583
584	if (attr.dev_name) {
585		char *str = os_malloc(attr.dev_name_len + 1);
586		size_t i;
587		if (str == NULL)
588			return pos - buf;
589		for (i = 0; i < attr.dev_name_len; i++) {
590			if (attr.dev_name[i] < 32)
591				str[i] = '_';
592			else
593				str[i] = attr.dev_name[i];
594		}
595		str[i] = '\0';
596		ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
597		os_free(str);
598		if (ret < 0 || ret >= end - pos)
599			return pos - buf;
600		pos += ret;
601	}
602
603	if (attr.config_methods) {
604		ret = os_snprintf(pos, end - pos,
605				  "wps_config_methods=0x%04x\n",
606				  WPA_GET_BE16(attr.config_methods));
607		if (ret < 0 || ret >= end - pos)
608			return pos - buf;
609		pos += ret;
610	}
611
612	return pos - buf;
613}
614