Browse Source

WPS: Split wps_common.c into parts

To make it easier to find various functions, attribute functions were
split into wps_attr_{build,parse,process}.c.
Jouni Malinen 16 years ago
parent
commit
7d7b8e960a
7 changed files with 1008 additions and 937 deletions
  1. 3 0
      hostapd/Makefile
  2. 253 0
      src/wps/wps_attr_build.c
  3. 429 0
      src/wps/wps_attr_parse.c
  4. 302 0
      src/wps/wps_attr_process.c
  5. 0 926
      src/wps/wps_common.c
  6. 18 11
      src/wps/wps_i.h
  7. 3 0
      wpa_supplicant/Makefile

+ 3 - 0
hostapd/Makefile

@@ -265,6 +265,9 @@ OBJS += wps_hostapd.o
 OBJS += ../src/eap_server/eap_wsc.o ../src/eap_common/eap_wsc_common.o
 OBJS += ../src/wps/wps.o
 OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
 OBJS += ../src/wps/wps_dev_attr.o
 OBJS += ../src/wps/wps_enrollee.o
 OBJS += ../src/wps/wps_registrar.o

+ 253 - 0
src/wps/wps_attr_build.c

@@ -0,0 +1,253 @@
+/*
+ * Wi-Fi Protected Setup - attribute building
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "dh_groups.h"
+#include "sha256.h"
+#include "aes_wrap.h"
+#include "wps_i.h"
+
+
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
+{
+	struct wpabuf *pubkey;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
+	pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey);
+	if (pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
+			   "Diffie-Hellman handshake");
+		return -1;
+	}
+
+	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
+	wpabuf_put_be16(msg, wpabuf_len(pubkey));
+	wpabuf_put_buf(msg, pubkey);
+
+	if (wps->registrar) {
+		wpabuf_free(wps->dh_pubkey_r);
+		wps->dh_pubkey_r = pubkey;
+	} else {
+		wpabuf_free(wps->dh_pubkey_e);
+		wps->dh_pubkey_e = pubkey;
+	}
+
+	return 0;
+}
+
+
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
+	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, type);
+	return 0;
+}
+
+
+int wps_build_config_methods(struct wpabuf *msg, u16 methods)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
+	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
+	wpabuf_put_be16(msg, ATTR_UUID_E);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
+	return 0;
+}
+
+
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, id);
+	return 0;
+}
+
+
+int wps_build_config_error(struct wpabuf *msg, u16 err)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
+	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, err);
+	return 0;
+}
+
+
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "building authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
+	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
+	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
+	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
+
+	return 0;
+}
+
+
+int wps_build_version(struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Version");
+	wpabuf_put_be16(msg, ATTR_VERSION);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_VERSION);
+	return 0;
+}
+
+
+int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
+	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, msg_type);
+	return 0;
+}
+
+
+int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
+	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
+	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_AUTH_TYPES);
+	return 0;
+}
+
+
+int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_ENCR_TYPES);
+	return 0;
+}
+
+
+int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
+	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_CONN_ESS);
+	return 0;
+}
+
+
+int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
+	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
+	return 0;
+}
+
+
+int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+		    wpabuf_len(msg), hash);
+
+	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
+	wpabuf_put_be16(msg, WPS_KWA_LEN);
+	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
+	return 0;
+}
+
+
+int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
+			    struct wpabuf *plain)
+{
+	size_t pad_len;
+	const size_t block_size = 16;
+	u8 *iv, *data;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
+
+	/* PKCS#5 v2.0 pad */
+	pad_len = block_size - wpabuf_len(plain) % block_size;
+	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
+
+	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
+	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
+
+	iv = wpabuf_put(msg, block_size);
+	if (os_get_random(iv, block_size) < 0)
+		return -1;
+
+	data = wpabuf_put(msg, 0);
+	wpabuf_put_buf(msg, plain);
+	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
+		return -1;
+
+	return 0;
+}

+ 429 - 0
src/wps/wps_attr_parse.c

@@ -0,0 +1,429 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wps_i.h"
+
+
+static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
+			const u8 *pos, u16 len)
+{
+	switch (type) {
+	case ATTR_VERSION:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
+				   len);
+			return -1;
+		}
+		attr->version = pos;
+		break;
+	case ATTR_MSG_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->msg_type = pos;
+		break;
+	case ATTR_ENROLLEE_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->enrollee_nonce = pos;
+		break;
+	case ATTR_REGISTRAR_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->registrar_nonce = pos;
+		break;
+	case ATTR_UUID_E:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_e = pos;
+		break;
+	case ATTR_UUID_R:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_r = pos;
+		break;
+	case ATTR_AUTH_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type Flags length %u", len);
+			return -1;
+		}
+		attr->auth_type_flags = pos;
+		break;
+	case ATTR_ENCR_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->encr_type_flags = pos;
+		break;
+	case ATTR_CONN_TYPE_FLAGS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->conn_type_flags = pos;
+		break;
+	case ATTR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
+				   "length %u", len);
+			return -1;
+		}
+		attr->config_methods = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
+				   "Registrar Config Methods length %u", len);
+			return -1;
+		}
+		attr->sel_reg_config_methods = pos;
+		break;
+	case ATTR_PRIMARY_DEV_TYPE:
+		if (len != sizeof(struct wps_dev_type)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->primary_dev_type = pos;
+		break;
+	case ATTR_RF_BANDS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
+				   "%u", len);
+			return -1;
+		}
+		attr->rf_bands = pos;
+		break;
+	case ATTR_ASSOC_STATE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
+				   "length %u", len);
+			return -1;
+		}
+		attr->assoc_state = pos;
+		break;
+	case ATTR_CONFIG_ERROR:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
+				   "Error length %u", len);
+			return -1;
+		}
+		attr->config_error = pos;
+		break;
+	case ATTR_DEV_PASSWORD_ID:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
+				   "ID length %u", len);
+			return -1;
+		}
+		attr->dev_password_id = pos;
+		break;
+	case ATTR_OS_VERSION:
+		if (len != 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
+				   "%u", len);
+			return -1;
+		}
+		attr->os_version = pos;
+		break;
+	case ATTR_WPS_STATE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
+				   "Setup State length %u", len);
+			return -1;
+		}
+		attr->wps_state = pos;
+		break;
+	case ATTR_AUTHENTICATOR:
+		if (len != WPS_AUTHENTICATOR_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
+				   "length %u", len);
+			return -1;
+		}
+		attr->authenticator = pos;
+		break;
+	case ATTR_R_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash1 = pos;
+		break;
+	case ATTR_R_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash2 = pos;
+		break;
+	case ATTR_E_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash1 = pos;
+		break;
+	case ATTR_E_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash2 = pos;
+		break;
+	case ATTR_R_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce1 = pos;
+		break;
+	case ATTR_R_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce2 = pos;
+		break;
+	case ATTR_E_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce1 = pos;
+		break;
+	case ATTR_E_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce2 = pos;
+		break;
+	case ATTR_KEY_WRAP_AUTH:
+		if (len != WPS_KWA_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
+				   "Authenticator length %u", len);
+			return -1;
+		}
+		attr->key_wrap_auth = pos;
+		break;
+	case ATTR_AUTH_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->auth_type = pos;
+		break;
+	case ATTR_ENCR_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->encr_type = pos;
+		break;
+	case ATTR_NETWORK_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_idx = pos;
+		break;
+	case ATTR_NETWORK_KEY_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_key_idx = pos;
+		break;
+	case ATTR_MAC_ADDR:
+		if (len != ETH_ALEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
+				   "length %u", len);
+			return -1;
+		}
+		attr->mac_addr = pos;
+		break;
+	case ATTR_KEY_PROVIDED_AUTO:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
+				   "Automatically length %u", len);
+			return -1;
+		}
+		attr->key_prov_auto = pos;
+		break;
+	case ATTR_802_1X_ENABLED:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
+				   "length %u", len);
+			return -1;
+		}
+		attr->dot1x_enabled = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
+				   " length %u", len);
+			return -1;
+		}
+		attr->selected_registrar = pos;
+		break;
+	case ATTR_REQUEST_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_type = pos;
+		break;
+	case ATTR_RESPONSE_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_type = pos;
+		break;
+	case ATTR_MANUFACTURER:
+		attr->manufacturer = pos;
+		attr->manufacturer_len = len;
+		break;
+	case ATTR_MODEL_NAME:
+		attr->model_name = pos;
+		attr->model_name_len = len;
+		break;
+	case ATTR_MODEL_NUMBER:
+		attr->model_number = pos;
+		attr->model_number_len = len;
+		break;
+	case ATTR_SERIAL_NUMBER:
+		attr->serial_number = pos;
+		attr->serial_number_len = len;
+		break;
+	case ATTR_DEV_NAME:
+		attr->dev_name = pos;
+		attr->dev_name_len = len;
+		break;
+	case ATTR_PUBLIC_KEY:
+		attr->public_key = pos;
+		attr->public_key_len = len;
+		break;
+	case ATTR_ENCR_SETTINGS:
+		attr->encr_settings = pos;
+		attr->encr_settings_len = len;
+		break;
+	case ATTR_CRED:
+		if (attr->num_cred >= MAX_CRED_COUNT) {
+			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
+				   "attribute (max %d credentials)",
+				   MAX_CRED_COUNT);
+			break;
+		}
+		attr->cred[attr->num_cred] = pos;
+		attr->cred_len[attr->num_cred] = len;
+		attr->num_cred++;
+		break;
+	case ATTR_SSID:
+		attr->ssid = pos;
+		attr->ssid_len = len;
+		break;
+	case ATTR_NETWORK_KEY:
+		attr->network_key = pos;
+		attr->network_key_len = len;
+		break;
+	case ATTR_EAP_TYPE:
+		attr->eap_type = pos;
+		attr->eap_type_len = len;
+		break;
+	case ATTR_EAP_IDENTITY:
+		attr->eap_identity = pos;
+		attr->eap_identity_len = len;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
+			   "len=%u", type, len);
+		break;
+	}
+
+	return 0;
+}
+
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
+{
+	const u8 *pos, *end;
+	u16 type, len;
+
+	os_memset(attr, 0, sizeof(*attr));
+	pos = wpabuf_head(msg);
+	end = pos + wpabuf_len(msg);
+
+	while (pos < end) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
+				   "%lu bytes remaining",
+				   (unsigned long) (end - pos));
+			return -1;
+		}
+
+		type = WPA_GET_BE16(pos);
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
+			   type, len);
+		if (len > end - pos) {
+			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
+			return -1;
+		}
+
+		if (wps_set_attr(attr, type, pos, len) < 0)
+			return -1;
+
+		pos += len;
+	}
+
+	return 0;
+}

+ 302 - 0
src/wps/wps_attr_process.c

@@ -0,0 +1,302 @@
+/*
+ * Wi-Fi Protected Setup - attribute processing
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "wps_i.h"
+
+
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (authenticator == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
+			   "included");
+		return -1;
+	}
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "validating authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *head;
+	size_t len;
+
+	if (key_wrap_auth == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
+		return -1;
+	}
+
+	head = wpabuf_head(msg);
+	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
+	if (head + len != key_wrap_auth - 4) {
+		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
+			   "decrypted attribute");
+		return -1;
+	}
+
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
+	if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_idx(struct wps_credential *cred,
+					const u8 *idx)
+{
+	if (idx == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Index");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
+
+	return 0;
+}
+
+
+static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
+				 size_t ssid_len)
+{
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
+		return -1;
+	}
+
+	/* Remove zero-padding since some Registrar implementations seem to use
+	 * hardcoded 32-octet length for this attribute */
+	while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
+		ssid_len--;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
+	if (ssid_len <= sizeof(cred->ssid)) {
+		os_memcpy(cred->ssid, ssid, ssid_len);
+		cred->ssid_len = ssid_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_auth_type(struct wps_credential *cred,
+				      const u8 *auth_type)
+{
+	if (auth_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Authentication Type");
+		return -1;
+	}
+
+	cred->auth_type = WPA_GET_BE16(auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
+		   cred->auth_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_encr_type(struct wps_credential *cred,
+				      const u8 *encr_type)
+{
+	if (encr_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Encryption Type");
+		return -1;
+	}
+
+	cred->encr_type = WPA_GET_BE16(encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
+		   cred->encr_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key_idx(struct wps_credential *cred,
+					    const u8 *key_idx)
+{
+	if (key_idx == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
+	cred->key_idx = *key_idx;
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key(struct wps_credential *cred,
+					const u8 *key, size_t key_len)
+{
+	if (key == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Key");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
+	if (key_len <= sizeof(cred->key)) {
+		os_memcpy(cred->key, key, key_len);
+		cred->key_len = key_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_mac_addr(struct wps_credential *cred,
+				     const u8 *mac_addr)
+{
+	if (mac_addr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "MAC Address");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
+	os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_type(struct wps_credential *cred,
+				     const u8 *eap_type, size_t eap_type_len)
+{
+	if (eap_type == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_identity(struct wps_credential *cred,
+					 const u8 *identity,
+					 size_t identity_len)
+{
+	if (identity == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
+			  identity, identity_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
+					  const u8 *key_prov_auto)
+{
+	if (key_prov_auto == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
+		   *key_prov_auto);
+
+	return 0;
+}
+
+
+static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
+					   const u8 *dot1x_enabled)
+{
+	if (dot1x_enabled == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
+
+	return 0;
+}
+
+
+int wps_process_cred(struct wps_parse_attr *attr,
+		     struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Process Credential");
+
+	/* TODO: support multiple Network Keys */
+	if (wps_process_cred_network_idx(cred, attr->network_idx) ||
+	    wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
+	    wps_process_cred_eap_type(cred, attr->eap_type,
+				      attr->eap_type_len) ||
+	    wps_process_cred_eap_identity(cred, attr->eap_identity,
+					  attr->eap_identity_len) ||
+	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
+	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
+		return -1;
+
+	return 0;
+}
+
+
+int wps_process_ap_settings(struct wps_parse_attr *attr,
+			    struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
+	os_memset(cred, 0, sizeof(*cred));
+	/* TODO: optional attributes New Password and Device Password ID */
+	if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr))
+		return -1;
+
+	return 0;
+}

+ 0 - 926
src/wps/wps_common.c

@@ -24,417 +24,6 @@
 #include "wps_dev_attr.h"
 
 
-static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
-			const u8 *pos, u16 len)
-{
-	switch (type) {
-	case ATTR_VERSION:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
-				   len);
-			return -1;
-		}
-		attr->version = pos;
-		break;
-	case ATTR_MSG_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->msg_type = pos;
-		break;
-	case ATTR_ENROLLEE_NONCE:
-		if (len != WPS_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
-				   "length %u", len);
-			return -1;
-		}
-		attr->enrollee_nonce = pos;
-		break;
-	case ATTR_REGISTRAR_NONCE:
-		if (len != WPS_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
-				   "length %u", len);
-			return -1;
-		}
-		attr->registrar_nonce = pos;
-		break;
-	case ATTR_UUID_E:
-		if (len != WPS_UUID_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
-				   len);
-			return -1;
-		}
-		attr->uuid_e = pos;
-		break;
-	case ATTR_UUID_R:
-		if (len != WPS_UUID_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
-				   len);
-			return -1;
-		}
-		attr->uuid_r = pos;
-		break;
-	case ATTR_AUTH_TYPE_FLAGS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
-				   "Type Flags length %u", len);
-			return -1;
-		}
-		attr->auth_type_flags = pos;
-		break;
-	case ATTR_ENCR_TYPE_FLAGS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
-				   "Flags length %u", len);
-			return -1;
-		}
-		attr->encr_type_flags = pos;
-		break;
-	case ATTR_CONN_TYPE_FLAGS:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
-				   "Flags length %u", len);
-			return -1;
-		}
-		attr->conn_type_flags = pos;
-		break;
-	case ATTR_CONFIG_METHODS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
-				   "length %u", len);
-			return -1;
-		}
-		attr->config_methods = pos;
-		break;
-	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
-				   "Registrar Config Methods length %u", len);
-			return -1;
-		}
-		attr->sel_reg_config_methods = pos;
-		break;
-	case ATTR_PRIMARY_DEV_TYPE:
-		if (len != sizeof(struct wps_dev_type)) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->primary_dev_type = pos;
-		break;
-	case ATTR_RF_BANDS:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
-				   "%u", len);
-			return -1;
-		}
-		attr->rf_bands = pos;
-		break;
-	case ATTR_ASSOC_STATE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
-				   "length %u", len);
-			return -1;
-		}
-		attr->assoc_state = pos;
-		break;
-	case ATTR_CONFIG_ERROR:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
-				   "Error length %u", len);
-			return -1;
-		}
-		attr->config_error = pos;
-		break;
-	case ATTR_DEV_PASSWORD_ID:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
-				   "ID length %u", len);
-			return -1;
-		}
-		attr->dev_password_id = pos;
-		break;
-	case ATTR_OS_VERSION:
-		if (len != 4) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
-				   "%u", len);
-			return -1;
-		}
-		attr->os_version = pos;
-		break;
-	case ATTR_WPS_STATE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
-				   "Setup State length %u", len);
-			return -1;
-		}
-		attr->wps_state = pos;
-		break;
-	case ATTR_AUTHENTICATOR:
-		if (len != WPS_AUTHENTICATOR_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
-				   "length %u", len);
-			return -1;
-		}
-		attr->authenticator = pos;
-		break;
-	case ATTR_R_HASH1:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
-				   len);
-			return -1;
-		}
-		attr->r_hash1 = pos;
-		break;
-	case ATTR_R_HASH2:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
-				   len);
-			return -1;
-		}
-		attr->r_hash2 = pos;
-		break;
-	case ATTR_E_HASH1:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
-				   len);
-			return -1;
-		}
-		attr->e_hash1 = pos;
-		break;
-	case ATTR_E_HASH2:
-		if (len != WPS_HASH_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
-				   len);
-			return -1;
-		}
-		attr->e_hash2 = pos;
-		break;
-	case ATTR_R_SNONCE1:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->r_snonce1 = pos;
-		break;
-	case ATTR_R_SNONCE2:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->r_snonce2 = pos;
-		break;
-	case ATTR_E_SNONCE1:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->e_snonce1 = pos;
-		break;
-	case ATTR_E_SNONCE2:
-		if (len != WPS_SECRET_NONCE_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
-				   "%u", len);
-			return -1;
-		}
-		attr->e_snonce2 = pos;
-		break;
-	case ATTR_KEY_WRAP_AUTH:
-		if (len != WPS_KWA_LEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
-				   "Authenticator length %u", len);
-			return -1;
-		}
-		attr->key_wrap_auth = pos;
-		break;
-	case ATTR_AUTH_TYPE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->auth_type = pos;
-		break;
-	case ATTR_ENCR_TYPE:
-		if (len != 2) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
-				   "Type length %u", len);
-			return -1;
-		}
-		attr->encr_type = pos;
-		break;
-	case ATTR_NETWORK_INDEX:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
-				   "length %u", len);
-			return -1;
-		}
-		attr->network_idx = pos;
-		break;
-	case ATTR_NETWORK_KEY_INDEX:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
-				   "length %u", len);
-			return -1;
-		}
-		attr->network_key_idx = pos;
-		break;
-	case ATTR_MAC_ADDR:
-		if (len != ETH_ALEN) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
-				   "length %u", len);
-			return -1;
-		}
-		attr->mac_addr = pos;
-		break;
-	case ATTR_KEY_PROVIDED_AUTO:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
-				   "Automatically length %u", len);
-			return -1;
-		}
-		attr->key_prov_auto = pos;
-		break;
-	case ATTR_802_1X_ENABLED:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
-				   "length %u", len);
-			return -1;
-		}
-		attr->dot1x_enabled = pos;
-		break;
-	case ATTR_SELECTED_REGISTRAR:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
-				   " length %u", len);
-			return -1;
-		}
-		attr->selected_registrar = pos;
-		break;
-	case ATTR_REQUEST_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->request_type = pos;
-		break;
-	case ATTR_RESPONSE_TYPE:
-		if (len != 1) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
-				   "length %u", len);
-			return -1;
-		}
-		attr->request_type = pos;
-		break;
-	case ATTR_MANUFACTURER:
-		attr->manufacturer = pos;
-		attr->manufacturer_len = len;
-		break;
-	case ATTR_MODEL_NAME:
-		attr->model_name = pos;
-		attr->model_name_len = len;
-		break;
-	case ATTR_MODEL_NUMBER:
-		attr->model_number = pos;
-		attr->model_number_len = len;
-		break;
-	case ATTR_SERIAL_NUMBER:
-		attr->serial_number = pos;
-		attr->serial_number_len = len;
-		break;
-	case ATTR_DEV_NAME:
-		attr->dev_name = pos;
-		attr->dev_name_len = len;
-		break;
-	case ATTR_PUBLIC_KEY:
-		attr->public_key = pos;
-		attr->public_key_len = len;
-		break;
-	case ATTR_ENCR_SETTINGS:
-		attr->encr_settings = pos;
-		attr->encr_settings_len = len;
-		break;
-	case ATTR_CRED:
-		if (attr->num_cred >= MAX_CRED_COUNT) {
-			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
-				   "attribute (max %d credentials)",
-				   MAX_CRED_COUNT);
-			break;
-		}
-		attr->cred[attr->num_cred] = pos;
-		attr->cred_len[attr->num_cred] = len;
-		attr->num_cred++;
-		break;
-	case ATTR_SSID:
-		attr->ssid = pos;
-		attr->ssid_len = len;
-		break;
-	case ATTR_NETWORK_KEY:
-		attr->network_key = pos;
-		attr->network_key_len = len;
-		break;
-	case ATTR_EAP_TYPE:
-		attr->eap_type = pos;
-		attr->eap_type_len = len;
-		break;
-	case ATTR_EAP_IDENTITY:
-		attr->eap_identity = pos;
-		attr->eap_identity_len = len;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
-			   "len=%u", type, len);
-		break;
-	}
-
-	return 0;
-}
-
-
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
-{
-	const u8 *pos, *end;
-	u16 type, len;
-
-	os_memset(attr, 0, sizeof(*attr));
-	pos = wpabuf_head(msg);
-	end = pos + wpabuf_len(msg);
-
-	while (pos < end) {
-		if (end - pos < 4) {
-			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
-				   "%lu bytes remaining",
-				   (unsigned long) (end - pos));
-			return -1;
-		}
-
-		type = WPA_GET_BE16(pos);
-		pos += 2;
-		len = WPA_GET_BE16(pos);
-		pos += 2;
-		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
-			   type, len);
-		if (len > end - pos) {
-			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
-			return -1;
-		}
-
-		if (wps_set_attr(attr, type, pos, len) < 0)
-			return -1;
-
-		pos += len;
-	}
-
-	return 0;
-}
-
-
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
 	     const char *label, u8 *res, size_t res_len)
 {
@@ -473,84 +62,6 @@ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
 }
 
 
-int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
-{
-	struct wpabuf *pubkey;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
-	pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey);
-	if (pubkey == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
-			   "Diffie-Hellman handshake");
-		return -1;
-	}
-
-	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
-	wpabuf_put_be16(msg, wpabuf_len(pubkey));
-	wpabuf_put_buf(msg, pubkey);
-
-	if (wps->registrar) {
-		wpabuf_free(wps->dh_pubkey_r);
-		wps->dh_pubkey_r = pubkey;
-	} else {
-		wpabuf_free(wps->dh_pubkey_e);
-		wps->dh_pubkey_e = pubkey;
-	}
-
-	return 0;
-}
-
-
-static int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
-	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, type);
-	return 0;
-}
-
-
-int wps_build_config_methods(struct wpabuf *msg, u16 methods)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
-	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, methods);
-	return 0;
-}
-
-
-int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
-	wpabuf_put_be16(msg, ATTR_UUID_E);
-	wpabuf_put_be16(msg, WPS_UUID_LEN);
-	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
-	return 0;
-}
-
-
-int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
-	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, id);
-	return 0;
-}
-
-
-int wps_build_config_error(struct wpabuf *msg, u16 err)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
-	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, err);
-	return 0;
-}
-
-
 struct wpabuf * wps_build_assoc_req_ie(void)
 {
 	struct wpabuf *ie;
@@ -737,73 +248,6 @@ int wps_derive_mgmt_keys(struct wps_data *wps)
 }
 
 
-int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	if (wps->last_msg == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
-			   "building authenticator");
-		return -1;
-	}
-
-	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
-	 * (M_curr* is M_curr without the Authenticator attribute)
-	 */
-	addr[0] = wpabuf_head(wps->last_msg);
-	len[0] = wpabuf_len(wps->last_msg);
-	addr[1] = wpabuf_head(msg);
-	len[1] = wpabuf_len(msg);
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
-	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
-	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
-	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
-
-	return 0;
-}
-
-
-int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
-			      const struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *addr[2];
-	size_t len[2];
-
-	if (authenticator == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
-			   "included");
-		return -1;
-	}
-
-	if (wps->last_msg == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
-			   "validating authenticator");
-		return -1;
-	}
-
-	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
-	 * (M_curr* is M_curr without the Authenticator attribute)
-	 */
-	addr[0] = wpabuf_head(wps->last_msg);
-	len[0] = wpabuf_len(wps->last_msg);
-	addr[1] = wpabuf_head(msg);
-	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
-	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
-
-	if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
-		return -1;
-	}
-
-	return 0;
-}
-
-
 void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
 		    size_t dev_passwd_len)
 {
@@ -874,373 +318,3 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
 
 	return decrypted;
 }
-
-
-int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
-			      const u8 *key_wrap_auth)
-{
-	u8 hash[SHA256_MAC_LEN];
-	const u8 *head;
-	size_t len;
-
-	if (key_wrap_auth == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
-		return -1;
-	}
-
-	head = wpabuf_head(msg);
-	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
-	if (head + len != key_wrap_auth - 4) {
-		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
-			   "decrypted attribute");
-		return -1;
-	}
-
-	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
-	if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-int wps_build_version(struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Version");
-	wpabuf_put_be16(msg, ATTR_VERSION);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, WPS_VERSION);
-	return 0;
-}
-
-
-int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
-	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, msg_type);
-	return 0;
-}
-
-
-int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
-	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
-	return 0;
-}
-
-
-int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
-	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
-	wpabuf_put_be16(msg, WPS_NONCE_LEN);
-	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
-	return 0;
-}
-
-
-int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
-	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_AUTH_TYPES);
-	return 0;
-}
-
-
-int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
-	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_ENCR_TYPES);
-	return 0;
-}
-
-
-int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
-	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
-	wpabuf_put_be16(msg, 1);
-	wpabuf_put_u8(msg, WPS_CONN_ESS);
-	return 0;
-}
-
-
-int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
-{
-	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
-	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
-	wpabuf_put_be16(msg, 2);
-	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
-	return 0;
-}
-
-
-int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
-{
-	u8 hash[SHA256_MAC_LEN];
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
-	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
-		    wpabuf_len(msg), hash);
-
-	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
-	wpabuf_put_be16(msg, WPS_KWA_LEN);
-	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
-	return 0;
-}
-
-
-int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
-			    struct wpabuf *plain)
-{
-	size_t pad_len;
-	const size_t block_size = 16;
-	u8 *iv, *data;
-
-	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
-
-	/* PKCS#5 v2.0 pad */
-	pad_len = block_size - wpabuf_len(plain) % block_size;
-	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
-
-	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
-	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
-
-	iv = wpabuf_put(msg, block_size);
-	if (os_get_random(iv, block_size) < 0)
-		return -1;
-
-	data = wpabuf_put(msg, 0);
-	wpabuf_put_buf(msg, plain);
-	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
-		return -1;
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_idx(struct wps_credential *cred,
-					const u8 *idx)
-{
-	if (idx == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Network Index");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
-
-	return 0;
-}
-
-
-static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
-				 size_t ssid_len)
-{
-	if (ssid == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
-		return -1;
-	}
-
-	/* Remove zero-padding since some Registrar implementations seem to use
-	 * hardcoded 32-octet length for this attribute */
-	while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
-		ssid_len--;
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
-	if (ssid_len <= sizeof(cred->ssid)) {
-		os_memcpy(cred->ssid, ssid, ssid_len);
-		cred->ssid_len = ssid_len;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_cred_auth_type(struct wps_credential *cred,
-				      const u8 *auth_type)
-{
-	if (auth_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Authentication Type");
-		return -1;
-	}
-
-	cred->auth_type = WPA_GET_BE16(auth_type);
-	wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
-		   cred->auth_type);
-
-	return 0;
-}
-
-
-static int wps_process_cred_encr_type(struct wps_credential *cred,
-				      const u8 *encr_type)
-{
-	if (encr_type == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Encryption Type");
-		return -1;
-	}
-
-	cred->encr_type = WPA_GET_BE16(encr_type);
-	wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
-		   cred->encr_type);
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_key_idx(struct wps_credential *cred,
-					    const u8 *key_idx)
-{
-	if (key_idx == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
-	cred->key_idx = *key_idx;
-
-	return 0;
-}
-
-
-static int wps_process_cred_network_key(struct wps_credential *cred,
-					const u8 *key, size_t key_len)
-{
-	if (key == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "Network Key");
-		return -1;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
-	if (key_len <= sizeof(cred->key)) {
-		os_memcpy(cred->key, key, key_len);
-		cred->key_len = key_len;
-	}
-
-	return 0;
-}
-
-
-static int wps_process_cred_mac_addr(struct wps_credential *cred,
-				     const u8 *mac_addr)
-{
-	if (mac_addr == NULL) {
-		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
-			   "MAC Address");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
-	os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
-
-	return 0;
-}
-
-
-static int wps_process_cred_eap_type(struct wps_credential *cred,
-				     const u8 *eap_type, size_t eap_type_len)
-{
-	if (eap_type == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_eap_identity(struct wps_credential *cred,
-					 const u8 *identity,
-					 size_t identity_len)
-{
-	if (identity == NULL)
-		return 0; /* optional attribute */
-
-	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
-			  identity, identity_len);
-
-	return 0;
-}
-
-
-static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
-					  const u8 *key_prov_auto)
-{
-	if (key_prov_auto == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
-		   *key_prov_auto);
-
-	return 0;
-}
-
-
-static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
-					   const u8 *dot1x_enabled)
-{
-	if (dot1x_enabled == NULL)
-		return 0; /* optional attribute */
-
-	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
-
-	return 0;
-}
-
-
-int wps_process_cred(struct wps_parse_attr *attr,
-		     struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Process Credential");
-
-	/* TODO: support multiple Network Keys */
-	if (wps_process_cred_network_idx(cred, attr->network_idx) ||
-	    wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
-	    wps_process_cred_auth_type(cred, attr->auth_type) ||
-	    wps_process_cred_encr_type(cred, attr->encr_type) ||
-	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
-	    wps_process_cred_network_key(cred, attr->network_key,
-					 attr->network_key_len) ||
-	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
-	    wps_process_cred_eap_type(cred, attr->eap_type,
-				      attr->eap_type_len) ||
-	    wps_process_cred_eap_identity(cred, attr->eap_identity,
-					  attr->eap_identity_len) ||
-	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
-	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
-		return -1;
-
-	return 0;
-}
-
-
-int wps_process_ap_settings(struct wps_parse_attr *attr,
-			    struct wps_credential *cred)
-{
-	wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
-	os_memset(cred, 0, sizeof(*cred));
-	/* TODO: optional attributes New Password and Device Password ID */
-	if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
-	    wps_process_cred_auth_type(cred, attr->auth_type) ||
-	    wps_process_cred_encr_type(cred, attr->encr_type) ||
-	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
-	    wps_process_cred_network_key(cred, attr->network_key,
-					 attr->network_key_len) ||
-	    wps_process_cred_mac_addr(cred, attr->mac_addr))
-		return -1;
-
-	return 0;
-}

+ 18 - 11
src/wps/wps_i.h

@@ -155,25 +155,26 @@ struct wps_parse_attr {
 };
 
 /* wps_common.c */
-int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
 	     const char *label, u8 *res, size_t res_len);
-int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
-int wps_build_config_methods(struct wpabuf *msg, u16 methods);
-int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
-int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
-int wps_build_config_error(struct wpabuf *msg, u16 err);
 int wps_derive_keys(struct wps_data *wps);
 int wps_derive_mgmt_keys(struct wps_data *wps);
-int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
-int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
-			      const struct wpabuf *msg);
 void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
 		    size_t dev_passwd_len);
 struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
 					  size_t encr_len);
-int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
-			      const u8 *key_wrap_auth);
+
+/* wps_attr_parse.c */
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
+
+/* wps_attr_build.c */
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
+int wps_build_config_methods(struct wpabuf *msg, u16 methods);
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
+int wps_build_config_error(struct wpabuf *msg, u16 err);
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
 			    struct wpabuf *plain);
@@ -185,6 +186,12 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
 int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
+
+/* wps_attr_process.c */
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg);
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth);
 int wps_process_cred(struct wps_parse_attr *attr,
 		     struct wps_credential *cred);
 int wps_process_ap_settings(struct wps_parse_attr *attr,

+ 3 - 0
wpa_supplicant/Makefile

@@ -505,6 +505,9 @@ OBJS += ../src/utils/uuid.o
 OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
 OBJS += ../src/wps/wps.o
 OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
 OBJS += ../src/wps/wps_dev_attr.o
 OBJS += ../src/wps/wps_enrollee.o
 OBJS += ../src/wps/wps_registrar.o