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