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