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