18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Protected Setup - attribute building
3de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/dh_group5.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pubkey;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->dh_privkey);
271e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	wps->dh_privkey = NULL;
281e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
291e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	    wps->wps->dh_ctx) {
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
311e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		if (wps->wps->dh_pubkey == NULL) {
321e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			wpa_printf(MSG_DEBUG,
331e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt				   "WPS: wps->wps->dh_pubkey == NULL");
341e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			return -1;
351e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		}
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->dh_ctx = wps->wps->dh_ctx;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->wps->dh_ctx = NULL;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_WPS_NFC
41cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	} else if ((wps->dev_pw_id >= 0x10 ||
42cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
43cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   (wps->wps->ap ||
44cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		    (wps->wps->ap_nfc_dh_pubkey &&
45cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		     wps->wps->ap_nfc_dev_pw_id ==
46cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		     DEV_PW_NFC_CONNECTION_HANDOVER &&
47cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		     wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
48cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
49cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		    wps->wps->ap_nfc_dh_pubkey)) {
5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
511e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		if (wps->wps->ap_nfc_dh_privkey == NULL) {
521e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			wpa_printf(MSG_DEBUG,
531e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt				   "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
541e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			return -1;
551e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		}
561e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		if (wps->wps->ap_nfc_dh_pubkey == NULL) {
571e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			wpa_printf(MSG_DEBUG,
581e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt				   "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
591e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			return -1;
601e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		}
6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_WPS_NFC */
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dh5_free(wps->dh_ctx);
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pubkey = wpabuf_zeropad(pubkey, 192);
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Diffie-Hellman handshake");
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(pubkey);
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, wpabuf_len(pubkey));
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, pubkey);
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->registrar) {
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps->dh_pubkey_r);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->dh_pubkey_r = pubkey;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps->dh_pubkey_e);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->dh_pubkey_e = pubkey;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, type);
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Response Type (%d)", type);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, type);
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_config_methods(struct wpabuf *msg, u16 methods)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, methods);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
12968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return -1;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_UUID_E);
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_UUID_LEN);
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_dev_password_id(struct wpabuf *msg, u16 id)
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, id);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_config_error(struct wpabuf *msg, u16 err)
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, err);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->last_msg == NULL) {
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "building authenticator");
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * (M_curr* is M_curr without the Authenticator attribute)
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wpabuf_head(wps->last_msg);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = wpabuf_len(wps->last_msg);
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wpabuf_head(msg);
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = wpabuf_len(msg);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_version(struct wpabuf *msg)
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Note: This attribute is deprecated and set to hardcoded 0x10 for
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * backwards compatibility reasons. The real version negotiation is
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * done with Version2.
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
19568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (wpabuf_tailroom(msg) < 5)
19668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return -1;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Version (hardcoded 0x10)");
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_VERSION);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, 0x10);
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *auth_macs, size_t auth_macs_count)
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *len;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
210fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt#ifdef CONFIG_WPS_TESTING
211fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (WPS_VERSION == 0x10)
212fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return 0;
213fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt#endif /* CONFIG_WPS_TESTING */
214fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
21568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (wpabuf_tailroom(msg) <
21668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	    7 + 3 + (req_to_enroll ? 3 : 0) +
21768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	    (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
21868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		return -1;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = wpabuf_put(msg, 2); /* to be filled */
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Version2 (0x%x)", WPS_VERSION);
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, 1);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, WPS_VERSION);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req_to_enroll) {
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS:  * Request to Enroll (1)");
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, 1);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, 1);
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (auth_macs && auth_macs_count) {
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t i;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS:  * AuthorizedMACs (count=%d)",
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) auth_macs_count);
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; i < auth_macs_count; i++)
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS:    AuthorizedMAC: " MACSTR,
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(&auth_macs[i * ETH_ALEN]));
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_TESTING
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (WPS_VERSION > 0x20) {
25168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (wpabuf_tailroom(msg) < 5)
25268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			return -1;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS:  * Extensibility Testing - extra "
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "attribute");
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, 1);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, 42);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_TESTING */
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, msg_type);
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_NONCE_LEN);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_NONCE_LEN);
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 auth_types = WPS_AUTH_TYPES;
2976cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	/* WPA/WPA2-Enterprise enrollment not supported through WPS */
2986cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	auth_types &= ~WPS_AUTH_WPA;
2996cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	auth_types &= ~WPS_AUTH_WPA2;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	auth_types &= ~WPS_AUTH_SHARED;
301de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt#ifdef CONFIG_WPS_TESTING
302de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	if (wps_force_auth_types_in_use) {
303de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		wpa_printf(MSG_DEBUG,
304de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt			   "WPS: Testing - replace auth type 0x%x with 0x%x",
305de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt			   auth_types, wps_force_auth_types);
306de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		auth_types = wps_force_auth_types;
307de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	}
308de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt#endif /* CONFIG_WPS_TESTING */
309de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags (0x%x)",
310de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		   auth_types);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, auth_types);
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 encr_types = WPS_ENCR_TYPES;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_types &= ~WPS_ENCR_WEP;
322de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt#ifdef CONFIG_WPS_TESTING
323de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	if (wps_force_encr_types_in_use) {
324de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		wpa_printf(MSG_DEBUG,
325de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt			   "WPS: Testing - replace encr type 0x%x with 0x%x",
326de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt			   encr_types, wps_force_encr_types);
327de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		encr_types = wps_force_encr_types;
328de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	}
329de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt#endif /* CONFIG_WPS_TESTING */
330de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags (0x%x)",
331de47be75037bccd4a11b62eedb3d4aed1b36fa67Dmitry Shmidt		   encr_types);
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, encr_types);
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, WPS_CONN_ESS);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpabuf_len(msg), hash);
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_KWA_LEN);
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct wpabuf *plain)
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pad_len;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t block_size = 16;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *iv, *data;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* PKCS#5 v2.0 pad */
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad_len = block_size - wpabuf_len(plain) % block_size;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iv = wpabuf_put(msg, block_size);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(iv, block_size) < 0)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = wpabuf_put(msg, 0);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, plain);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
40404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
40504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 const struct wpabuf *pubkey, const u8 *dev_pw,
40604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			 size_t dev_pw_len)
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t hash_len;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[1];
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 pubkey_hash[WPS_HASH_LEN];
41104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4125460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * OOB Device Password (dev_pw_id=%u)",
4135460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		   dev_pw_id);
41404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	addr[0] = wpabuf_head(pubkey);
41504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	hash_len = wpabuf_len(pubkey);
41604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	sha256_vector(1, addr, &hash_len, pubkey_hash);
417cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#ifdef CONFIG_WPS_TESTING
418cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_corrupt_pkhash) {
419cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
420cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
421cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash");
422cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++;
423cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
424cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#endif /* CONFIG_WPS_TESTING */
42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
42704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
4285460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
4295460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt		    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
43004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
43104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_put_be16(msg, dev_pw_id);
432cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (dev_pw) {
433cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
434cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				dev_pw, dev_pw_len);
435cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_put_data(msg, dev_pw, dev_pw_len);
436cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
43704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return 0;
43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *ie;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ie = wpabuf_alloc(wpabuf_len(data) + 100);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie == NULL) {
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(data);
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = wpabuf_head(data);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = pos + wpabuf_len(data);
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (end > pos) {
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t frag_len = end - pos;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (frag_len > 251)
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			frag_len = 251;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(ie, 4 + frag_len);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_data(ie, pos, frag_len);
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += frag_len;
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(data);
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ie;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4734b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4744b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4754b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidtint wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
4764b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt{
4774b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
4784b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		   MAC2STR(addr));
4794b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
4804b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	wpabuf_put_be16(msg, ETH_ALEN);
4814b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	wpabuf_put_data(msg, addr, ETH_ALEN);
4824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	return 0;
4834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt}
484cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
485cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
486cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands)
487cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
488cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", rf_bands);
489cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, ATTR_RF_BANDS);
490cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, 1);
491cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_u8(msg, rf_bands);
492cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
493cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
494cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
495cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
496cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel)
497cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
498cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * AP Channel (%u)", ap_channel);
499cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, ATTR_AP_CHANNEL);
500cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, 2);
501cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, ap_channel);
502cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
503cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
504