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