wps_common.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Protected Setup - common functionality
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/aes_wrap.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/dh_group5.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_dev_attr.h"
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     const char *label, u8 *res, size_t res_len)
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 i_buf[4], key_bits[4];
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, iter;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN], *opos;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t left;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE32(key_bits, res_len * 8);
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = i_buf;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(i_buf);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = label_prefix;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = label_prefix_len;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = (const u8 *) label;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = os_strlen(label);
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = key_bits;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = sizeof(key_bits);
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	opos = res;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	left = res_len;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 1; i <= iter; i++) {
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_PUT_BE32(i_buf, i);
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i < iter) {
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, SHA256_MAC_LEN);
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			opos += SHA256_MAC_LEN;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			left -= SHA256_MAC_LEN;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(opos, hash, left);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_derive_keys(struct wps_data *wps)
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pubkey, *dh_shared;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[3];
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[3];
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_privkey == NULL) {
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pubkey == NULL) {
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh5_free(wps->dh_ctx);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_ctx = NULL;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dh_shared = wpabuf_zeropad(dh_shared, 192);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dh_shared == NULL) {
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Own DH private key is not needed anymore */
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->dh_privkey);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_privkey = NULL;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* DHKey = SHA-256(g^AB mod p) */
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wpabuf_head(dh_shared);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = wpabuf_len(dh_shared);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha256_vector(1, addr, len, dhkey);
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(dh_shared);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wps->nonce_e;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_NONCE_LEN;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->mac_addr_e;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = ETH_ALEN;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wps->nonce_r;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = WPS_NONCE_LEN;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		keys, sizeof(keys));
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  WPS_EMSK_LEN);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->authkey, WPS_AUTHKEY_LEN);
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    size_t dev_passwd_len)
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (dev_passwd_len + 1) / 2, hash);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd + (dev_passwd_len + 1) / 2,
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    dev_passwd_len / 2, hash);
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      dev_passwd, dev_passwd_len);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  size_t encr_len)
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const size_t block_size = 16;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 pad;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AES-128-CBC */
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wpabuf_alloc(encr_len - block_size);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL)
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpabuf_len(decrypted))) {
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    decrypted);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pad = *pos;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pad > wpabuf_len(decrypted)) {
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < pad; i++) {
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos-- != pad) {
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "string");
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(decrypted);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted->used -= pad;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decrypted;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_checksum - Compute PIN checksum
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Checksum digit
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_checksum(unsigned int pin)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int accum = 0;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pin) {
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += 3 * (pin % 10);
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		accum += pin % 10;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin /= 10;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (10 - accum % 10) % 10;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_pin_valid - Check whether a PIN has a valid checksum
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: Eight digit PIN (i.e., including the checksum digit)
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if checksum digit is valid, or 0 if not
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_pin_valid(unsigned int pin)
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_pin_checksum(pin / 10) == (pin % 10);
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_generate_pin - Generate a random PIN
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Eight digit PIN (i.e., including the checksum digit)
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int wps_generate_pin(void)
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int val;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Generate seven random digits for the PIN */
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct os_time now;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_get_time(&now);
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = os_random() ^ now.sec ^ now.usec;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	val %= 10000000;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Append checksum digit */
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return val * 10 + wps_pin_checksum(val);
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    u16 config_error, u16 error_indication)
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.msg = msg;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.config_error = config_error;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.fail.error_indication = error_indication;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_success_event(struct wps_context *wps)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.enrollee = enrollee;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.pwd_auth_fail.part = part;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_overlap_event(struct wps_context *wps)
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_pbc_timeout_event(struct wps_context *wps)
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_data data;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *plain;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(500);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL) {
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "credential");
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.wps = wps;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.auth_type = wps->auth_types;
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.encr_type = wps->encr_types;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(plain) ||
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred(&data, plain) ||
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return plain;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *data;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN);
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL) {
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "device password attribute");
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->oob_conf.dev_password);
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->oob_conf.dev_password =
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->oob_conf.dev_password == NULL) {
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "device password");
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(data);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(data) ||
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_oob_dev_password(data, wps) ||
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(data, 0, NULL, 0)) {
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "attribute error");
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(data);
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_parse_oob_dev_pwd(struct wps_context *wps,
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct wpabuf *data)
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct oob_conf_data *oob_conf = &wps->oob_conf;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(data, &attr) < 0 ||
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    attr.oob_dev_password == NULL) {
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = attr.oob_dev_password;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	oob_conf->pubkey_hash =
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (oob_conf->pubkey_hash == NULL) {
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "public key hash");
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += WPS_OOB_PUBKEY_HASH_LEN;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->oob_dev_pw_id = WPA_GET_BE16(pos);
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += sizeof(wps->oob_dev_pw_id);
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	oob_conf->dev_password =
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (oob_conf->dev_password == NULL) {
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "device password");
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   wpabuf_size(oob_conf->dev_password)),
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   wpabuf_size(oob_conf->dev_password), pos,
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   WPS_OOB_DEVICE_PASSWORD_LEN);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf msg;
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < attr.num_cred; i++) {
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential local_cred;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr cattr;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&local_cred, 0, sizeof(local_cred));
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]);
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(&msg, &cattr) < 0 ||
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps_process_cred(&cattr, &local_cred)) {
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credential");
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred_cb(wps->cb_ctx, &local_cred);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    int registrar)
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *data;
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret, write_f, oob_method = wps->oob_conf.oob_method;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *oob_priv;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (oob_priv == NULL) {
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (write_f) {
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (oob_method == OOB_METHOD_CRED)
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data = wps_get_oob_cred(wps);
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data = wps_get_oob_dev_pwd(wps);
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = -1;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data = oob_dev->read_func(oob_priv);
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data == NULL)
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = -1;
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else {
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (oob_method == OOB_METHOD_CRED)
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ret = wps_parse_oob_cred(wps, data);
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ret = wps_parse_oob_dev_pwd(wps, data);
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(data);
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	oob_dev->deinit_func(oob_priv);
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct oob_device_data * wps_get_oob_device(char *device_type)
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UFD
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(device_type, "ufd") != NULL)
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &oob_ufd_device_data;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UFD */
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(device_type, "nfc") != NULL)
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &oob_nfc_device_data;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (device_name == NULL)
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC_PN531
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(device_name, "pn531") != NULL)
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return &oob_nfc_pn531_device_data;
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC_PN531 */
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_get_oob_method(char *method)
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(method, "pin-e") != NULL)
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return OOB_METHOD_DEV_PWD_E;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(method, "pin-r") != NULL)
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return OOB_METHOD_DEV_PWD_R;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(method, "cred") != NULL)
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return OOB_METHOD_CRED;
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return OOB_METHOD_UNKNOWN;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *pos;
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* <categ>-<OUI>-<subcateg> */
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(dev_type, atoi(str));
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(str, '-');
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hexstr2bin(pos, &dev_type[2], 4))
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(pos, '-');
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(&dev_type[6], atoi(pos));
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    size_t buf_len)
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  WPA_GET_BE16(&dev_type[6]));
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || (unsigned int) ret >= buf_len)
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[2];
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[2];
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA1_MAC_LEN];
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 nsid[16] = {
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x52, 0x64, 0x80, 0xf8,
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xc9, 0x9b,
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x4b, 0xe5,
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0xa6, 0x55,
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = nsid;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = sizeof(nsid);
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = mac_addr;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = 6;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sha1_vector(2, addr, len, hash);
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(uuid, hash, 16);
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Version: 5 = named-based version using SHA-1 */
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variant specified in RFC 4122 */
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid[8] = 0x80 | (uuid[8] & 0x3f);
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu16 wps_config_methods_str2bin(const char *str)
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods = 0;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (str == NULL) {
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Default to enabling methods based on build configuration */
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_VIRT_DISPLAY;
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UFD
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_USBA;
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UFD */
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_NFC
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods |= WPS_CONFIG_NFC_INTERFACE;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_NFC */
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "usba"))
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_USBA;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ethernet"))
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_ETHERNET;
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "label"))
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_LABEL;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "display"))
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_DISPLAY;
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "ext_nfc_token"))
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "int_nfc_token"))
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_INT_NFC_TOKEN;
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "nfc_interface"))
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_NFC_INTERFACE;
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "push_button"))
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PUSHBUTTON;
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "keypad"))
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_KEYPAD;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_display"))
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_DISPLAY;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_display"))
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_DISPLAY;
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "virtual_push_button"))
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strstr(str, "physical_push_button"))
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return methods;
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, wps->config_error) ||
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
705