2 * Wi-Fi Protected Setup - attribute parsing
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "wps_attr_parse.h"
15 #ifndef CONFIG_WPS_STRICT
16 #define WPS_WORKAROUNDS
17 #endif /* CONFIG_WPS_STRICT */
20 static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr
*attr
,
21 u8 id
, u8 len
, const u8
*pos
)
23 wpa_printf(MSG_EXCESSIVE
, "WPS: WFA subelement id=%u len=%u",
26 case WFA_ELEM_VERSION2
:
28 wpa_printf(MSG_DEBUG
, "WPS: Invalid Version2 length "
34 case WFA_ELEM_AUTHORIZEDMACS
:
35 attr
->authorized_macs
= pos
;
36 attr
->authorized_macs_len
= len
;
38 case WFA_ELEM_NETWORK_KEY_SHAREABLE
:
40 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Key "
41 "Shareable length %u", len
);
44 attr
->network_key_shareable
= pos
;
46 case WFA_ELEM_REQUEST_TO_ENROLL
:
48 wpa_printf(MSG_DEBUG
, "WPS: Invalid Request to Enroll "
52 attr
->request_to_enroll
= pos
;
54 case WFA_ELEM_SETTINGS_DELAY_TIME
:
56 wpa_printf(MSG_DEBUG
, "WPS: Invalid Settings Delay "
57 "Time length %u", len
);
60 attr
->settings_delay_time
= pos
;
62 case WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS
:
64 wpa_printf(MSG_DEBUG
, "WPS: Invalid Registrar Configuration Methods length %u",
68 attr
->registrar_configuration_methods
= pos
;
70 case WFA_ELEM_MULTI_AP
:
73 "WPS: Invalid Multi-AP Extension length %u",
77 attr
->multi_ap_ext
= *pos
;
78 wpa_printf(MSG_DEBUG
, "WPS: Multi-AP Extension 0x%02x",
82 wpa_printf(MSG_MSGDUMP
, "WPS: Skipped unknown WFA Vendor "
83 "Extension subelement %u", id
);
91 static int wps_parse_vendor_ext_wfa(struct wps_parse_attr
*attr
, const u8
*pos
,
94 const u8
*end
= pos
+ len
;
97 while (end
- pos
>= 2) {
100 if (elen
> end
- pos
)
102 if (wps_set_vendor_ext_wfa_subelem(attr
, id
, elen
, pos
) < 0)
111 static int wps_parse_vendor_ext(struct wps_parse_attr
*attr
, const u8
*pos
,
117 wpa_printf(MSG_DEBUG
, "WPS: Skip invalid Vendor Extension");
121 vendor_id
= WPA_GET_BE24(pos
);
123 case WPS_VENDOR_ID_WFA
:
124 return wps_parse_vendor_ext_wfa(attr
, pos
+ 3, len
- 3);
127 /* Handle unknown vendor extensions */
129 wpa_printf(MSG_MSGDUMP
, "WPS: Unknown Vendor Extension (Vendor ID %u)",
132 if (len
> WPS_MAX_VENDOR_EXT_LEN
) {
133 wpa_printf(MSG_DEBUG
, "WPS: Too long Vendor Extension (%u)",
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
);
144 attr
->vendor_ext
[attr
->num_vendor_ext
] = pos
;
145 attr
->vendor_ext_len
[attr
->num_vendor_ext
] = len
;
146 attr
->num_vendor_ext
++;
152 static int wps_set_attr(struct wps_parse_attr
*attr
, u16 type
,
153 const u8
*pos
, u16 len
)
158 wpa_printf(MSG_DEBUG
, "WPS: Invalid Version length %u",
166 wpa_printf(MSG_DEBUG
, "WPS: Invalid Message Type "
170 attr
->msg_type
= pos
;
172 case ATTR_ENROLLEE_NONCE
:
173 if (len
!= WPS_NONCE_LEN
) {
174 wpa_printf(MSG_DEBUG
, "WPS: Invalid Enrollee Nonce "
178 attr
->enrollee_nonce
= pos
;
180 case ATTR_REGISTRAR_NONCE
:
181 if (len
!= WPS_NONCE_LEN
) {
182 wpa_printf(MSG_DEBUG
, "WPS: Invalid Registrar Nonce "
186 attr
->registrar_nonce
= pos
;
189 if (len
!= WPS_UUID_LEN
) {
190 wpa_printf(MSG_DEBUG
, "WPS: Invalid UUID-E length %u",
197 if (len
!= WPS_UUID_LEN
) {
198 wpa_printf(MSG_DEBUG
, "WPS: Invalid UUID-R length %u",
204 case ATTR_AUTH_TYPE_FLAGS
:
206 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authentication "
207 "Type Flags length %u", len
);
210 attr
->auth_type_flags
= pos
;
212 case ATTR_ENCR_TYPE_FLAGS
:
214 wpa_printf(MSG_DEBUG
, "WPS: Invalid Encryption Type "
215 "Flags length %u", len
);
218 attr
->encr_type_flags
= pos
;
220 case ATTR_CONN_TYPE_FLAGS
:
222 wpa_printf(MSG_DEBUG
, "WPS: Invalid Connection Type "
223 "Flags length %u", len
);
226 attr
->conn_type_flags
= pos
;
228 case ATTR_CONFIG_METHODS
:
230 wpa_printf(MSG_DEBUG
, "WPS: Invalid Config Methods "
234 attr
->config_methods
= pos
;
236 case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS
:
238 wpa_printf(MSG_DEBUG
, "WPS: Invalid Selected "
239 "Registrar Config Methods length %u", len
);
242 attr
->sel_reg_config_methods
= pos
;
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
);
250 attr
->primary_dev_type
= pos
;
254 wpa_printf(MSG_DEBUG
, "WPS: Invalid RF Bands length "
258 attr
->rf_bands
= pos
;
260 case ATTR_ASSOC_STATE
:
262 wpa_printf(MSG_DEBUG
, "WPS: Invalid Association State "
266 attr
->assoc_state
= pos
;
268 case ATTR_CONFIG_ERROR
:
270 wpa_printf(MSG_DEBUG
, "WPS: Invalid Configuration "
271 "Error length %u", len
);
274 attr
->config_error
= pos
;
276 case ATTR_DEV_PASSWORD_ID
:
278 wpa_printf(MSG_DEBUG
, "WPS: Invalid Device Password "
279 "ID length %u", len
);
282 attr
->dev_password_id
= pos
;
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
);
296 attr
->oob_dev_password
= pos
;
297 attr
->oob_dev_password_len
= len
;
299 case ATTR_OS_VERSION
:
301 wpa_printf(MSG_DEBUG
, "WPS: Invalid OS Version length "
305 attr
->os_version
= pos
;
309 wpa_printf(MSG_DEBUG
, "WPS: Invalid Wi-Fi Protected "
310 "Setup State length %u", len
);
313 attr
->wps_state
= pos
;
315 case ATTR_AUTHENTICATOR
:
316 if (len
!= WPS_AUTHENTICATOR_LEN
) {
317 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authenticator "
321 attr
->authenticator
= pos
;
324 if (len
!= WPS_HASH_LEN
) {
325 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-Hash1 length %u",
332 if (len
!= WPS_HASH_LEN
) {
333 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-Hash2 length %u",
340 if (len
!= WPS_HASH_LEN
) {
341 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-Hash1 length %u",
348 if (len
!= WPS_HASH_LEN
) {
349 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-Hash2 length %u",
356 if (len
!= WPS_SECRET_NONCE_LEN
) {
357 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-SNonce1 length "
361 attr
->r_snonce1
= pos
;
364 if (len
!= WPS_SECRET_NONCE_LEN
) {
365 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-SNonce2 length "
369 attr
->r_snonce2
= pos
;
372 if (len
!= WPS_SECRET_NONCE_LEN
) {
373 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-SNonce1 length "
377 attr
->e_snonce1
= pos
;
380 if (len
!= WPS_SECRET_NONCE_LEN
) {
381 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-SNonce2 length "
385 attr
->e_snonce2
= pos
;
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
);
393 attr
->key_wrap_auth
= pos
;
397 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authentication "
398 "Type length %u", len
);
401 attr
->auth_type
= pos
;
405 wpa_printf(MSG_DEBUG
, "WPS: Invalid Encryption "
406 "Type length %u", len
);
409 attr
->encr_type
= pos
;
411 case ATTR_NETWORK_INDEX
:
413 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Index "
417 attr
->network_idx
= pos
;
419 case ATTR_NETWORK_KEY_INDEX
:
421 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Key Index "
425 attr
->network_key_idx
= pos
;
428 if (len
!= ETH_ALEN
) {
429 wpa_printf(MSG_DEBUG
, "WPS: Invalid MAC Address "
433 attr
->mac_addr
= pos
;
435 case ATTR_SELECTED_REGISTRAR
:
437 wpa_printf(MSG_DEBUG
, "WPS: Invalid Selected Registrar"
441 attr
->selected_registrar
= pos
;
443 case ATTR_REQUEST_TYPE
:
445 wpa_printf(MSG_DEBUG
, "WPS: Invalid Request Type "
449 attr
->request_type
= pos
;
451 case ATTR_RESPONSE_TYPE
:
453 wpa_printf(MSG_DEBUG
, "WPS: Invalid Response Type "
457 attr
->response_type
= pos
;
459 case ATTR_MANUFACTURER
:
460 attr
->manufacturer
= pos
;
461 if (len
> WPS_MANUFACTURER_MAX_LEN
)
462 attr
->manufacturer_len
= WPS_MANUFACTURER_MAX_LEN
;
464 attr
->manufacturer_len
= len
;
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
;
471 attr
->model_name_len
= len
;
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
;
478 attr
->model_number_len
= len
;
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
;
485 attr
->serial_number_len
= len
;
488 if (len
> WPS_DEV_NAME_MAX_LEN
) {
489 wpa_printf(MSG_DEBUG
,
490 "WPS: Ignore too long Device Name (len=%u)",
494 attr
->dev_name
= pos
;
495 attr
->dev_name_len
= len
;
497 case ATTR_PUBLIC_KEY
:
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
504 if (len
< 190 || len
> 192) {
505 wpa_printf(MSG_DEBUG
,
506 "WPS: Ignore Public Key with unexpected length %u",
510 attr
->public_key
= pos
;
511 attr
->public_key_len
= len
;
513 case ATTR_ENCR_SETTINGS
:
514 attr
->encr_settings
= pos
;
515 attr
->encr_settings_len
= len
;
518 if (attr
->num_cred
>= MAX_CRED_COUNT
) {
519 wpa_printf(MSG_DEBUG
, "WPS: Skipped Credential "
520 "attribute (max %d credentials)",
524 attr
->cred
[attr
->num_cred
] = pos
;
525 attr
->cred_len
[attr
->num_cred
] = len
;
529 if (len
> SSID_MAX_LEN
) {
530 wpa_printf(MSG_DEBUG
,
531 "WPS: Ignore too long SSID (len=%u)", len
);
535 attr
->ssid_len
= len
;
537 case ATTR_NETWORK_KEY
:
538 attr
->network_key
= pos
;
539 attr
->network_key_len
= len
;
541 case ATTR_AP_SETUP_LOCKED
:
543 wpa_printf(MSG_DEBUG
, "WPS: Invalid AP Setup Locked "
547 attr
->ap_setup_locked
= pos
;
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
);
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
);
561 attr
->req_dev_type
[attr
->num_req_dev_type
] = pos
;
562 attr
->num_req_dev_type
++;
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
);
571 attr
->sec_dev_type_list
= pos
;
572 attr
->sec_dev_type_list_len
= len
;
574 case ATTR_VENDOR_EXT
:
575 if (wps_parse_vendor_ext(attr
, pos
, len
) < 0)
578 case ATTR_AP_CHANNEL
:
580 wpa_printf(MSG_DEBUG
, "WPS: Invalid AP Channel "
584 attr
->ap_channel
= pos
;
587 wpa_printf(MSG_DEBUG
, "WPS: Unsupported attribute type 0x%x "
588 "len=%u", type
, len
);
596 int wps_parse_msg(const struct wpabuf
*msg
, struct wps_parse_attr
*attr
)
600 #ifdef WPS_WORKAROUNDS
602 #endif /* WPS_WORKAROUNDS */
604 os_memset(attr
, 0, sizeof(*attr
));
605 pos
= wpabuf_head(msg
);
606 end
= pos
+ wpabuf_len(msg
);
610 wpa_printf(MSG_DEBUG
, "WPS: Invalid message - "
611 "%lu bytes remaining",
612 (unsigned long) (end
- pos
));
616 type
= WPA_GET_BE16(pos
);
618 len
= WPA_GET_BE16(pos
);
620 wpa_printf(MSG_EXCESSIVE
, "WPS: attr type=0x%x len=%u",
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
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
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 "
641 #endif /* WPS_WORKAROUNDS */
645 #ifdef WPS_WORKAROUNDS
646 if (type
== 0 && len
== 0) {
648 * Mac OS X 10.6 seems to be adding 0x00 padding to the
649 * end of M1. Skip those to avoid interop issues.
652 for (i
= 0; i
< end
- pos
; i
++) {
656 if (i
== end
- pos
) {
657 wpa_printf(MSG_DEBUG
, "WPS: Workaround - skip "
658 "unexpected message padding");
662 #endif /* WPS_WORKAROUNDS */
664 if (wps_set_attr(attr
, type
, pos
, len
) < 0)
667 #ifdef WPS_WORKAROUNDS
669 #endif /* WPS_WORKAROUNDS */