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