xref: /freebsd/contrib/wpa/src/wps/wps_attr_parse.c (revision e28a4053b110e06768631ac8401ed4a3c05e68a5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Wi-Fi Protected Setup - attribute parsing
339beb93cSSam Leffler  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #include "common.h"
1839beb93cSSam Leffler #include "wps_i.h"
1939beb93cSSam Leffler 
20*e28a4053SRui Paulo #define WPS_WORKAROUNDS
21*e28a4053SRui Paulo 
2239beb93cSSam Leffler 
2339beb93cSSam Leffler static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
2439beb93cSSam Leffler 			const u8 *pos, u16 len)
2539beb93cSSam Leffler {
2639beb93cSSam Leffler 	switch (type) {
2739beb93cSSam Leffler 	case ATTR_VERSION:
2839beb93cSSam Leffler 		if (len != 1) {
2939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
3039beb93cSSam Leffler 				   len);
3139beb93cSSam Leffler 			return -1;
3239beb93cSSam Leffler 		}
3339beb93cSSam Leffler 		attr->version = pos;
3439beb93cSSam Leffler 		break;
3539beb93cSSam Leffler 	case ATTR_MSG_TYPE:
3639beb93cSSam Leffler 		if (len != 1) {
3739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
3839beb93cSSam Leffler 				   "length %u", len);
3939beb93cSSam Leffler 			return -1;
4039beb93cSSam Leffler 		}
4139beb93cSSam Leffler 		attr->msg_type = pos;
4239beb93cSSam Leffler 		break;
4339beb93cSSam Leffler 	case ATTR_ENROLLEE_NONCE:
4439beb93cSSam Leffler 		if (len != WPS_NONCE_LEN) {
4539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
4639beb93cSSam Leffler 				   "length %u", len);
4739beb93cSSam Leffler 			return -1;
4839beb93cSSam Leffler 		}
4939beb93cSSam Leffler 		attr->enrollee_nonce = pos;
5039beb93cSSam Leffler 		break;
5139beb93cSSam Leffler 	case ATTR_REGISTRAR_NONCE:
5239beb93cSSam Leffler 		if (len != WPS_NONCE_LEN) {
5339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
5439beb93cSSam Leffler 				   "length %u", len);
5539beb93cSSam Leffler 			return -1;
5639beb93cSSam Leffler 		}
5739beb93cSSam Leffler 		attr->registrar_nonce = pos;
5839beb93cSSam Leffler 		break;
5939beb93cSSam Leffler 	case ATTR_UUID_E:
6039beb93cSSam Leffler 		if (len != WPS_UUID_LEN) {
6139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
6239beb93cSSam Leffler 				   len);
6339beb93cSSam Leffler 			return -1;
6439beb93cSSam Leffler 		}
6539beb93cSSam Leffler 		attr->uuid_e = pos;
6639beb93cSSam Leffler 		break;
6739beb93cSSam Leffler 	case ATTR_UUID_R:
6839beb93cSSam Leffler 		if (len != WPS_UUID_LEN) {
6939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
7039beb93cSSam Leffler 				   len);
7139beb93cSSam Leffler 			return -1;
7239beb93cSSam Leffler 		}
7339beb93cSSam Leffler 		attr->uuid_r = pos;
7439beb93cSSam Leffler 		break;
7539beb93cSSam Leffler 	case ATTR_AUTH_TYPE_FLAGS:
7639beb93cSSam Leffler 		if (len != 2) {
7739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
7839beb93cSSam Leffler 				   "Type Flags length %u", len);
7939beb93cSSam Leffler 			return -1;
8039beb93cSSam Leffler 		}
8139beb93cSSam Leffler 		attr->auth_type_flags = pos;
8239beb93cSSam Leffler 		break;
8339beb93cSSam Leffler 	case ATTR_ENCR_TYPE_FLAGS:
8439beb93cSSam Leffler 		if (len != 2) {
8539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
8639beb93cSSam Leffler 				   "Flags length %u", len);
8739beb93cSSam Leffler 			return -1;
8839beb93cSSam Leffler 		}
8939beb93cSSam Leffler 		attr->encr_type_flags = pos;
9039beb93cSSam Leffler 		break;
9139beb93cSSam Leffler 	case ATTR_CONN_TYPE_FLAGS:
9239beb93cSSam Leffler 		if (len != 1) {
9339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
9439beb93cSSam Leffler 				   "Flags length %u", len);
9539beb93cSSam Leffler 			return -1;
9639beb93cSSam Leffler 		}
9739beb93cSSam Leffler 		attr->conn_type_flags = pos;
9839beb93cSSam Leffler 		break;
9939beb93cSSam Leffler 	case ATTR_CONFIG_METHODS:
10039beb93cSSam Leffler 		if (len != 2) {
10139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
10239beb93cSSam Leffler 				   "length %u", len);
10339beb93cSSam Leffler 			return -1;
10439beb93cSSam Leffler 		}
10539beb93cSSam Leffler 		attr->config_methods = pos;
10639beb93cSSam Leffler 		break;
10739beb93cSSam Leffler 	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
10839beb93cSSam Leffler 		if (len != 2) {
10939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
11039beb93cSSam Leffler 				   "Registrar Config Methods length %u", len);
11139beb93cSSam Leffler 			return -1;
11239beb93cSSam Leffler 		}
11339beb93cSSam Leffler 		attr->sel_reg_config_methods = pos;
11439beb93cSSam Leffler 		break;
11539beb93cSSam Leffler 	case ATTR_PRIMARY_DEV_TYPE:
116*e28a4053SRui Paulo 		if (len != WPS_DEV_TYPE_LEN) {
11739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
11839beb93cSSam Leffler 				   "Type length %u", len);
11939beb93cSSam Leffler 			return -1;
12039beb93cSSam Leffler 		}
12139beb93cSSam Leffler 		attr->primary_dev_type = pos;
12239beb93cSSam Leffler 		break;
12339beb93cSSam Leffler 	case ATTR_RF_BANDS:
12439beb93cSSam Leffler 		if (len != 1) {
12539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
12639beb93cSSam Leffler 				   "%u", len);
12739beb93cSSam Leffler 			return -1;
12839beb93cSSam Leffler 		}
12939beb93cSSam Leffler 		attr->rf_bands = pos;
13039beb93cSSam Leffler 		break;
13139beb93cSSam Leffler 	case ATTR_ASSOC_STATE:
13239beb93cSSam Leffler 		if (len != 2) {
13339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
13439beb93cSSam Leffler 				   "length %u", len);
13539beb93cSSam Leffler 			return -1;
13639beb93cSSam Leffler 		}
13739beb93cSSam Leffler 		attr->assoc_state = pos;
13839beb93cSSam Leffler 		break;
13939beb93cSSam Leffler 	case ATTR_CONFIG_ERROR:
14039beb93cSSam Leffler 		if (len != 2) {
14139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
14239beb93cSSam Leffler 				   "Error length %u", len);
14339beb93cSSam Leffler 			return -1;
14439beb93cSSam Leffler 		}
14539beb93cSSam Leffler 		attr->config_error = pos;
14639beb93cSSam Leffler 		break;
14739beb93cSSam Leffler 	case ATTR_DEV_PASSWORD_ID:
14839beb93cSSam Leffler 		if (len != 2) {
14939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
15039beb93cSSam Leffler 				   "ID length %u", len);
15139beb93cSSam Leffler 			return -1;
15239beb93cSSam Leffler 		}
15339beb93cSSam Leffler 		attr->dev_password_id = pos;
15439beb93cSSam Leffler 		break;
155*e28a4053SRui Paulo 	case ATTR_OOB_DEVICE_PASSWORD:
156*e28a4053SRui Paulo 		if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) {
157*e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
158*e28a4053SRui Paulo 				   "Password length %u", len);
159*e28a4053SRui Paulo 			return -1;
160*e28a4053SRui Paulo 		}
161*e28a4053SRui Paulo 		attr->oob_dev_password = pos;
162*e28a4053SRui Paulo 		break;
16339beb93cSSam Leffler 	case ATTR_OS_VERSION:
16439beb93cSSam Leffler 		if (len != 4) {
16539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
16639beb93cSSam Leffler 				   "%u", len);
16739beb93cSSam Leffler 			return -1;
16839beb93cSSam Leffler 		}
16939beb93cSSam Leffler 		attr->os_version = pos;
17039beb93cSSam Leffler 		break;
17139beb93cSSam Leffler 	case ATTR_WPS_STATE:
17239beb93cSSam Leffler 		if (len != 1) {
17339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
17439beb93cSSam Leffler 				   "Setup State length %u", len);
17539beb93cSSam Leffler 			return -1;
17639beb93cSSam Leffler 		}
17739beb93cSSam Leffler 		attr->wps_state = pos;
17839beb93cSSam Leffler 		break;
17939beb93cSSam Leffler 	case ATTR_AUTHENTICATOR:
18039beb93cSSam Leffler 		if (len != WPS_AUTHENTICATOR_LEN) {
18139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
18239beb93cSSam Leffler 				   "length %u", len);
18339beb93cSSam Leffler 			return -1;
18439beb93cSSam Leffler 		}
18539beb93cSSam Leffler 		attr->authenticator = pos;
18639beb93cSSam Leffler 		break;
18739beb93cSSam Leffler 	case ATTR_R_HASH1:
18839beb93cSSam Leffler 		if (len != WPS_HASH_LEN) {
18939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
19039beb93cSSam Leffler 				   len);
19139beb93cSSam Leffler 			return -1;
19239beb93cSSam Leffler 		}
19339beb93cSSam Leffler 		attr->r_hash1 = pos;
19439beb93cSSam Leffler 		break;
19539beb93cSSam Leffler 	case ATTR_R_HASH2:
19639beb93cSSam Leffler 		if (len != WPS_HASH_LEN) {
19739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
19839beb93cSSam Leffler 				   len);
19939beb93cSSam Leffler 			return -1;
20039beb93cSSam Leffler 		}
20139beb93cSSam Leffler 		attr->r_hash2 = pos;
20239beb93cSSam Leffler 		break;
20339beb93cSSam Leffler 	case ATTR_E_HASH1:
20439beb93cSSam Leffler 		if (len != WPS_HASH_LEN) {
20539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
20639beb93cSSam Leffler 				   len);
20739beb93cSSam Leffler 			return -1;
20839beb93cSSam Leffler 		}
20939beb93cSSam Leffler 		attr->e_hash1 = pos;
21039beb93cSSam Leffler 		break;
21139beb93cSSam Leffler 	case ATTR_E_HASH2:
21239beb93cSSam Leffler 		if (len != WPS_HASH_LEN) {
21339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
21439beb93cSSam Leffler 				   len);
21539beb93cSSam Leffler 			return -1;
21639beb93cSSam Leffler 		}
21739beb93cSSam Leffler 		attr->e_hash2 = pos;
21839beb93cSSam Leffler 		break;
21939beb93cSSam Leffler 	case ATTR_R_SNONCE1:
22039beb93cSSam Leffler 		if (len != WPS_SECRET_NONCE_LEN) {
22139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
22239beb93cSSam Leffler 				   "%u", len);
22339beb93cSSam Leffler 			return -1;
22439beb93cSSam Leffler 		}
22539beb93cSSam Leffler 		attr->r_snonce1 = pos;
22639beb93cSSam Leffler 		break;
22739beb93cSSam Leffler 	case ATTR_R_SNONCE2:
22839beb93cSSam Leffler 		if (len != WPS_SECRET_NONCE_LEN) {
22939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
23039beb93cSSam Leffler 				   "%u", len);
23139beb93cSSam Leffler 			return -1;
23239beb93cSSam Leffler 		}
23339beb93cSSam Leffler 		attr->r_snonce2 = pos;
23439beb93cSSam Leffler 		break;
23539beb93cSSam Leffler 	case ATTR_E_SNONCE1:
23639beb93cSSam Leffler 		if (len != WPS_SECRET_NONCE_LEN) {
23739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
23839beb93cSSam Leffler 				   "%u", len);
23939beb93cSSam Leffler 			return -1;
24039beb93cSSam Leffler 		}
24139beb93cSSam Leffler 		attr->e_snonce1 = pos;
24239beb93cSSam Leffler 		break;
24339beb93cSSam Leffler 	case ATTR_E_SNONCE2:
24439beb93cSSam Leffler 		if (len != WPS_SECRET_NONCE_LEN) {
24539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
24639beb93cSSam Leffler 				   "%u", len);
24739beb93cSSam Leffler 			return -1;
24839beb93cSSam Leffler 		}
24939beb93cSSam Leffler 		attr->e_snonce2 = pos;
25039beb93cSSam Leffler 		break;
25139beb93cSSam Leffler 	case ATTR_KEY_WRAP_AUTH:
25239beb93cSSam Leffler 		if (len != WPS_KWA_LEN) {
25339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
25439beb93cSSam Leffler 				   "Authenticator length %u", len);
25539beb93cSSam Leffler 			return -1;
25639beb93cSSam Leffler 		}
25739beb93cSSam Leffler 		attr->key_wrap_auth = pos;
25839beb93cSSam Leffler 		break;
25939beb93cSSam Leffler 	case ATTR_AUTH_TYPE:
26039beb93cSSam Leffler 		if (len != 2) {
26139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
26239beb93cSSam Leffler 				   "Type length %u", len);
26339beb93cSSam Leffler 			return -1;
26439beb93cSSam Leffler 		}
26539beb93cSSam Leffler 		attr->auth_type = pos;
26639beb93cSSam Leffler 		break;
26739beb93cSSam Leffler 	case ATTR_ENCR_TYPE:
26839beb93cSSam Leffler 		if (len != 2) {
26939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
27039beb93cSSam Leffler 				   "Type length %u", len);
27139beb93cSSam Leffler 			return -1;
27239beb93cSSam Leffler 		}
27339beb93cSSam Leffler 		attr->encr_type = pos;
27439beb93cSSam Leffler 		break;
27539beb93cSSam Leffler 	case ATTR_NETWORK_INDEX:
27639beb93cSSam Leffler 		if (len != 1) {
27739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
27839beb93cSSam Leffler 				   "length %u", len);
27939beb93cSSam Leffler 			return -1;
28039beb93cSSam Leffler 		}
28139beb93cSSam Leffler 		attr->network_idx = pos;
28239beb93cSSam Leffler 		break;
28339beb93cSSam Leffler 	case ATTR_NETWORK_KEY_INDEX:
28439beb93cSSam Leffler 		if (len != 1) {
28539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
28639beb93cSSam Leffler 				   "length %u", len);
28739beb93cSSam Leffler 			return -1;
28839beb93cSSam Leffler 		}
28939beb93cSSam Leffler 		attr->network_key_idx = pos;
29039beb93cSSam Leffler 		break;
29139beb93cSSam Leffler 	case ATTR_MAC_ADDR:
29239beb93cSSam Leffler 		if (len != ETH_ALEN) {
29339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
29439beb93cSSam Leffler 				   "length %u", len);
29539beb93cSSam Leffler 			return -1;
29639beb93cSSam Leffler 		}
29739beb93cSSam Leffler 		attr->mac_addr = pos;
29839beb93cSSam Leffler 		break;
29939beb93cSSam Leffler 	case ATTR_KEY_PROVIDED_AUTO:
30039beb93cSSam Leffler 		if (len != 1) {
30139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
30239beb93cSSam Leffler 				   "Automatically length %u", len);
30339beb93cSSam Leffler 			return -1;
30439beb93cSSam Leffler 		}
30539beb93cSSam Leffler 		attr->key_prov_auto = pos;
30639beb93cSSam Leffler 		break;
30739beb93cSSam Leffler 	case ATTR_802_1X_ENABLED:
30839beb93cSSam Leffler 		if (len != 1) {
30939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
31039beb93cSSam Leffler 				   "length %u", len);
31139beb93cSSam Leffler 			return -1;
31239beb93cSSam Leffler 		}
31339beb93cSSam Leffler 		attr->dot1x_enabled = pos;
31439beb93cSSam Leffler 		break;
31539beb93cSSam Leffler 	case ATTR_SELECTED_REGISTRAR:
31639beb93cSSam Leffler 		if (len != 1) {
31739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
31839beb93cSSam Leffler 				   " length %u", len);
31939beb93cSSam Leffler 			return -1;
32039beb93cSSam Leffler 		}
32139beb93cSSam Leffler 		attr->selected_registrar = pos;
32239beb93cSSam Leffler 		break;
32339beb93cSSam Leffler 	case ATTR_REQUEST_TYPE:
32439beb93cSSam Leffler 		if (len != 1) {
32539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
32639beb93cSSam Leffler 				   "length %u", len);
32739beb93cSSam Leffler 			return -1;
32839beb93cSSam Leffler 		}
32939beb93cSSam Leffler 		attr->request_type = pos;
33039beb93cSSam Leffler 		break;
33139beb93cSSam Leffler 	case ATTR_RESPONSE_TYPE:
33239beb93cSSam Leffler 		if (len != 1) {
33339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
33439beb93cSSam Leffler 				   "length %u", len);
33539beb93cSSam Leffler 			return -1;
33639beb93cSSam Leffler 		}
337*e28a4053SRui Paulo 		attr->response_type = pos;
33839beb93cSSam Leffler 		break;
33939beb93cSSam Leffler 	case ATTR_MANUFACTURER:
34039beb93cSSam Leffler 		attr->manufacturer = pos;
34139beb93cSSam Leffler 		attr->manufacturer_len = len;
34239beb93cSSam Leffler 		break;
34339beb93cSSam Leffler 	case ATTR_MODEL_NAME:
34439beb93cSSam Leffler 		attr->model_name = pos;
34539beb93cSSam Leffler 		attr->model_name_len = len;
34639beb93cSSam Leffler 		break;
34739beb93cSSam Leffler 	case ATTR_MODEL_NUMBER:
34839beb93cSSam Leffler 		attr->model_number = pos;
34939beb93cSSam Leffler 		attr->model_number_len = len;
35039beb93cSSam Leffler 		break;
35139beb93cSSam Leffler 	case ATTR_SERIAL_NUMBER:
35239beb93cSSam Leffler 		attr->serial_number = pos;
35339beb93cSSam Leffler 		attr->serial_number_len = len;
35439beb93cSSam Leffler 		break;
35539beb93cSSam Leffler 	case ATTR_DEV_NAME:
35639beb93cSSam Leffler 		attr->dev_name = pos;
35739beb93cSSam Leffler 		attr->dev_name_len = len;
35839beb93cSSam Leffler 		break;
35939beb93cSSam Leffler 	case ATTR_PUBLIC_KEY:
36039beb93cSSam Leffler 		attr->public_key = pos;
36139beb93cSSam Leffler 		attr->public_key_len = len;
36239beb93cSSam Leffler 		break;
36339beb93cSSam Leffler 	case ATTR_ENCR_SETTINGS:
36439beb93cSSam Leffler 		attr->encr_settings = pos;
36539beb93cSSam Leffler 		attr->encr_settings_len = len;
36639beb93cSSam Leffler 		break;
36739beb93cSSam Leffler 	case ATTR_CRED:
36839beb93cSSam Leffler 		if (attr->num_cred >= MAX_CRED_COUNT) {
36939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
37039beb93cSSam Leffler 				   "attribute (max %d credentials)",
37139beb93cSSam Leffler 				   MAX_CRED_COUNT);
37239beb93cSSam Leffler 			break;
37339beb93cSSam Leffler 		}
37439beb93cSSam Leffler 		attr->cred[attr->num_cred] = pos;
37539beb93cSSam Leffler 		attr->cred_len[attr->num_cred] = len;
37639beb93cSSam Leffler 		attr->num_cred++;
37739beb93cSSam Leffler 		break;
37839beb93cSSam Leffler 	case ATTR_SSID:
37939beb93cSSam Leffler 		attr->ssid = pos;
38039beb93cSSam Leffler 		attr->ssid_len = len;
38139beb93cSSam Leffler 		break;
38239beb93cSSam Leffler 	case ATTR_NETWORK_KEY:
38339beb93cSSam Leffler 		attr->network_key = pos;
38439beb93cSSam Leffler 		attr->network_key_len = len;
38539beb93cSSam Leffler 		break;
38639beb93cSSam Leffler 	case ATTR_EAP_TYPE:
38739beb93cSSam Leffler 		attr->eap_type = pos;
38839beb93cSSam Leffler 		attr->eap_type_len = len;
38939beb93cSSam Leffler 		break;
39039beb93cSSam Leffler 	case ATTR_EAP_IDENTITY:
39139beb93cSSam Leffler 		attr->eap_identity = pos;
39239beb93cSSam Leffler 		attr->eap_identity_len = len;
39339beb93cSSam Leffler 		break;
3943157ba21SRui Paulo 	case ATTR_AP_SETUP_LOCKED:
3953157ba21SRui Paulo 		if (len != 1) {
3963157ba21SRui Paulo 			wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
3973157ba21SRui Paulo 				   "length %u", len);
3983157ba21SRui Paulo 			return -1;
3993157ba21SRui Paulo 		}
4003157ba21SRui Paulo 		attr->ap_setup_locked = pos;
4013157ba21SRui Paulo 		break;
40239beb93cSSam Leffler 	default:
40339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
40439beb93cSSam Leffler 			   "len=%u", type, len);
40539beb93cSSam Leffler 		break;
40639beb93cSSam Leffler 	}
40739beb93cSSam Leffler 
40839beb93cSSam Leffler 	return 0;
40939beb93cSSam Leffler }
41039beb93cSSam Leffler 
41139beb93cSSam Leffler 
41239beb93cSSam Leffler int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
41339beb93cSSam Leffler {
41439beb93cSSam Leffler 	const u8 *pos, *end;
41539beb93cSSam Leffler 	u16 type, len;
41639beb93cSSam Leffler 
41739beb93cSSam Leffler 	os_memset(attr, 0, sizeof(*attr));
41839beb93cSSam Leffler 	pos = wpabuf_head(msg);
41939beb93cSSam Leffler 	end = pos + wpabuf_len(msg);
42039beb93cSSam Leffler 
42139beb93cSSam Leffler 	while (pos < end) {
42239beb93cSSam Leffler 		if (end - pos < 4) {
42339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
42439beb93cSSam Leffler 				   "%lu bytes remaining",
42539beb93cSSam Leffler 				   (unsigned long) (end - pos));
42639beb93cSSam Leffler 			return -1;
42739beb93cSSam Leffler 		}
42839beb93cSSam Leffler 
42939beb93cSSam Leffler 		type = WPA_GET_BE16(pos);
43039beb93cSSam Leffler 		pos += 2;
43139beb93cSSam Leffler 		len = WPA_GET_BE16(pos);
43239beb93cSSam Leffler 		pos += 2;
43339beb93cSSam Leffler 		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
43439beb93cSSam Leffler 			   type, len);
43539beb93cSSam Leffler 		if (len > end - pos) {
43639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
43739beb93cSSam Leffler 			return -1;
43839beb93cSSam Leffler 		}
43939beb93cSSam Leffler 
440*e28a4053SRui Paulo #ifdef WPS_WORKAROUNDS
441*e28a4053SRui Paulo 		if (type == 0 && len == 0) {
442*e28a4053SRui Paulo 			/*
443*e28a4053SRui Paulo 			 * Mac OS X 10.6 seems to be adding 0x00 padding to the
444*e28a4053SRui Paulo 			 * end of M1. Skip those to avoid interop issues.
445*e28a4053SRui Paulo 			 */
446*e28a4053SRui Paulo 			int i;
447*e28a4053SRui Paulo 			for (i = 0; i < end - pos; i++) {
448*e28a4053SRui Paulo 				if (pos[i])
449*e28a4053SRui Paulo 					break;
450*e28a4053SRui Paulo 			}
451*e28a4053SRui Paulo 			if (i == end - pos) {
452*e28a4053SRui Paulo 				wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
453*e28a4053SRui Paulo 					   "unexpected message padding");
454*e28a4053SRui Paulo 				break;
455*e28a4053SRui Paulo 			}
456*e28a4053SRui Paulo 		}
457*e28a4053SRui Paulo #endif /* WPS_WORKAROUNDS */
458*e28a4053SRui Paulo 
45939beb93cSSam Leffler 		if (wps_set_attr(attr, type, pos, len) < 0)
46039beb93cSSam Leffler 			return -1;
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 		pos += len;
46339beb93cSSam Leffler 	}
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 	return 0;
46639beb93cSSam Leffler }
467