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