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"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/dh_group5.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     const char *label, u8 *res, size_t res_len)
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 i_buf[4], key_bits[4];
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, iter;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN], *opos;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t left;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(key_bits, res_len * 8);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = i_buf;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(i_buf);
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = label_prefix;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = label_prefix_len;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = (const u8 *) label;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = os_strlen(label);
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = key_bits;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = sizeof(key_bits);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	opos = res;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = res_len;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 1; i <= iter; i++) {
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_BE32(i_buf, i);
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i < iter) {
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, SHA256_MAC_LEN);
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			opos += SHA256_MAC_LEN;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= SHA256_MAC_LEN;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, left);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_derive_keys(struct wps_data *wps)
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pubkey, *dh_shared;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_privkey == NULL) {
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pubkey == NULL) {
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh5_free(wps->dh_ctx);
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_ctx = NULL;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = wpabuf_zeropad(dh_shared, 192);
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dh_shared == NULL) {
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Own DH private key is not needed anymore */
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->dh_privkey);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_privkey = NULL;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* DHKey = SHA-256(g^AB mod p) */
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wpabuf_head(dh_shared);
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = wpabuf_len(dh_shared);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(1, addr, len, dhkey);
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(dh_shared);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wps->nonce_e;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_NONCE_LEN;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->mac_addr_e;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = ETH_ALEN;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wps->nonce_r;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = WPS_NONCE_LEN;
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys, sizeof(keys));
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  WPS_EMSK_LEN);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->authkey, WPS_AUTHKEY_LEN);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    size_t dev_passwd_len)
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (dev_passwd_len + 1) / 2, hash);
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd + (dev_passwd_len + 1) / 2,
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd_len / 2, hash);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      dev_passwd, dev_passwd_len);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  size_t encr_len)
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t block_size = 16;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 pad;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AES-128-CBC */
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wpabuf_alloc(encr_len - block_size);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(decrypted))) {
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    decrypted);
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad = *pos;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad > wpabuf_len(decrypted)) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < pad; i++) {
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos-- != pad) {
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "string");
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(decrypted);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted->used -= pad;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_checksum - Compute PIN checksum
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Checksum digit
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_checksum(unsigned int pin)
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int accum = 0;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pin) {
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += 3 * (pin % 10);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += pin % 10;
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (10 - accum % 10) % 10;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_valid - Check whether a PIN has a valid checksum
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Eight digit PIN (i.e., including the checksum digit)
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if checksum digit is valid, or 0 if not
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_valid(unsigned int pin)
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_pin_checksum(pin / 10) == (pin % 10);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_generate_pin - Generate a random PIN
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Eight digit PIN (i.e., including the checksum digit)
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_generate_pin(void)
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int val;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Generate seven random digits for the PIN */
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct os_time now;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_get_time(&now);
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = os_random() ^ now.sec ^ now.usec;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	val %= 10000000;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Append checksum digit */
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return val * 10 + wps_pin_checksum(val);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_pin_str_valid(const char *pin)
25304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
25404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	const char *p;
25504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	size_t len;
25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	p = pin;
25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	while (*p >= '0' && *p <= '9')
25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		p++;
26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (*p != '\0')
26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return 0;
26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	len = p - pin;
26404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return len == 4 || len == 8;
26504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
26604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
26704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
269b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		    u16 config_error, u16 error_indication, const u8 *mac_addr)
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.msg = msg;
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.config_error = config_error;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.error_indication = error_indication;
280b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
285b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_success_event(struct wps_context *wps, const u8 *mac_addr)
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
287b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	union wps_event_data data;
288b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
292b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
293b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN);
294b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
298b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part,
299b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     const u8 *mac_addr)
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.enrollee = enrollee;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.part = part;
309b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN);
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_overlap_event(struct wps_context *wps)
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_timeout_event(struct wps_context *wps)
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
332b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_active_event(struct wps_context *wps)
333b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
334b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
335b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
336b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
337b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL);
338b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
339b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
340b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
341b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtvoid wps_pbc_disable_event(struct wps_context *wps)
342b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
343b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (wps->event_cb == NULL)
344b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
345b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
346b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL);
347b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
348b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
349b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_get_oob_cred(struct wps_context *wps)
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_data data;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *plain;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(500);
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL) {
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "credential");
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.wps = wps;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.auth_type = wps->auth_types;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.encr_type = wps->encr_types;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(plain) ||
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred(&data, plain) ||
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
3714b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_free(data.new_psk);
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3764b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk &&
3774b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	    wps->ap) {
3784b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		struct wps_credential cred;
3794b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3804b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
3814b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			   "on credential token generation");
3824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memset(&cred, 0, sizeof(cred));
3844b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.ssid, wps->ssid, wps->ssid_len);
3854b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.ssid_len = wps->ssid_len;
3864b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
3874b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
3884b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		os_memcpy(cred.key, data.new_psk, data.new_psk_len);
3894b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		cred.key_len = data.new_psk_len;
3904b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3914b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wps->wps_state = WPS_STATE_CONFIGURED;
3924b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG,
3934b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      "WPS: Generated random passphrase",
3944b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				      data.new_psk, data.new_psk_len);
3954b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		if (wps->cred_cb)
3964b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			wps->cred_cb(wps->cb_ctx, &cred);
3974b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	}
3984b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3994b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	os_free(data.new_psk);
4004b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return plain;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
40604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *pubkey,
40704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				       const struct wpabuf *dev_pw)
40804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
40904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *data;
41004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
41104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data = wpabuf_alloc(200);
41204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (data == NULL)
41304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
41404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
41504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (wps_build_version(data) ||
41604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
41704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
41804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wps_build_wfa_ext(data, 0, NULL, 0)) {
41904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
42004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   "token");
42104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(data);
42204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
42304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
42404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
42504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return data;
42604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
42704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
42804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
42904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtint wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf msg;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	for (i = 0; i < attr->num_cred; i++) {
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential local_cred;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr cattr;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&local_cred, 0, sizeof(local_cred));
43904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(&msg, &cattr) < 0 ||
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps_process_cred(&cattr, &local_cred)) {
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credential");
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred_cb(wps->cb_ctx, &local_cred);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *pos;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* <categ>-<OUI>-<subcateg> */
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(dev_type, atoi(str));
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(str, '-');
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(pos, &dev_type[2], 4))
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(pos, '-');
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(&dev_type[6], atoi(pos));
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    size_t buf_len)
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(&dev_type[6]));
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || (unsigned int) ret >= buf_len)
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 nsid[16] = {
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x52, 0x64, 0x80, 0xf8,
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xc9, 0x9b,
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4b, 0xe5,
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xa6, 0x55,
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = nsid;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(nsid);
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = mac_addr;
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 6;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha1_vector(2, addr, len, hash);
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(uuid, hash, 16);
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Version: 5 = named-based version using SHA-1 */
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variant specified in RFC 4122 */
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[8] = 0x80 | (uuid[8] & 0x3f);
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu16 wps_config_methods_str2bin(const char *str)
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods = 0;
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (str == NULL) {
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Default to enabling methods based on build configuration */
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_VIRT_DISPLAY;
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_NFC_INTERFACE;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ethernet"))
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_ETHERNET;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "label"))
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_LABEL;
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "display"))
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_DISPLAY;
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ext_nfc_token"))
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "int_nfc_token"))
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_INT_NFC_TOKEN;
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "nfc_interface"))
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_NFC_INTERFACE;
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "push_button"))
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PUSHBUTTON;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "keypad"))
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_KEYPAD;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_display"))
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_DISPLAY;
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_display"))
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_DISPLAY;
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_push_button"))
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_push_button"))
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return methods;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, wps->config_error) ||
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
61404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
61504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_WPS_NFC
616f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
617f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstruct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
618f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				    struct wpabuf *dev_pw)
619f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
620f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpabuf *ret;
621f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
622f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (pubkey == NULL || dev_pw == NULL)
623f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return NULL;
624f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
625f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
626f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (ndef && ret) {
627f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		struct wpabuf *tmp;
628f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		tmp = ndef_build_wifi(ret);
629f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpabuf_free(ret);
630f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (tmp == NULL)
631f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return NULL;
632f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		ret = tmp;
633f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
634f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
635f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return ret;
636f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
637f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
638f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
63904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
64004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **privkey,
64104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				  struct wpabuf **dev_pw)
64204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
643f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct wpabuf *priv = NULL, *pub = NULL, *pw;
64404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	void *dh_ctx;
64504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u16 val;
64604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
64704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
64804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (pw == NULL)
64904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
65004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
65104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
65204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			     WPS_OOB_DEVICE_PASSWORD_LEN) ||
65304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    random_get_bytes((u8 *) &val, sizeof(val))) {
65404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
65504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
65604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
65704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
65804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dh_ctx = dh5_init(&priv, &pub);
65904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (dh_ctx == NULL) {
66004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(pw);
66104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
66204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
66304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dh5_free(dh_ctx);
66404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
66504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*id = 0x10 + val % 0xfff0;
66604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(*pubkey);
66704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pubkey = pub;
66804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(*privkey);
66904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*privkey = priv;
67004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpabuf_free(*dev_pw);
67104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*dev_pw = pw;
67204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
673f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
67404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
675f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
67604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_WPS_NFC */
677