18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Protected Setup - common functionality
304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2008-2012, 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"
12cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#include "common/defs.h"
13cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#include "common/ieee802_11_common.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/dh_group5.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
21cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#include "wps_dev_attr.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     const char *label, u8 *res, size_t res_len)
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 i_buf[4], key_bits[4];
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, iter;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN], *opos;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t left;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(key_bits, res_len * 8);
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = i_buf;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(i_buf);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = label_prefix;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = label_prefix_len;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = (const u8 *) label;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = os_strlen(label);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = key_bits;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = sizeof(key_bits);
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	opos = res;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = res_len;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 1; i <= iter; i++) {
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_BE32(i_buf, i);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i < iter) {
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, SHA256_MAC_LEN);
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			opos += SHA256_MAC_LEN;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= SHA256_MAC_LEN;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, left);
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_derive_keys(struct wps_data *wps)
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pubkey, *dh_shared;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_privkey == NULL) {
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pubkey == NULL) {
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh5_free(wps->dh_ctx);
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_ctx = NULL;
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = wpabuf_zeropad(dh_shared, 192);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dh_shared == NULL) {
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Own DH private key is not needed anymore */
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->dh_privkey);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_privkey = NULL;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* DHKey = SHA-256(g^AB mod p) */
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wpabuf_head(dh_shared);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = wpabuf_len(dh_shared);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(1, addr, len, dhkey);
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(dh_shared);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wps->nonce_e;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_NONCE_LEN;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->mac_addr_e;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = ETH_ALEN;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wps->nonce_r;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = WPS_NONCE_LEN;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys, sizeof(keys));
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  WPS_EMSK_LEN);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->authkey, WPS_AUTHKEY_LEN);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    size_t dev_passwd_len)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (dev_passwd_len + 1) / 2, hash);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd + (dev_passwd_len + 1) / 2,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd_len / 2, hash);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      dev_passwd, dev_passwd_len);
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  size_t encr_len)
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t block_size = 16;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 pad;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AES-128-CBC */
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wpabuf_alloc(encr_len - block_size);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(decrypted))) {
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    decrypted);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad = *pos;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad > wpabuf_len(decrypted)) {
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < pad; i++) {
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos-- != pad) {
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "string");
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(decrypted);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted->used -= pad;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_checksum - Compute PIN checksum
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Checksum digit
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_checksum(unsigned int pin)
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int accum = 0;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pin) {
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += 3 * (pin % 10);
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += pin % 10;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (10 - accum % 10) % 10;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_valid - Check whether a PIN has a valid checksum
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Eight digit PIN (i.e., including the checksum digit)
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if checksum digit is valid, or 0 if not
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_valid(unsigned int pin)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_pin_checksum(pin / 10) == (pin % 10);
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_generate_pin - Generate a random PIN
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Eight digit PIN (i.e., including the checksum digit)
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_generate_pin(void)
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int val;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Generate seven random digits for the PIN */
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct os_time now;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_get_time(&now);
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = os_random() ^ now.sec ^ now.usec;
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	val %= 10000000;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Append checksum digit */
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return val * 10 + wps_pin_checksum(val);
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_pin_str_valid(const char *pin)
25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const char *p;
25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	size_t len;
25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	p = pin;
26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (*p >= '0' && *p <= '9')
26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		p++;
26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (*p != '\0')
26404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0;
26504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = p - pin;
26704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return len == 4 || len == 8;
26804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
26904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
27004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
272b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		    u16 config_error, u16 error_indication, const u8 *mac_addr)
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.msg = msg;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.config_error = config_error;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.error_indication = error_indication;
283b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN);
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_success_event(struct wps_context *wps, const u8 *mac_addr)
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
290b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	union wps_event_data data;
291b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
295b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
296b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN);
297b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
301b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
302b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     const u8 *mac_addr)
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.enrollee = enrollee;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.part = part;
312b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN);
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_overlap_event(struct wps_context *wps)
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_timeout_event(struct wps_context *wps)
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
335b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_active_event(struct wps_context *wps)
336b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
337b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
338b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
339b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
340b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL);
341b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
342b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
343b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
344b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_disable_event(struct wps_context *wps)
345b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
346b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
347b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
348b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
349b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL);
350b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
351b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
352b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
355cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
356cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 int channel)
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_data data;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *plain;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(500);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL) {
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "credential");
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.wps = wps;
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.auth_type = wps->auth_types;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.encr_type = wps->encr_types;
372cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_cred(&data, plain) ||
373cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (rf_band && wps_build_rf_bands_attr(plain, rf_band)) ||
374cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (channel && wps_build_ap_channel(plain, channel)) ||
375cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_mac_addr(plain, wps->dev.mac_addr) ||
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
3774b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_free(data.new_psk);
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
3834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	    wps->ap) {
3844b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		struct wps_credential cred;
3854b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3864b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
3874b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			   "on credential token generation");
3884b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3894b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memset(&cred, 0, sizeof(cred));
3904b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
3914b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.ssid_len = wps->ssid_len;
3924b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
3934b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
3944b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.key, data.new_psk, data.new_psk_len);
3954b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.key_len = data.new_psk_len;
3964b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3974b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wps->wps_state = WPS_STATE_CONFIGURED;
3984b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG,
3994b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      "WPS: Generated random passphrase",
4004b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      data.new_psk, data.new_psk_len);
4014b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		if (wps->cred_cb)
4024b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			wps->cred_cb(wps->cb_ctx, &cred);
4034b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	}
4044b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4054b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	os_free(data.new_psk);
4064b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return plain;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
41204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *pubkey,
41304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *dev_pw)
41404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
41504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *data;
41604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
41704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data = wpabuf_alloc(200);
41804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (data == NULL)
41904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
42004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
421cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
42204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
42304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wps_build_wfa_ext(data, 0, NULL, 0)) {
42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   "token");
42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(data);
42704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
42804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
42904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return data;
43104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
43204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf msg;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; i < attr->num_cred; i++) {
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential local_cred;
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr cattr;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&local_cred, 0, sizeof(local_cred));
44404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(&msg, &cattr) < 0 ||
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps_process_cred(&cattr, &local_cred)) {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credential");
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred_cb(wps->cb_ctx, &local_cred);
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *pos;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* <categ>-<OUI>-<subcateg> */
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(dev_type, atoi(str));
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(str, '-');
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(pos, &dev_type[2], 4))
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(pos, '-');
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(&dev_type[6], atoi(pos));
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    size_t buf_len)
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(&dev_type[6]));
4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(buf_len, ret))
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 nsid[16] = {
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x52, 0x64, 0x80, 0xf8,
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xc9, 0x9b,
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4b, 0xe5,
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xa6, 0x55,
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = nsid;
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(nsid);
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = mac_addr;
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 6;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha1_vector(2, addr, len, hash);
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(uuid, hash, 16);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Version: 5 = named-based version using SHA-1 */
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variant specified in RFC 4122 */
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[8] = 0x80 | (uuid[8] & 0x3f);
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu16 wps_config_methods_str2bin(const char *str)
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods = 0;
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (str == NULL) {
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Default to enabling methods based on build configuration */
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_VIRT_DISPLAY;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_NFC_INTERFACE;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
538216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt#ifdef CONFIG_P2P
539216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt		methods |= WPS_CONFIG_P2PS;
540216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt#endif /* CONFIG_P2P */
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ethernet"))
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_ETHERNET;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "label"))
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_LABEL;
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "display"))
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_DISPLAY;
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ext_nfc_token"))
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "int_nfc_token"))
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_INT_NFC_TOKEN;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "nfc_interface"))
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_NFC_INTERFACE;
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "push_button"))
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PUSHBUTTON;
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "keypad"))
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_KEYPAD;
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_display"))
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_DISPLAY;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_display"))
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_DISPLAY;
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_push_button"))
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_push_button"))
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
566216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt		if (os_strstr(str, "p2ps"))
567216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt			methods |= WPS_CONFIG_P2PS;
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return methods;
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, wps->config_error) ||
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
62004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
62104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_WPS_NFC
622f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
623f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstruct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
624f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				    struct wpabuf *dev_pw)
625f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
626f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpabuf *ret;
627f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
628f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (pubkey == NULL || dev_pw == NULL)
629f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return NULL;
630f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
631f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
632f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (ndef && ret) {
633f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		struct wpabuf *tmp;
634f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		tmp = ndef_build_wifi(ret);
635f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpabuf_free(ret);
636f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (tmp == NULL)
637f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return NULL;
638f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		ret = tmp;
639f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
640f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
641f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return ret;
642f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
643f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
644f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
645cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
646cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
647cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *priv = NULL, *pub = NULL;
648cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *dh_ctx;
649cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
650cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	dh_ctx = dh5_init(&priv, &pub);
651cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (dh_ctx == NULL)
652cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
653cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	pub = wpabuf_zeropad(pub, 192);
654cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (pub == NULL) {
655cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(priv);
656cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
657cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
658cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
659cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	dh5_free(dh_ctx);
660cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
661cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_free(*pubkey);
662cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	*pubkey = pub;
663cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_free(*privkey);
664cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	*privkey = priv;
665cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
666cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
667cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
668cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
669cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
67004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
67104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **privkey,
67204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **dev_pw)
67304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
674cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *pw;
67504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u16 val;
67604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
67704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
67804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (pw == NULL)
67904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
68004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
68104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
68204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			     WPS_OOB_DEVICE_PASSWORD_LEN) ||
68304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    random_get_bytes((u8 *) &val, sizeof(val))) {
68404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
68504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
68604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
68704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
688cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_nfc_gen_dh(pubkey, privkey) < 0) {
68904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
69004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
69104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
69204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
69304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*id = 0x10 + val % 0xfff0;
69404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(*dev_pw);
69504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*dev_pw = pw;
69604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
697f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
69804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
699f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
700cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
701cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
702cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   struct wpabuf *nfc_dh_pubkey)
703cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
704cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
705cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *len;
706cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
707cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
708cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
709cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
710cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
711cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover request");
712cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
713cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
714cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
715cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
716cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
717cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
718cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
719cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
720cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
721cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
722cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	len = wpabuf_put(msg, 2);
723cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
724cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
725cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
726cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
727cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
728cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
729cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
730cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
731cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
732cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
733cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
734cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
735cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
736cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
737cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
738cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstatic int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps)
739cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
740cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
741cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select",
742cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			  wps->ssid, wps->ssid_len);
743cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, ATTR_SSID);
744cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, wps->ssid_len);
745cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_data(msg, wps->ssid, wps->ssid_len);
746cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
747cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
748cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
749cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
750cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstatic int wps_build_ap_freq(struct wpabuf *msg, int freq)
751cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
752cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	enum hostapd_hw_mode mode;
753cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	u8 channel, rf_band;
754cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	u16 ap_channel;
755cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
756cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (freq <= 0)
757cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0;
758cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
759cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	mode = ieee80211_freq_to_chan(freq, &channel);
760cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (mode == NUM_HOSTAPD_MODES)
761cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0; /* Unknown channel */
762cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
763cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B)
764cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		rf_band = WPS_RF_24GHZ;
765cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	else if (mode == HOSTAPD_MODE_IEEE80211A)
766cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		rf_band = WPS_RF_50GHZ;
7671d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	else if (mode == HOSTAPD_MODE_IEEE80211AD)
7681d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		rf_band = WPS_RF_60GHZ;
769cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	else
770cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0; /* Unknown band */
771cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	ap_channel = channel;
772cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
773cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_rf_bands_attr(msg, rf_band) ||
774cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ap_channel(msg, ap_channel))
775cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
776cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
777cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
778cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
779cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
780cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
781cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
782cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   struct wpabuf *nfc_dh_pubkey,
783cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   const u8 *bssid, int freq)
784cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
785cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
786cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *len;
787cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
788cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
789cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
790cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
791cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
792cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover select");
793cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
794cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
795cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
796cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
797cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
798cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
799cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
800cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
801cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
802cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
803cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	len = wpabuf_put(msg, 2);
804cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
805cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
806cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
807cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ssid(msg, ctx) ||
808cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ap_freq(msg, freq) ||
809cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (bssid && wps_build_mac_addr(msg, bssid)) ||
810cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
811cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
812cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
813cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
814cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
815cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
816cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
817cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
818cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
819cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
820cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
821cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
822cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dh_pubkey)
823cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
824cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
825cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
826cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
827cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
828cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
829cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
830cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover request (P2P)");
831cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
832cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
833cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured");
834cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
835cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
836cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
837cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
838cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
839cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
840cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
841cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_manufacturer(&ctx->dev, msg) ||
842cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_name(&ctx->dev, msg) ||
843cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_number(&ctx->dev, msg) ||
844cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
845cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
846cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
847cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_serial_number(&ctx->dev, msg) ||
848cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
849cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
850cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
851cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
852cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
853cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
854cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
855cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
856cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
857cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
858cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
859cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       int nfc_dev_pw_id,
860cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dh_pubkey,
861cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dev_pw)
862cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
863cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
864cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	const u8 *dev_pw;
865cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	size_t dev_pw_len;
866cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
867cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
868cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
869cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
870cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
871cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover select (P2P)");
872cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
873cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL ||
874cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
875cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	     nfc_dev_pw == NULL)) {
876cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
877cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
878cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
879cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
880cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
881cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
882cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
883cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
884cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
885cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dev_pw) {
886cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw = wpabuf_head(nfc_dev_pw);
887cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw_len = wpabuf_len(nfc_dev_pw);
888cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	} else {
889cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw = NULL;
890cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw_len = 0;
891cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
892cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
893cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_manufacturer(&ctx->dev, msg) ||
894cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_name(&ctx->dev, msg) ||
895cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_number(&ctx->dev, msg) ||
896cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey,
897cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 dev_pw, dev_pw_len) ||
898cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
899cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_serial_number(&ctx->dev, msg) ||
900cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
901cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
902cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
903cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
904cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
905cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
906cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
907cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
908cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
90904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_WPS_NFC */
910