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 */
93849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	wpabuf_clear_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));
103849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	wpabuf_clear_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
132849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtint wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
133849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		   size_t dev_passwd_len)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
137849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
138849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			(dev_passwd_len + 1) / 2, hash) < 0)
139849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		return -1;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
141849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
142849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			dev_passwd + (dev_passwd_len + 1) / 2,
143849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			dev_passwd_len / 2, hash) < 0)
144849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		return -1;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      dev_passwd, dev_passwd_len);
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
151849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	return 0;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  size_t encr_len)
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t block_size = 16;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 pad;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AES-128-CBC */
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wpabuf_alloc(encr_len - block_size);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(decrypted))) {
179849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpabuf_clear_free(decrypted);
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    decrypted);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad = *pos;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad > wpabuf_len(decrypted)) {
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
190849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpabuf_clear_free(decrypted);
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < pad; i++) {
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos-- != pad) {
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "string");
197849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			wpabuf_clear_free(decrypted);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted->used -= pad;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_checksum - Compute PIN checksum
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Checksum digit
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_checksum(unsigned int pin)
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int accum = 0;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pin) {
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += 3 * (pin % 10);
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += pin % 10;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (10 - accum % 10) % 10;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_valid - Check whether a PIN has a valid checksum
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Eight digit PIN (i.e., including the checksum digit)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if checksum digit is valid, or 0 if not
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_valid(unsigned int pin)
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_pin_checksum(pin / 10) == (pin % 10);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_generate_pin - Generate a random PIN
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Eight digit PIN (i.e., including the checksum digit)
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
24157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidtint wps_generate_pin(unsigned int *pin)
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int val;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Generate seven random digits for the PIN */
24657c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0)
24757c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt		return -1;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	val %= 10000000;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Append checksum digit */
25157c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	*pin = val * 10 + wps_pin_checksum(val);
25257c2d39d85825f38c5fdac9b73bb0088406ffc85Dmitry Shmidt	return 0;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_pin_str_valid(const char *pin)
25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const char *p;
25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	size_t len;
26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	p = pin;
26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (*p >= '0' && *p <= '9')
26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		p++;
26404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (*p != '\0')
26504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0;
26604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = p - pin;
26804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return len == 4 || len == 8;
26904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
27004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
27104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
273b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		    u16 config_error, u16 error_indication, const u8 *mac_addr)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.msg = msg;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.config_error = config_error;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.error_indication = error_indication;
284b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
289b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_success_event(struct wps_context *wps, const u8 *mac_addr)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
291b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	union wps_event_data data;
292b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
296b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
297b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN);
298b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
302b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
303b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     const u8 *mac_addr)
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.enrollee = enrollee;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.part = part;
313b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN);
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_overlap_event(struct wps_context *wps)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_timeout_event(struct wps_context *wps)
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
336b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_active_event(struct wps_context *wps)
337b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
338b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
339b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
340b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
341b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL);
342b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
343b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
344b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
345b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_disable_event(struct wps_context *wps)
346b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
347b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
348b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
349b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
350b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL);
351b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
352b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
353b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
356cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band,
357cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 int channel)
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_data data;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *plain;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(500);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL) {
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "credential");
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.wps = wps;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.auth_type = wps->auth_types;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.encr_type = wps->encr_types;
373cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_cred(&data, plain) ||
374cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (rf_band && wps_build_rf_bands_attr(plain, rf_band)) ||
375cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (channel && wps_build_ap_channel(plain, channel)) ||
376cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_mac_addr(plain, wps->dev.mac_addr) ||
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
3784b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_free(data.new_psk);
379849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpabuf_clear_free(plain);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
3844b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	    wps->ap) {
3854b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		struct wps_credential cred;
3864b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3874b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
3884b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			   "on credential token generation");
3894b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3904b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memset(&cred, 0, sizeof(cred));
3914b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
3924b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.ssid_len = wps->ssid_len;
3934b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
3944b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
3954b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.key, data.new_psk, data.new_psk_len);
3964b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.key_len = data.new_psk_len;
3974b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3984b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wps->wps_state = WPS_STATE_CONFIGURED;
3994b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG,
4004b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      "WPS: Generated random passphrase",
4014b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      data.new_psk, data.new_psk_len);
4024b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		if (wps->cred_cb)
4034b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			wps->cred_cb(wps->cb_ctx, &cred);
4044b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	}
4054b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4064b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	os_free(data.new_psk);
4074b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return plain;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
41304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *pubkey,
41404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *dev_pw)
41504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
41604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *data;
41704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
41804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data = wpabuf_alloc(200);
41904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (data == NULL)
42004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
42104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
422cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
42304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wps_build_wfa_ext(data, 0, NULL, 0)) {
42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   "token");
427849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt		wpabuf_clear_free(data);
42804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
42904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
43004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return data;
43204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
43304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf msg;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; i < attr->num_cred; i++) {
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential local_cred;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr cattr;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&local_cred, 0, sizeof(local_cred));
44504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(&msg, &cattr) < 0 ||
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps_process_cred(&cattr, &local_cred)) {
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credential");
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred_cb(wps->cb_ctx, &local_cred);
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *pos;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* <categ>-<OUI>-<subcateg> */
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(dev_type, atoi(str));
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(str, '-');
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(pos, &dev_type[2], 4))
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(pos, '-');
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(&dev_type[6], atoi(pos));
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    size_t buf_len)
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(&dev_type[6]));
4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(buf_len, ret))
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 nsid[16] = {
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x52, 0x64, 0x80, 0xf8,
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xc9, 0x9b,
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4b, 0xe5,
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xa6, 0x55,
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = nsid;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(nsid);
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = mac_addr;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 6;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha1_vector(2, addr, len, hash);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(uuid, hash, 16);
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Version: 5 = named-based version using SHA-1 */
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variant specified in RFC 4122 */
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[8] = 0x80 | (uuid[8] & 0x3f);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu16 wps_config_methods_str2bin(const char *str)
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods = 0;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
532d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (str == NULL || str[0] == '\0') {
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Default to enabling methods based on build configuration */
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_VIRT_DISPLAY;
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_NFC_INTERFACE;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
539216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt#ifdef CONFIG_P2P
540216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt		methods |= WPS_CONFIG_P2PS;
541216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt#endif /* CONFIG_P2P */
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ethernet"))
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_ETHERNET;
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "label"))
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_LABEL;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "display"))
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_DISPLAY;
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ext_nfc_token"))
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "int_nfc_token"))
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_INT_NFC_TOKEN;
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "nfc_interface"))
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_NFC_INTERFACE;
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "push_button"))
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PUSHBUTTON;
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "keypad"))
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_KEYPAD;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_display"))
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_DISPLAY;
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_display"))
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_DISPLAY;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_push_button"))
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_push_button"))
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
567216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt		if (os_strstr(str, "p2ps"))
568216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt			methods |= WPS_CONFIG_P2PS;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return methods;
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, wps->config_error) ||
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
62104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
62204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_WPS_NFC
623f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
624f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstruct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
625f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				    struct wpabuf *dev_pw)
626f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
627f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpabuf *ret;
628f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
629f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (pubkey == NULL || dev_pw == NULL)
630f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return NULL;
631f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
632f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
633f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (ndef && ret) {
634f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		struct wpabuf *tmp;
635f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		tmp = ndef_build_wifi(ret);
636f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpabuf_free(ret);
637f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (tmp == NULL)
638f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return NULL;
639f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		ret = tmp;
640f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
641f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
642f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return ret;
643f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
644f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
645f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
646cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtint wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey)
647cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
648cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *priv = NULL, *pub = NULL;
649cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *dh_ctx;
650cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
651cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	dh_ctx = dh5_init(&priv, &pub);
652cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (dh_ctx == NULL)
653cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
654cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	pub = wpabuf_zeropad(pub, 192);
655cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (pub == NULL) {
656cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(priv);
657cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
658cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
659cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub);
660cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	dh5_free(dh_ctx);
661cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
662cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_free(*pubkey);
663cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	*pubkey = pub;
664849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	wpabuf_clear_free(*privkey);
665cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	*privkey = priv;
666cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
667cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
668cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
669cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
670cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
67104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
67204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **privkey,
67304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **dev_pw)
67404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
675cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *pw;
67604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u16 val;
67704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
67804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
67904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (pw == NULL)
68004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
68104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
68204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
68304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			     WPS_OOB_DEVICE_PASSWORD_LEN) ||
68404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    random_get_bytes((u8 *) &val, sizeof(val))) {
68504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
68604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
68704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
68804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
689cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_nfc_gen_dh(pubkey, privkey) < 0) {
69004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
69104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
69204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
69304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
69404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*id = 0x10 + val % 0xfff0;
695849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	wpabuf_clear_free(*dev_pw);
69604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*dev_pw = pw;
69704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
698f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
69904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
700f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
701cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
702cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
703cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   struct wpabuf *nfc_dh_pubkey)
704cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
705cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
706cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *len;
707cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
708cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
709cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
710cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
711cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
712cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover request");
713cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
714cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
715cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
716cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
717cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
718cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
719cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
720cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
721cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
722cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
723cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	len = wpabuf_put(msg, 2);
724cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
725cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
726cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
727cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
728cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
729cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
730cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
731cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
732cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
733cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
734cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
735cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
736cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
737cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
738cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
739cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstatic int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps)
740cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
741cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
742cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select",
743cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			  wps->ssid, wps->ssid_len);
744cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, ATTR_SSID);
745cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_be16(msg, wps->ssid_len);
746cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpabuf_put_data(msg, wps->ssid, wps->ssid_len);
747cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
748cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
749cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
750cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
751cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstatic int wps_build_ap_freq(struct wpabuf *msg, int freq)
752cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
753cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	enum hostapd_hw_mode mode;
754cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	u8 channel, rf_band;
755cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	u16 ap_channel;
756cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
757cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (freq <= 0)
758cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0;
759cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
760cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	mode = ieee80211_freq_to_chan(freq, &channel);
761cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (mode == NUM_HOSTAPD_MODES)
762cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0; /* Unknown channel */
763cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
764cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B)
765cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		rf_band = WPS_RF_24GHZ;
766cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	else if (mode == HOSTAPD_MODE_IEEE80211A)
767cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		rf_band = WPS_RF_50GHZ;
7681d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	else if (mode == HOSTAPD_MODE_IEEE80211AD)
7691d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		rf_band = WPS_RF_60GHZ;
770cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	else
771cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return 0; /* Unknown band */
772cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	ap_channel = channel;
773cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
774cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_rf_bands_attr(msg, rf_band) ||
775cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ap_channel(msg, ap_channel))
776cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return -1;
777cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
778cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return 0;
779cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
780cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
781cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
782cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
783cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   struct wpabuf *nfc_dh_pubkey,
784cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					   const u8 *bssid, int freq)
785cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
786cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
787cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	void *len;
788cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
789cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
790cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
791cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
792cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
793cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover select");
794cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
795cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
796cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
797cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
798cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
799cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
800cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
801cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
802cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
803cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
804cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	len = wpabuf_put(msg, 2);
805cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
806cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
807cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
808cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ssid(msg, ctx) ||
809cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_ap_freq(msg, freq) ||
810cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (bssid && wps_build_mac_addr(msg, bssid)) ||
811cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
812cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
813cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
814cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
815cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
816cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
817cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
818cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
819cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
820cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
821cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
822cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx,
823cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dh_pubkey)
824cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
825cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
826cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
827cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
828cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
829cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
830cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
831cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover request (P2P)");
832cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
833cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL) {
834cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured");
835cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
836cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
837cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
838cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
839cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
840cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
841cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
842cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_manufacturer(&ctx->dev, msg) ||
843cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_name(&ctx->dev, msg) ||
844cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_number(&ctx->dev, msg) ||
845cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
846cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 nfc_dh_pubkey, NULL, 0) ||
847cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
848cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_serial_number(&ctx->dev, msg) ||
849cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
850cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
851cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
852cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
853cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
854cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
855cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
856cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
857cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
858cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
859cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx,
860cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       int nfc_dev_pw_id,
861cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dh_pubkey,
862cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					       struct wpabuf *nfc_dev_pw)
863cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
864cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wpabuf *msg;
865cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	const u8 *dev_pw;
866cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	size_t dev_pw_len;
867cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
868cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ctx == NULL)
869cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
870cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
871cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
872cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		   "handover select (P2P)");
873cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
874cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dh_pubkey == NULL ||
875cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
876cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	     nfc_dev_pw == NULL)) {
877cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
878cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "configured");
879cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
880cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
881cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
882cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	msg = wpabuf_alloc(1000);
883cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (msg == NULL)
884cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return msg;
885cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
886cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (nfc_dev_pw) {
887cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw = wpabuf_head(nfc_dev_pw);
888cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw_len = wpabuf_len(nfc_dev_pw);
889cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	} else {
890cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw = NULL;
891cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		dev_pw_len = 0;
892cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
893cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
894cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_manufacturer(&ctx->dev, msg) ||
895cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_name(&ctx->dev, msg) ||
896cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_model_number(&ctx->dev, msg) ||
897cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey,
898cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt				 dev_pw, dev_pw_len) ||
899cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_rf_bands(&ctx->dev, msg, 0) ||
900cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_serial_number(&ctx->dev, msg) ||
901cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_uuid_e(msg, ctx->uuid) ||
902cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
903cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpabuf_free(msg);
904cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
905cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
906cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
907cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return msg;
908cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
909cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
91004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_WPS_NFC */
911