2 * Wi-Fi Protected Setup - attribute parsing
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
20 #ifndef CONFIG_WPS_STRICT
21 #define WPS_WORKAROUNDS
22 #endif /* CONFIG_WPS_STRICT */
25 static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr
*attr
,
26 u8 id
, u8 len
, const u8
*pos
)
28 wpa_printf(MSG_EXCESSIVE
, "WPS: WFA subelement id=%u len=%u",
31 case WFA_ELEM_VERSION2
:
33 wpa_printf(MSG_DEBUG
, "WPS: Invalid Version2 length "
39 case WFA_ELEM_AUTHORIZEDMACS
:
40 attr
->authorized_macs
= pos
;
41 attr
->authorized_macs_len
= len
;
43 case WFA_ELEM_NETWORK_KEY_SHAREABLE
:
45 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Key "
46 "Shareable length %u", len
);
49 attr
->network_key_shareable
= pos
;
51 case WFA_ELEM_REQUEST_TO_ENROLL
:
53 wpa_printf(MSG_DEBUG
, "WPS: Invalid Request to Enroll "
57 attr
->request_to_enroll
= pos
;
59 case WFA_ELEM_SETTINGS_DELAY_TIME
:
61 wpa_printf(MSG_DEBUG
, "WPS: Invalid Settings Delay "
62 "Time length %u", len
);
65 attr
->settings_delay_time
= pos
;
68 wpa_printf(MSG_MSGDUMP
, "WPS: Skipped unknown WFA Vendor "
69 "Extension subelement %u", id
);
77 static int wps_parse_vendor_ext_wfa(struct wps_parse_attr
*attr
, const u8
*pos
,
80 const u8
*end
= pos
+ len
;
83 while (pos
+ 2 < end
) {
88 if (wps_set_vendor_ext_wfa_subelem(attr
, id
, elen
, pos
) < 0)
97 static int wps_parse_vendor_ext(struct wps_parse_attr
*attr
, const u8
*pos
,
103 wpa_printf(MSG_DEBUG
, "WPS: Skip invalid Vendor Extension");
107 vendor_id
= WPA_GET_BE24(pos
);
109 case WPS_VENDOR_ID_WFA
:
110 return wps_parse_vendor_ext_wfa(attr
, pos
+ 3, len
- 3);
113 /* Handle unknown vendor extensions */
115 wpa_printf(MSG_MSGDUMP
, "WPS: Unknown Vendor Extension (Vendor ID %u)",
118 if (len
> WPS_MAX_VENDOR_EXT_LEN
) {
119 wpa_printf(MSG_DEBUG
, "WPS: Too long Vendor Extension (%u)",
124 if (attr
->num_vendor_ext
>= MAX_WPS_PARSE_VENDOR_EXT
) {
125 wpa_printf(MSG_DEBUG
, "WPS: Skipped Vendor Extension "
126 "attribute (max %d vendor extensions)",
127 MAX_WPS_PARSE_VENDOR_EXT
);
130 attr
->vendor_ext
[attr
->num_vendor_ext
] = pos
;
131 attr
->vendor_ext_len
[attr
->num_vendor_ext
] = len
;
132 attr
->num_vendor_ext
++;
138 static int wps_set_attr(struct wps_parse_attr
*attr
, u16 type
,
139 const u8
*pos
, u16 len
)
144 wpa_printf(MSG_DEBUG
, "WPS: Invalid Version length %u",
152 wpa_printf(MSG_DEBUG
, "WPS: Invalid Message Type "
156 attr
->msg_type
= pos
;
158 case ATTR_ENROLLEE_NONCE
:
159 if (len
!= WPS_NONCE_LEN
) {
160 wpa_printf(MSG_DEBUG
, "WPS: Invalid Enrollee Nonce "
164 attr
->enrollee_nonce
= pos
;
166 case ATTR_REGISTRAR_NONCE
:
167 if (len
!= WPS_NONCE_LEN
) {
168 wpa_printf(MSG_DEBUG
, "WPS: Invalid Registrar Nonce "
172 attr
->registrar_nonce
= pos
;
175 if (len
!= WPS_UUID_LEN
) {
176 wpa_printf(MSG_DEBUG
, "WPS: Invalid UUID-E length %u",
183 if (len
!= WPS_UUID_LEN
) {
184 wpa_printf(MSG_DEBUG
, "WPS: Invalid UUID-R length %u",
190 case ATTR_AUTH_TYPE_FLAGS
:
192 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authentication "
193 "Type Flags length %u", len
);
196 attr
->auth_type_flags
= pos
;
198 case ATTR_ENCR_TYPE_FLAGS
:
200 wpa_printf(MSG_DEBUG
, "WPS: Invalid Encryption Type "
201 "Flags length %u", len
);
204 attr
->encr_type_flags
= pos
;
206 case ATTR_CONN_TYPE_FLAGS
:
208 wpa_printf(MSG_DEBUG
, "WPS: Invalid Connection Type "
209 "Flags length %u", len
);
212 attr
->conn_type_flags
= pos
;
214 case ATTR_CONFIG_METHODS
:
216 wpa_printf(MSG_DEBUG
, "WPS: Invalid Config Methods "
220 attr
->config_methods
= pos
;
222 case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS
:
224 wpa_printf(MSG_DEBUG
, "WPS: Invalid Selected "
225 "Registrar Config Methods length %u", len
);
228 attr
->sel_reg_config_methods
= pos
;
230 case ATTR_PRIMARY_DEV_TYPE
:
231 if (len
!= WPS_DEV_TYPE_LEN
) {
232 wpa_printf(MSG_DEBUG
, "WPS: Invalid Primary Device "
233 "Type length %u", len
);
236 attr
->primary_dev_type
= pos
;
240 wpa_printf(MSG_DEBUG
, "WPS: Invalid RF Bands length "
244 attr
->rf_bands
= pos
;
246 case ATTR_ASSOC_STATE
:
248 wpa_printf(MSG_DEBUG
, "WPS: Invalid Association State "
252 attr
->assoc_state
= pos
;
254 case ATTR_CONFIG_ERROR
:
256 wpa_printf(MSG_DEBUG
, "WPS: Invalid Configuration "
257 "Error length %u", len
);
260 attr
->config_error
= pos
;
262 case ATTR_DEV_PASSWORD_ID
:
264 wpa_printf(MSG_DEBUG
, "WPS: Invalid Device Password "
265 "ID length %u", len
);
268 attr
->dev_password_id
= pos
;
270 case ATTR_OOB_DEVICE_PASSWORD
:
271 if (len
!= WPS_OOB_DEVICE_PASSWORD_ATTR_LEN
) {
272 wpa_printf(MSG_DEBUG
, "WPS: Invalid OOB Device "
273 "Password length %u", len
);
276 attr
->oob_dev_password
= pos
;
278 case ATTR_OS_VERSION
:
280 wpa_printf(MSG_DEBUG
, "WPS: Invalid OS Version length "
284 attr
->os_version
= pos
;
288 wpa_printf(MSG_DEBUG
, "WPS: Invalid Wi-Fi Protected "
289 "Setup State length %u", len
);
292 attr
->wps_state
= pos
;
294 case ATTR_AUTHENTICATOR
:
295 if (len
!= WPS_AUTHENTICATOR_LEN
) {
296 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authenticator "
300 attr
->authenticator
= pos
;
303 if (len
!= WPS_HASH_LEN
) {
304 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-Hash1 length %u",
311 if (len
!= WPS_HASH_LEN
) {
312 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-Hash2 length %u",
319 if (len
!= WPS_HASH_LEN
) {
320 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-Hash1 length %u",
327 if (len
!= WPS_HASH_LEN
) {
328 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-Hash2 length %u",
335 if (len
!= WPS_SECRET_NONCE_LEN
) {
336 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-SNonce1 length "
340 attr
->r_snonce1
= pos
;
343 if (len
!= WPS_SECRET_NONCE_LEN
) {
344 wpa_printf(MSG_DEBUG
, "WPS: Invalid R-SNonce2 length "
348 attr
->r_snonce2
= pos
;
351 if (len
!= WPS_SECRET_NONCE_LEN
) {
352 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-SNonce1 length "
356 attr
->e_snonce1
= pos
;
359 if (len
!= WPS_SECRET_NONCE_LEN
) {
360 wpa_printf(MSG_DEBUG
, "WPS: Invalid E-SNonce2 length "
364 attr
->e_snonce2
= pos
;
366 case ATTR_KEY_WRAP_AUTH
:
367 if (len
!= WPS_KWA_LEN
) {
368 wpa_printf(MSG_DEBUG
, "WPS: Invalid Key Wrap "
369 "Authenticator length %u", len
);
372 attr
->key_wrap_auth
= pos
;
376 wpa_printf(MSG_DEBUG
, "WPS: Invalid Authentication "
377 "Type length %u", len
);
380 attr
->auth_type
= pos
;
384 wpa_printf(MSG_DEBUG
, "WPS: Invalid Encryption "
385 "Type length %u", len
);
388 attr
->encr_type
= pos
;
390 case ATTR_NETWORK_INDEX
:
392 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Index "
396 attr
->network_idx
= pos
;
398 case ATTR_NETWORK_KEY_INDEX
:
400 wpa_printf(MSG_DEBUG
, "WPS: Invalid Network Key Index "
404 attr
->network_key_idx
= pos
;
407 if (len
!= ETH_ALEN
) {
408 wpa_printf(MSG_DEBUG
, "WPS: Invalid MAC Address "
412 attr
->mac_addr
= pos
;
414 case ATTR_KEY_PROVIDED_AUTO
:
416 wpa_printf(MSG_DEBUG
, "WPS: Invalid Key Provided "
417 "Automatically length %u", len
);
420 attr
->key_prov_auto
= pos
;
422 case ATTR_802_1X_ENABLED
:
424 wpa_printf(MSG_DEBUG
, "WPS: Invalid 802.1X Enabled "
428 attr
->dot1x_enabled
= pos
;
430 case ATTR_SELECTED_REGISTRAR
:
432 wpa_printf(MSG_DEBUG
, "WPS: Invalid Selected Registrar"
436 attr
->selected_registrar
= pos
;
438 case ATTR_REQUEST_TYPE
:
440 wpa_printf(MSG_DEBUG
, "WPS: Invalid Request Type "
444 attr
->request_type
= pos
;
446 case ATTR_RESPONSE_TYPE
:
448 wpa_printf(MSG_DEBUG
, "WPS: Invalid Response Type "
452 attr
->response_type
= pos
;
454 case ATTR_MANUFACTURER
:
455 attr
->manufacturer
= pos
;
456 attr
->manufacturer_len
= len
;
458 case ATTR_MODEL_NAME
:
459 attr
->model_name
= pos
;
460 attr
->model_name_len
= len
;
462 case ATTR_MODEL_NUMBER
:
463 attr
->model_number
= pos
;
464 attr
->model_number_len
= len
;
466 case ATTR_SERIAL_NUMBER
:
467 attr
->serial_number
= pos
;
468 attr
->serial_number_len
= len
;
471 attr
->dev_name
= pos
;
472 attr
->dev_name_len
= len
;
474 case ATTR_PUBLIC_KEY
:
475 attr
->public_key
= pos
;
476 attr
->public_key_len
= len
;
478 case ATTR_ENCR_SETTINGS
:
479 attr
->encr_settings
= pos
;
480 attr
->encr_settings_len
= len
;
483 if (attr
->num_cred
>= MAX_CRED_COUNT
) {
484 wpa_printf(MSG_DEBUG
, "WPS: Skipped Credential "
485 "attribute (max %d credentials)",
489 attr
->cred
[attr
->num_cred
] = pos
;
490 attr
->cred_len
[attr
->num_cred
] = len
;
495 attr
->ssid_len
= len
;
497 case ATTR_NETWORK_KEY
:
498 attr
->network_key
= pos
;
499 attr
->network_key_len
= len
;
502 attr
->eap_type
= pos
;
503 attr
->eap_type_len
= len
;
505 case ATTR_EAP_IDENTITY
:
506 attr
->eap_identity
= pos
;
507 attr
->eap_identity_len
= len
;
509 case ATTR_AP_SETUP_LOCKED
:
511 wpa_printf(MSG_DEBUG
, "WPS: Invalid AP Setup Locked "
515 attr
->ap_setup_locked
= pos
;
517 case ATTR_REQUESTED_DEV_TYPE
:
518 if (len
!= WPS_DEV_TYPE_LEN
) {
519 wpa_printf(MSG_DEBUG
, "WPS: Invalid Requested Device "
520 "Type length %u", len
);
523 if (attr
->num_req_dev_type
>= MAX_REQ_DEV_TYPE_COUNT
) {
524 wpa_printf(MSG_DEBUG
, "WPS: Skipped Requested Device "
525 "Type attribute (max %u types)",
526 MAX_REQ_DEV_TYPE_COUNT
);
529 attr
->req_dev_type
[attr
->num_req_dev_type
] = pos
;
530 attr
->num_req_dev_type
++;
532 case ATTR_SECONDARY_DEV_TYPE_LIST
:
533 if (len
> WPS_SEC_DEV_TYPE_MAX_LEN
||
534 (len
% WPS_DEV_TYPE_LEN
) > 0) {
535 wpa_printf(MSG_DEBUG
, "WPS: Invalid Secondary Device "
536 "Type length %u", len
);
539 attr
->sec_dev_type_list
= pos
;
540 attr
->sec_dev_type_list_len
= len
;
542 case ATTR_VENDOR_EXT
:
543 if (wps_parse_vendor_ext(attr
, pos
, len
) < 0)
547 wpa_printf(MSG_DEBUG
, "WPS: Unsupported attribute type 0x%x "
548 "len=%u", type
, len
);
556 int wps_parse_msg(const struct wpabuf
*msg
, struct wps_parse_attr
*attr
)
560 #ifdef WPS_WORKAROUNDS
562 #endif /* WPS_WORKAROUNDS */
564 os_memset(attr
, 0, sizeof(*attr
));
565 pos
= wpabuf_head(msg
);
566 end
= pos
+ wpabuf_len(msg
);
570 wpa_printf(MSG_DEBUG
, "WPS: Invalid message - "
571 "%lu bytes remaining",
572 (unsigned long) (end
- pos
));
576 type
= WPA_GET_BE16(pos
);
578 len
= WPA_GET_BE16(pos
);
580 wpa_printf(MSG_EXCESSIVE
, "WPS: attr type=0x%x len=%u",
582 if (len
> end
- pos
) {
583 wpa_printf(MSG_DEBUG
, "WPS: Attribute overflow");
584 wpa_hexdump_buf(MSG_MSGDUMP
, "WPS: Message data", msg
);
585 #ifdef WPS_WORKAROUNDS
587 * Some deployed APs seem to have a bug in encoding of
588 * Network Key attribute in the Credential attribute
589 * where they add an extra octet after the Network Key
590 * attribute at least when open network is being
593 if ((type
& 0xff00) != 0x1000 &&
594 prev_type
== ATTR_NETWORK_KEY
) {
595 wpa_printf(MSG_DEBUG
, "WPS: Workaround - try "
596 "to skip unexpected octet after "
601 #endif /* WPS_WORKAROUNDS */
605 #ifdef WPS_WORKAROUNDS
606 if (type
== 0 && len
== 0) {
608 * Mac OS X 10.6 seems to be adding 0x00 padding to the
609 * end of M1. Skip those to avoid interop issues.
612 for (i
= 0; i
< end
- pos
; i
++) {
616 if (i
== end
- pos
) {
617 wpa_printf(MSG_DEBUG
, "WPS: Workaround - skip "
618 "unexpected message padding");
622 #endif /* WPS_WORKAROUNDS */
624 if (wps_set_attr(attr
, type
, pos
, len
) < 0)
627 #ifdef WPS_WORKAROUNDS
629 #endif /* WPS_WORKAROUNDS */