]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/wpa/src/wps/wps_attr_parse.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / wpa / src / wps / wps_attr_parse.c
1 /*
2  * Wi-Fi Protected Setup - attribute parsing
3  * Copyright (c) 2008, 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 "wps_defs.h"
13 #include "wps_attr_parse.h"
14
15 #ifndef CONFIG_WPS_STRICT
16 #define WPS_WORKAROUNDS
17 #endif /* CONFIG_WPS_STRICT */
18
19
20 static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
21                                           u8 id, u8 len, const u8 *pos)
22 {
23         wpa_printf(MSG_EXCESSIVE, "WPS: WFA subelement id=%u len=%u",
24                    id, len);
25         switch (id) {
26         case WFA_ELEM_VERSION2:
27                 if (len != 1) {
28                         wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
29                                    "%u", len);
30                         return -1;
31                 }
32                 attr->version2 = pos;
33                 break;
34         case WFA_ELEM_AUTHORIZEDMACS:
35                 attr->authorized_macs = pos;
36                 attr->authorized_macs_len = len;
37                 break;
38         case WFA_ELEM_NETWORK_KEY_SHAREABLE:
39                 if (len != 1) {
40                         wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
41                                    "Shareable length %u", len);
42                         return -1;
43                 }
44                 attr->network_key_shareable = pos;
45                 break;
46         case WFA_ELEM_REQUEST_TO_ENROLL:
47                 if (len != 1) {
48                         wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
49                                    "length %u", len);
50                         return -1;
51                 }
52                 attr->request_to_enroll = pos;
53                 break;
54         case WFA_ELEM_SETTINGS_DELAY_TIME:
55                 if (len != 1) {
56                         wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
57                                    "Time length %u", len);
58                         return -1;
59                 }
60                 attr->settings_delay_time = pos;
61                 break;
62         default:
63                 wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor "
64                            "Extension subelement %u", id);
65                 break;
66         }
67
68         return 0;
69 }
70
71
72 static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
73                                     u16 len)
74 {
75         const u8 *end = pos + len;
76         u8 id, elen;
77
78         while (pos + 2 < end) {
79                 id = *pos++;
80                 elen = *pos++;
81                 if (pos + elen > end)
82                         break;
83                 if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
84                         return -1;
85                 pos += elen;
86         }
87
88         return 0;
89 }
90
91
92 static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
93                                 u16 len)
94 {
95         u32 vendor_id;
96
97         if (len < 3) {
98                 wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
99                 return 0;
100         }
101
102         vendor_id = WPA_GET_BE24(pos);
103         switch (vendor_id) {
104         case WPS_VENDOR_ID_WFA:
105                 return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
106         }
107
108         /* Handle unknown vendor extensions */
109
110         wpa_printf(MSG_MSGDUMP, "WPS: Unknown Vendor Extension (Vendor ID %u)",
111                    vendor_id);
112
113         if (len > WPS_MAX_VENDOR_EXT_LEN) {
114                 wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
115                            len);
116                 return -1;
117         }
118
119         if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
120                 wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
121                            "attribute (max %d vendor extensions)",
122                            MAX_WPS_PARSE_VENDOR_EXT);
123                 return -1;
124         }
125         attr->vendor_ext[attr->num_vendor_ext] = pos;
126         attr->vendor_ext_len[attr->num_vendor_ext] = len;
127         attr->num_vendor_ext++;
128
129         return 0;
130 }
131
132
133 static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
134                         const u8 *pos, u16 len)
135 {
136         switch (type) {
137         case ATTR_VERSION:
138                 if (len != 1) {
139                         wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
140                                    len);
141                         return -1;
142                 }
143                 attr->version = pos;
144                 break;
145         case ATTR_MSG_TYPE:
146                 if (len != 1) {
147                         wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
148                                    "length %u", len);
149                         return -1;
150                 }
151                 attr->msg_type = pos;
152                 break;
153         case ATTR_ENROLLEE_NONCE:
154                 if (len != WPS_NONCE_LEN) {
155                         wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
156                                    "length %u", len);
157                         return -1;
158                 }
159                 attr->enrollee_nonce = pos;
160                 break;
161         case ATTR_REGISTRAR_NONCE:
162                 if (len != WPS_NONCE_LEN) {
163                         wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
164                                    "length %u", len);
165                         return -1;
166                 }
167                 attr->registrar_nonce = pos;
168                 break;
169         case ATTR_UUID_E:
170                 if (len != WPS_UUID_LEN) {
171                         wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
172                                    len);
173                         return -1;
174                 }
175                 attr->uuid_e = pos;
176                 break;
177         case ATTR_UUID_R:
178                 if (len != WPS_UUID_LEN) {
179                         wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
180                                    len);
181                         return -1;
182                 }
183                 attr->uuid_r = pos;
184                 break;
185         case ATTR_AUTH_TYPE_FLAGS:
186                 if (len != 2) {
187                         wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
188                                    "Type Flags length %u", len);
189                         return -1;
190                 }
191                 attr->auth_type_flags = pos;
192                 break;
193         case ATTR_ENCR_TYPE_FLAGS:
194                 if (len != 2) {
195                         wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
196                                    "Flags length %u", len);
197                         return -1;
198                 }
199                 attr->encr_type_flags = pos;
200                 break;
201         case ATTR_CONN_TYPE_FLAGS:
202                 if (len != 1) {
203                         wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
204                                    "Flags length %u", len);
205                         return -1;
206                 }
207                 attr->conn_type_flags = pos;
208                 break;
209         case ATTR_CONFIG_METHODS:
210                 if (len != 2) {
211                         wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
212                                    "length %u", len);
213                         return -1;
214                 }
215                 attr->config_methods = pos;
216                 break;
217         case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
218                 if (len != 2) {
219                         wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
220                                    "Registrar Config Methods length %u", len);
221                         return -1;
222                 }
223                 attr->sel_reg_config_methods = pos;
224                 break;
225         case ATTR_PRIMARY_DEV_TYPE:
226                 if (len != WPS_DEV_TYPE_LEN) {
227                         wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
228                                    "Type length %u", len);
229                         return -1;
230                 }
231                 attr->primary_dev_type = pos;
232                 break;
233         case ATTR_RF_BANDS:
234                 if (len != 1) {
235                         wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
236                                    "%u", len);
237                         return -1;
238                 }
239                 attr->rf_bands = pos;
240                 break;
241         case ATTR_ASSOC_STATE:
242                 if (len != 2) {
243                         wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
244                                    "length %u", len);
245                         return -1;
246                 }
247                 attr->assoc_state = pos;
248                 break;
249         case ATTR_CONFIG_ERROR:
250                 if (len != 2) {
251                         wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
252                                    "Error length %u", len);
253                         return -1;
254                 }
255                 attr->config_error = pos;
256                 break;
257         case ATTR_DEV_PASSWORD_ID:
258                 if (len != 2) {
259                         wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
260                                    "ID length %u", len);
261                         return -1;
262                 }
263                 attr->dev_password_id = pos;
264                 break;
265         case ATTR_OOB_DEVICE_PASSWORD:
266                 if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
267                     WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
268                     len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
269                     WPS_OOB_DEVICE_PASSWORD_LEN) {
270                         wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
271                                    "Password length %u", len);
272                         return -1;
273                 }
274                 attr->oob_dev_password = pos;
275                 attr->oob_dev_password_len = len;
276                 break;
277         case ATTR_OS_VERSION:
278                 if (len != 4) {
279                         wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
280                                    "%u", len);
281                         return -1;
282                 }
283                 attr->os_version = pos;
284                 break;
285         case ATTR_WPS_STATE:
286                 if (len != 1) {
287                         wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
288                                    "Setup State length %u", len);
289                         return -1;
290                 }
291                 attr->wps_state = pos;
292                 break;
293         case ATTR_AUTHENTICATOR:
294                 if (len != WPS_AUTHENTICATOR_LEN) {
295                         wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
296                                    "length %u", len);
297                         return -1;
298                 }
299                 attr->authenticator = pos;
300                 break;
301         case ATTR_R_HASH1:
302                 if (len != WPS_HASH_LEN) {
303                         wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
304                                    len);
305                         return -1;
306                 }
307                 attr->r_hash1 = pos;
308                 break;
309         case ATTR_R_HASH2:
310                 if (len != WPS_HASH_LEN) {
311                         wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
312                                    len);
313                         return -1;
314                 }
315                 attr->r_hash2 = pos;
316                 break;
317         case ATTR_E_HASH1:
318                 if (len != WPS_HASH_LEN) {
319                         wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
320                                    len);
321                         return -1;
322                 }
323                 attr->e_hash1 = pos;
324                 break;
325         case ATTR_E_HASH2:
326                 if (len != WPS_HASH_LEN) {
327                         wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
328                                    len);
329                         return -1;
330                 }
331                 attr->e_hash2 = pos;
332                 break;
333         case ATTR_R_SNONCE1:
334                 if (len != WPS_SECRET_NONCE_LEN) {
335                         wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
336                                    "%u", len);
337                         return -1;
338                 }
339                 attr->r_snonce1 = pos;
340                 break;
341         case ATTR_R_SNONCE2:
342                 if (len != WPS_SECRET_NONCE_LEN) {
343                         wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
344                                    "%u", len);
345                         return -1;
346                 }
347                 attr->r_snonce2 = pos;
348                 break;
349         case ATTR_E_SNONCE1:
350                 if (len != WPS_SECRET_NONCE_LEN) {
351                         wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
352                                    "%u", len);
353                         return -1;
354                 }
355                 attr->e_snonce1 = pos;
356                 break;
357         case ATTR_E_SNONCE2:
358                 if (len != WPS_SECRET_NONCE_LEN) {
359                         wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
360                                    "%u", len);
361                         return -1;
362                 }
363                 attr->e_snonce2 = pos;
364                 break;
365         case ATTR_KEY_WRAP_AUTH:
366                 if (len != WPS_KWA_LEN) {
367                         wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
368                                    "Authenticator length %u", len);
369                         return -1;
370                 }
371                 attr->key_wrap_auth = pos;
372                 break;
373         case ATTR_AUTH_TYPE:
374                 if (len != 2) {
375                         wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
376                                    "Type length %u", len);
377                         return -1;
378                 }
379                 attr->auth_type = pos;
380                 break;
381         case ATTR_ENCR_TYPE:
382                 if (len != 2) {
383                         wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
384                                    "Type length %u", len);
385                         return -1;
386                 }
387                 attr->encr_type = pos;
388                 break;
389         case ATTR_NETWORK_INDEX:
390                 if (len != 1) {
391                         wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
392                                    "length %u", len);
393                         return -1;
394                 }
395                 attr->network_idx = pos;
396                 break;
397         case ATTR_NETWORK_KEY_INDEX:
398                 if (len != 1) {
399                         wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
400                                    "length %u", len);
401                         return -1;
402                 }
403                 attr->network_key_idx = pos;
404                 break;
405         case ATTR_MAC_ADDR:
406                 if (len != ETH_ALEN) {
407                         wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
408                                    "length %u", len);
409                         return -1;
410                 }
411                 attr->mac_addr = pos;
412                 break;
413         case ATTR_KEY_PROVIDED_AUTO:
414                 if (len != 1) {
415                         wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
416                                    "Automatically length %u", len);
417                         return -1;
418                 }
419                 attr->key_prov_auto = pos;
420                 break;
421         case ATTR_802_1X_ENABLED:
422                 if (len != 1) {
423                         wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
424                                    "length %u", len);
425                         return -1;
426                 }
427                 attr->dot1x_enabled = pos;
428                 break;
429         case ATTR_SELECTED_REGISTRAR:
430                 if (len != 1) {
431                         wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
432                                    " length %u", len);
433                         return -1;
434                 }
435                 attr->selected_registrar = pos;
436                 break;
437         case ATTR_REQUEST_TYPE:
438                 if (len != 1) {
439                         wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
440                                    "length %u", len);
441                         return -1;
442                 }
443                 attr->request_type = pos;
444                 break;
445         case ATTR_RESPONSE_TYPE:
446                 if (len != 1) {
447                         wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
448                                    "length %u", len);
449                         return -1;
450                 }
451                 attr->response_type = pos;
452                 break;
453         case ATTR_MANUFACTURER:
454                 attr->manufacturer = pos;
455                 attr->manufacturer_len = len;
456                 break;
457         case ATTR_MODEL_NAME:
458                 attr->model_name = pos;
459                 attr->model_name_len = len;
460                 break;
461         case ATTR_MODEL_NUMBER:
462                 attr->model_number = pos;
463                 attr->model_number_len = len;
464                 break;
465         case ATTR_SERIAL_NUMBER:
466                 attr->serial_number = pos;
467                 attr->serial_number_len = len;
468                 break;
469         case ATTR_DEV_NAME:
470                 attr->dev_name = pos;
471                 attr->dev_name_len = len;
472                 break;
473         case ATTR_PUBLIC_KEY:
474                 attr->public_key = pos;
475                 attr->public_key_len = len;
476                 break;
477         case ATTR_ENCR_SETTINGS:
478                 attr->encr_settings = pos;
479                 attr->encr_settings_len = len;
480                 break;
481         case ATTR_CRED:
482                 if (attr->num_cred >= MAX_CRED_COUNT) {
483                         wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
484                                    "attribute (max %d credentials)",
485                                    MAX_CRED_COUNT);
486                         break;
487                 }
488                 attr->cred[attr->num_cred] = pos;
489                 attr->cred_len[attr->num_cred] = len;
490                 attr->num_cred++;
491                 break;
492         case ATTR_SSID:
493                 attr->ssid = pos;
494                 attr->ssid_len = len;
495                 break;
496         case ATTR_NETWORK_KEY:
497                 attr->network_key = pos;
498                 attr->network_key_len = len;
499                 break;
500         case ATTR_EAP_TYPE:
501                 attr->eap_type = pos;
502                 attr->eap_type_len = len;
503                 break;
504         case ATTR_EAP_IDENTITY:
505                 attr->eap_identity = pos;
506                 attr->eap_identity_len = len;
507                 break;
508         case ATTR_AP_SETUP_LOCKED:
509                 if (len != 1) {
510                         wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
511                                    "length %u", len);
512                         return -1;
513                 }
514                 attr->ap_setup_locked = pos;
515                 break;
516         case ATTR_REQUESTED_DEV_TYPE:
517                 if (len != WPS_DEV_TYPE_LEN) {
518                         wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
519                                    "Type length %u", len);
520                         return -1;
521                 }
522                 if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
523                         wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
524                                    "Type attribute (max %u types)",
525                                    MAX_REQ_DEV_TYPE_COUNT);
526                         break;
527                 }
528                 attr->req_dev_type[attr->num_req_dev_type] = pos;
529                 attr->num_req_dev_type++;
530                 break;
531         case ATTR_SECONDARY_DEV_TYPE_LIST:
532                 if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
533                     (len % WPS_DEV_TYPE_LEN) > 0) {
534                         wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
535                                    "Type length %u", len);
536                         return -1;
537                 }
538                 attr->sec_dev_type_list = pos;
539                 attr->sec_dev_type_list_len = len;
540                 break;
541         case ATTR_VENDOR_EXT:
542                 if (wps_parse_vendor_ext(attr, pos, len) < 0)
543                         return -1;
544                 break;
545         case ATTR_AP_CHANNEL:
546                 if (len != 2) {
547                         wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
548                                    "length %u", len);
549                         return -1;
550                 }
551                 attr->ap_channel = pos;
552                 break;
553         default:
554                 wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
555                            "len=%u", type, len);
556                 break;
557         }
558
559         return 0;
560 }
561
562
563 int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
564 {
565         const u8 *pos, *end;
566         u16 type, len;
567 #ifdef WPS_WORKAROUNDS
568         u16 prev_type = 0;
569 #endif /* WPS_WORKAROUNDS */
570
571         os_memset(attr, 0, sizeof(*attr));
572         pos = wpabuf_head(msg);
573         end = pos + wpabuf_len(msg);
574
575         while (pos < end) {
576                 if (end - pos < 4) {
577                         wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
578                                    "%lu bytes remaining",
579                                    (unsigned long) (end - pos));
580                         return -1;
581                 }
582
583                 type = WPA_GET_BE16(pos);
584                 pos += 2;
585                 len = WPA_GET_BE16(pos);
586                 pos += 2;
587                 wpa_printf(MSG_EXCESSIVE, "WPS: attr type=0x%x len=%u",
588                            type, len);
589                 if (len > end - pos) {
590                         wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
591                         wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
592 #ifdef WPS_WORKAROUNDS
593                         /*
594                          * Some deployed APs seem to have a bug in encoding of
595                          * Network Key attribute in the Credential attribute
596                          * where they add an extra octet after the Network Key
597                          * attribute at least when open network is being
598                          * provisioned.
599                          */
600                         if ((type & 0xff00) != 0x1000 &&
601                             prev_type == ATTR_NETWORK_KEY) {
602                                 wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
603                                            "to skip unexpected octet after "
604                                            "Network Key");
605                                 pos -= 3;
606                                 continue;
607                         }
608 #endif /* WPS_WORKAROUNDS */
609                         return -1;
610                 }
611
612 #ifdef WPS_WORKAROUNDS
613                 if (type == 0 && len == 0) {
614                         /*
615                          * Mac OS X 10.6 seems to be adding 0x00 padding to the
616                          * end of M1. Skip those to avoid interop issues.
617                          */
618                         int i;
619                         for (i = 0; i < end - pos; i++) {
620                                 if (pos[i])
621                                         break;
622                         }
623                         if (i == end - pos) {
624                                 wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
625                                            "unexpected message padding");
626                                 break;
627                         }
628                 }
629 #endif /* WPS_WORKAROUNDS */
630
631                 if (wps_set_attr(attr, type, pos, len) < 0)
632                         return -1;
633
634 #ifdef WPS_WORKAROUNDS
635                 prev_type = type;
636 #endif /* WPS_WORKAROUNDS */
637                 pos += len;
638         }
639
640         return 0;
641 }