wps_common.c revision 04949598a23f501be6eec21697465fd46a28840a
1b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org/*
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * Wi-Fi Protected Setup - common functionality
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
4b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org *
5b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org * This software may be distributed under the terms of the BSD license.
6b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org * See README for more details.
7b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org */
8e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
9e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org#include "includes.h"
10196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org
11248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org#include "common.h"
12ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org#include "crypto/aes_wrap.h"
135de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org#include "crypto/crypto.h"
14b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org#include "crypto/dh_group5.h"
15b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org#include "crypto/sha1.h"
16b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org#include "crypto/sha256.h"
17b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org#include "crypto/random.h"
18b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org#include "wps_i.h"
19b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
20b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
21b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.orgvoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
22b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	     const char *label, u8 *res, size_t res_len)
23b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org{
24b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	u8 i_buf[4], key_bits[4];
25b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	const u8 *addr[4];
26fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	size_t len[4];
27fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	int i, iter;
28fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	u8 hash[SHA256_MAC_LEN], *opos;
29fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	size_t left;
30fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
31fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	WPA_PUT_BE32(key_bits, res_len * 8);
32fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
33fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[0] = i_buf;
34fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[0] = sizeof(i_buf);
35fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[1] = label_prefix;
36fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[1] = label_prefix_len;
37fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[2] = (const u8 *) label;
38fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[2] = os_strlen(label);
39fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[3] = key_bits;
40fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[3] = sizeof(key_bits);
41fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
42fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
43fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	opos = res;
44fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	left = res_len;
45fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
46fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	for (i = 1; i <= iter; i++) {
47fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		WPA_PUT_BE32(i_buf, i);
48fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
49fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		if (i < iter) {
50fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org			os_memcpy(opos, hash, SHA256_MAC_LEN);
51fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org			opos += SHA256_MAC_LEN;
52fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org			left -= SHA256_MAC_LEN;
53fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		} else
54fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org			os_memcpy(opos, hash, left);
55fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	}
56fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org}
57fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
58fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
59fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.orgint wps_derive_keys(struct wps_data *wps)
60fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org{
61fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	struct wpabuf *pubkey, *dh_shared;
62fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
63fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	const u8 *addr[3];
64fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	size_t len[3];
65fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
66fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
67fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	if (wps->dh_privkey == NULL) {
68fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
69fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		return -1;
70fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	}
71fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
72fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
73fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	if (pubkey == NULL) {
74fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
75fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		return -1;
76fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	}
77fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
78fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
79fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
80fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
81fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	dh5_free(wps->dh_ctx);
82fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wps->dh_ctx = NULL;
83fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	dh_shared = wpabuf_zeropad(dh_shared, 192);
84fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	if (dh_shared == NULL) {
85fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
86fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org		return -1;
87fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	}
88fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
89fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	/* Own DH private key is not needed anymore */
90fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpabuf_free(wps->dh_privkey);
91fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wps->dh_privkey = NULL;
92fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
93fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
94fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
95fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	/* DHKey = SHA-256(g^AB mod p) */
96fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[0] = wpabuf_head(dh_shared);
97fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[0] = wpabuf_len(dh_shared);
98fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	sha256_vector(1, addr, len, dhkey);
99fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
100fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	wpabuf_free(dh_shared);
101fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org
102fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
103fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	addr[0] = wps->nonce_e;
104fa7f914e3bacba481b13da5cf2bc4c935567ebc4machenbach@chromium.org	len[0] = WPS_NONCE_LEN;
105b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	addr[1] = wps->mac_addr_e;
106b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	len[1] = ETH_ALEN;
107e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	addr[2] = wps->nonce_r;
108e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	len[2] = WPS_NONCE_LEN;
109e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
110e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
111e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
112e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
113e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		keys, sizeof(keys));
114e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
115e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
116e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
117e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		  WPS_EMSK_LEN);
118e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
119e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
120e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			wps->authkey, WPS_AUTHKEY_LEN);
121e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
122e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
123e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
124e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
125e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	return 0;
126e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org}
127e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
128e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
129e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.orgvoid wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
130e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		    size_t dev_passwd_len)
131e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org{
132e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	u8 hash[SHA256_MAC_LEN];
133e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
134e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
135e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		    (dev_passwd_len + 1) / 2, hash);
136e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
137e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
138e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		    dev_passwd + (dev_passwd_len + 1) / 2,
139e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		    dev_passwd_len / 2, hash);
140e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
141e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
142e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
143e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			      dev_passwd, dev_passwd_len);
144e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
145e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
146e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org}
147e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
148e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
149e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.orgstruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
150e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org					  size_t encr_len)
151e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org{
152e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	struct wpabuf *decrypted;
153e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	const size_t block_size = 16;
154e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	size_t i;
155e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	u8 pad;
156e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	const u8 *pos;
157e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
158e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	/* AES-128-CBC */
159e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
160e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	{
161e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
162e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		return NULL;
163e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	}
164e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
165e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	decrypted = wpabuf_alloc(encr_len - block_size);
166e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	if (decrypted == NULL)
167e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		return NULL;
168e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
169e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
170e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
171e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
172e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org				wpabuf_len(decrypted))) {
173e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		wpabuf_free(decrypted);
174e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		return NULL;
175e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	}
176e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
177e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
178e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			    decrypted);
179e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
180e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
181e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	pad = *pos;
182e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	if (pad > wpabuf_len(decrypted)) {
183e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
184e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		wpabuf_free(decrypted);
185e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		return NULL;
186e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	}
187e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	for (i = 0; i < pad; i++) {
188e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		if (*pos-- != pad) {
189e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
190e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org				   "string");
191e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			wpabuf_free(decrypted);
192e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org			return NULL;
193e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		}
194e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	}
195e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	decrypted->used -= pad;
196e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
197e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	return decrypted;
198e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org}
199e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
200e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
201e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org/**
202e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * wps_pin_checksum - Compute PIN checksum
203e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
204e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * Returns: Checksum digit
205e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org */
206e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.orgunsigned int wps_pin_checksum(unsigned int pin)
207e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org{
208e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	unsigned int accum = 0;
209e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	while (pin) {
210e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		accum += 3 * (pin % 10);
211e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		pin /= 10;
212e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		accum += pin % 10;
213e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		pin /= 10;
214e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	}
215e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
216e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	return (10 - accum % 10) % 10;
217e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org}
218e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
219e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
220e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org/**
221e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * wps_pin_valid - Check whether a PIN has a valid checksum
222e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * @pin: Eight digit PIN (i.e., including the checksum digit)
223e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * Returns: 1 if checksum digit is valid, or 0 if not
224e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org */
225e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.orgunsigned int wps_pin_valid(unsigned int pin)
226e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org{
227e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	return wps_pin_checksum(pin / 10) == (pin % 10);
228e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org}
229e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
230e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
231e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org/**
232e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * wps_generate_pin - Generate a random PIN
233e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org * Returns: Eight digit PIN (i.e., including the checksum digit)
234e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org */
235e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.orgunsigned int wps_generate_pin(void)
236e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org{
237e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	unsigned int val;
238e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org
239e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	/* Generate seven random digits for the PIN */
240e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org	if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
241e20e19efeef112c26d0e63b1e5118e695b42d855machenbach@chromium.org		struct os_time now;
242b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		os_get_time(&now);
243b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		val = os_random() ^ now.sec ^ now.usec;
244b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	}
245b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	val %= 10000000;
246b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
247b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	/* Append checksum digit */
248b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	return val * 10 + wps_pin_checksum(val);
249b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org}
250b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
251b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
252b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.orgint wps_pin_str_valid(const char *pin)
253b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org{
254b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	const char *p;
255b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	size_t len;
256b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
257b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	p = pin;
258b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	while (*p >= '0' && *p <= '9')
259b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		p++;
260b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	if (*p != '\0')
261b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		return 0;
262b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
263b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	len = p - pin;
264b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	return len == 4 || len == 8;
265ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org}
266ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org
267b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
268b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.orgvoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
2696a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org		    u16 config_error, u16 error_indication)
270b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org{
271b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	union wps_event_data data;
2726a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org
273b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	if (wps->event_cb == NULL)
274b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		return;
275b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
2766a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org	os_memset(&data, 0, sizeof(data));
2776a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org	data.fail.msg = msg;
2786a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org	data.fail.config_error = config_error;
2796a4d394882dba70a85567fb90ffd4f428a9eb170machenbach@chromium.org	data.fail.error_indication = error_indication;
280b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
281b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org}
282b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
283b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
284b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.orgvoid wps_success_event(struct wps_context *wps)
285b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org{
286b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	if (wps->event_cb == NULL)
287b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org		return;
288b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
289b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
290e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org}
291e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
292e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
293e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.orgvoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
294e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org{
295e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	union wps_event_data data;
296e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
297e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	if (wps->event_cb == NULL)
298e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org		return;
299e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
300e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	os_memset(&data, 0, sizeof(data));
301e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	data.pwd_auth_fail.enrollee = enrollee;
302e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	data.pwd_auth_fail.part = part;
303e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
304e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org}
305e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
306e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
307e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.orgvoid wps_pbc_overlap_event(struct wps_context *wps)
308e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org{
309e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	if (wps->event_cb == NULL)
310e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org		return;
311e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
312e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
313e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org}
314ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org
315e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
316e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.orgvoid wps_pbc_timeout_event(struct wps_context *wps)
317e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org{
318e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	if (wps->event_cb == NULL)
319e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org		return;
320e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
321e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org	wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
322e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org}
323e31b63e9608909e17e35a3330b0075140af2fe91machenbach@chromium.org
3243ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3253ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org#ifdef CONFIG_WPS_OOB
3263ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
327248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.orgstruct wpabuf * wps_get_oob_cred(struct wps_context *wps)
328248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org{
329248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	struct wps_data data;
330248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	struct wpabuf *plain;
331248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
332248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	plain = wpabuf_alloc(500);
333248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	if (plain == NULL) {
334248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
335248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org			   "credential");
336248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		return NULL;
337248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	}
338248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
339248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	os_memset(&data, 0, sizeof(data));
340248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	data.wps = wps;
341248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	data.auth_type = wps->auth_types;
342248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	data.encr_type = wps->encr_types;
343248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	if (wps_build_version(plain) ||
344248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	    wps_build_cred(&data, plain) ||
345248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	    wps_build_wfa_ext(plain, 0, NULL, 0)) {
346248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		wpabuf_free(plain);
347248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		return NULL;
348248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	}
349248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
350248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	return plain;
351248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org}
352248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
353248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
354248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.orgstruct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
355248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org				       const struct wpabuf *pubkey,
356248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org				       const struct wpabuf *dev_pw)
357248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org{
358248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	struct wpabuf *data;
359248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
360248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	data = wpabuf_alloc(200);
361248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	if (data == NULL)
362248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		return NULL;
363248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org
364248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	if (wps_build_version(data) ||
365248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	    wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
366248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
367248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	    wps_build_wfa_ext(data, 0, NULL, 0)) {
368248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
369248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org			   "token");
370248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		wpabuf_free(data);
371248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org		return NULL;
372248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org	}
3733ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3743ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org	return data;
3753ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org}
3763ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3773ee7a7ed19002e4a0efbf6cdb2a201f21763a80adanno@chromium.org
3785de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgstatic struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
3795de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org{
3805de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	struct wpabuf *data;
3815de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org
3825de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	data = wpabuf_alloc(200);
3835de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	if (data == NULL) {
3845de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3855de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org			   "device password attribute");
3865de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		return NULL;
3875de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	}
3885de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org
3895de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	wpabuf_free(wps->oob_conf.dev_password);
3905de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	wps->oob_conf.dev_password =
3915de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
3925de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	if (wps->oob_conf.dev_password == NULL) {
3935de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
3945de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org			   "device password");
3955de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpabuf_free(data);
3965de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		return NULL;
3975de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	}
3985de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org
3995de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	if (wps_build_version(data) ||
40021d700eedcdd6570eff22ece724b63a5eefe78cbmachenbach@chromium.org	    wps_build_oob_dev_password(data, wps) ||
4015de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	    wps_build_wfa_ext(data, 0, NULL, 0)) {
4025de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
4035de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org			   "attribute error");
4045de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		wpabuf_free(data);
4055de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org		return NULL;
4065de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	}
4075de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org
4085de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org	return data;
4095de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org}
4105de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org
411b67f96038c787a6bd6a835e6c436c82e1b245486machenbach@chromium.org
412static int wps_parse_oob_dev_pwd(struct wps_context *wps,
413				 struct wpabuf *data)
414{
415	struct oob_conf_data *oob_conf = &wps->oob_conf;
416	struct wps_parse_attr attr;
417	const u8 *pos;
418	size_t pw_len;
419
420	if (wps_parse_msg(data, &attr) < 0 ||
421	    attr.oob_dev_password == NULL) {
422		wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
423		return -1;
424	}
425
426	pos = attr.oob_dev_password;
427
428	wpabuf_free(oob_conf->pubkey_hash);
429	oob_conf->pubkey_hash =
430		wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
431	if (oob_conf->pubkey_hash == NULL) {
432		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
433			   "public key hash");
434		return -1;
435	}
436	pos += WPS_OOB_PUBKEY_HASH_LEN;
437
438	wps->oob_dev_pw_id = WPA_GET_BE16(pos);
439	pos += sizeof(wps->oob_dev_pw_id);
440
441	pw_len = attr.oob_dev_password_len - WPS_OOB_PUBKEY_HASH_LEN - 2;
442	oob_conf->dev_password = wpabuf_alloc(pw_len * 2 + 1);
443	if (oob_conf->dev_password == NULL) {
444		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
445			   "device password");
446		return -1;
447	}
448	wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
449					      pw_len * 2 + 1),
450				   pw_len * 2 + 1, pos, pw_len);
451
452	return 0;
453}
454
455
456int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
457{
458	struct wpabuf msg;
459	size_t i;
460
461	for (i = 0; i < attr->num_cred; i++) {
462		struct wps_credential local_cred;
463		struct wps_parse_attr cattr;
464
465		os_memset(&local_cred, 0, sizeof(local_cred));
466		wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
467		if (wps_parse_msg(&msg, &cattr) < 0 ||
468		    wps_process_cred(&cattr, &local_cred)) {
469			wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
470				   "credential");
471			return -1;
472		}
473		wps->cred_cb(wps->cb_ctx, &local_cred);
474	}
475
476	return 0;
477}
478
479
480static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
481{
482	struct wps_parse_attr attr;
483
484	if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
485		wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
486		return -1;
487	}
488
489	return wps_oob_use_cred(wps, &attr);
490}
491
492
493int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
494		    int registrar)
495{
496	struct wpabuf *data;
497	int ret, write_f, oob_method = wps->oob_conf.oob_method;
498	void *oob_priv;
499
500	write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
501
502	oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
503	if (oob_priv == NULL) {
504		wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
505		return -1;
506	}
507
508	if (write_f) {
509		if (oob_method == OOB_METHOD_CRED)
510			data = wps_get_oob_cred(wps);
511		else
512			data = wps_get_oob_dev_pwd(wps);
513
514		ret = 0;
515		if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
516			ret = -1;
517	} else {
518		data = oob_dev->read_func(oob_priv);
519		if (data == NULL)
520			ret = -1;
521		else {
522			if (oob_method == OOB_METHOD_CRED)
523				ret = wps_parse_oob_cred(wps, data);
524			else
525				ret = wps_parse_oob_dev_pwd(wps, data);
526		}
527	}
528	wpabuf_free(data);
529	oob_dev->deinit_func(oob_priv);
530
531	if (ret < 0) {
532		wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
533		return -1;
534	}
535
536	return 0;
537}
538
539
540struct oob_device_data * wps_get_oob_device(char *device_type)
541{
542#ifdef CONFIG_WPS_UFD
543	if (os_strstr(device_type, "ufd") != NULL)
544		return &oob_ufd_device_data;
545#endif /* CONFIG_WPS_UFD */
546#ifdef CONFIG_WPS_NFC
547	if (os_strstr(device_type, "nfc") != NULL)
548		return &oob_nfc_device_data;
549#endif /* CONFIG_WPS_NFC */
550
551	return NULL;
552}
553
554
555#ifdef CONFIG_WPS_NFC
556struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
557{
558	if (device_name == NULL)
559		return NULL;
560#ifdef CONFIG_WPS_NFC_PN531
561	if (os_strstr(device_name, "pn531") != NULL)
562		return &oob_nfc_pn531_device_data;
563#endif /* CONFIG_WPS_NFC_PN531 */
564
565	return NULL;
566}
567#endif /* CONFIG_WPS_NFC */
568
569
570int wps_get_oob_method(char *method)
571{
572	if (os_strstr(method, "pin-e") != NULL)
573		return OOB_METHOD_DEV_PWD_E;
574	if (os_strstr(method, "pin-r") != NULL)
575		return OOB_METHOD_DEV_PWD_R;
576	if (os_strstr(method, "cred") != NULL)
577		return OOB_METHOD_CRED;
578	return OOB_METHOD_UNKNOWN;
579}
580
581#endif /* CONFIG_WPS_OOB */
582
583
584int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
585{
586	const char *pos;
587
588	/* <categ>-<OUI>-<subcateg> */
589	WPA_PUT_BE16(dev_type, atoi(str));
590	pos = os_strchr(str, '-');
591	if (pos == NULL)
592		return -1;
593	pos++;
594	if (hexstr2bin(pos, &dev_type[2], 4))
595		return -1;
596	pos = os_strchr(pos, '-');
597	if (pos == NULL)
598		return -1;
599	pos++;
600	WPA_PUT_BE16(&dev_type[6], atoi(pos));
601
602
603	return 0;
604}
605
606
607char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
608			    size_t buf_len)
609{
610	int ret;
611
612	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
613			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
614			  WPA_GET_BE16(&dev_type[6]));
615	if (ret < 0 || (unsigned int) ret >= buf_len)
616		return NULL;
617
618	return buf;
619}
620
621
622void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
623{
624	const u8 *addr[2];
625	size_t len[2];
626	u8 hash[SHA1_MAC_LEN];
627	u8 nsid[16] = {
628		0x52, 0x64, 0x80, 0xf8,
629		0xc9, 0x9b,
630		0x4b, 0xe5,
631		0xa6, 0x55,
632		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
633	};
634
635	addr[0] = nsid;
636	len[0] = sizeof(nsid);
637	addr[1] = mac_addr;
638	len[1] = 6;
639	sha1_vector(2, addr, len, hash);
640	os_memcpy(uuid, hash, 16);
641
642	/* Version: 5 = named-based version using SHA-1 */
643	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
644
645	/* Variant specified in RFC 4122 */
646	uuid[8] = 0x80 | (uuid[8] & 0x3f);
647}
648
649
650u16 wps_config_methods_str2bin(const char *str)
651{
652	u16 methods = 0;
653
654	if (str == NULL) {
655		/* Default to enabling methods based on build configuration */
656		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
657#ifdef CONFIG_WPS2
658		methods |= WPS_CONFIG_VIRT_DISPLAY;
659#endif /* CONFIG_WPS2 */
660#ifdef CONFIG_WPS_UFD
661		methods |= WPS_CONFIG_USBA;
662#endif /* CONFIG_WPS_UFD */
663#ifdef CONFIG_WPS_NFC
664		methods |= WPS_CONFIG_NFC_INTERFACE;
665#endif /* CONFIG_WPS_NFC */
666	} else {
667		if (os_strstr(str, "usba"))
668			methods |= WPS_CONFIG_USBA;
669		if (os_strstr(str, "ethernet"))
670			methods |= WPS_CONFIG_ETHERNET;
671		if (os_strstr(str, "label"))
672			methods |= WPS_CONFIG_LABEL;
673		if (os_strstr(str, "display"))
674			methods |= WPS_CONFIG_DISPLAY;
675		if (os_strstr(str, "ext_nfc_token"))
676			methods |= WPS_CONFIG_EXT_NFC_TOKEN;
677		if (os_strstr(str, "int_nfc_token"))
678			methods |= WPS_CONFIG_INT_NFC_TOKEN;
679		if (os_strstr(str, "nfc_interface"))
680			methods |= WPS_CONFIG_NFC_INTERFACE;
681		if (os_strstr(str, "push_button"))
682			methods |= WPS_CONFIG_PUSHBUTTON;
683		if (os_strstr(str, "keypad"))
684			methods |= WPS_CONFIG_KEYPAD;
685#ifdef CONFIG_WPS2
686		if (os_strstr(str, "virtual_display"))
687			methods |= WPS_CONFIG_VIRT_DISPLAY;
688		if (os_strstr(str, "physical_display"))
689			methods |= WPS_CONFIG_PHY_DISPLAY;
690		if (os_strstr(str, "virtual_push_button"))
691			methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
692		if (os_strstr(str, "physical_push_button"))
693			methods |= WPS_CONFIG_PHY_PUSHBUTTON;
694#endif /* CONFIG_WPS2 */
695	}
696
697	return methods;
698}
699
700
701struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
702{
703	struct wpabuf *msg;
704
705	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
706
707	msg = wpabuf_alloc(1000);
708	if (msg == NULL)
709		return NULL;
710
711	if (wps_build_version(msg) ||
712	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
713	    wps_build_enrollee_nonce(wps, msg) ||
714	    wps_build_registrar_nonce(wps, msg) ||
715	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
716		wpabuf_free(msg);
717		return NULL;
718	}
719
720	return msg;
721}
722
723
724struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
725{
726	struct wpabuf *msg;
727
728	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
729
730	msg = wpabuf_alloc(1000);
731	if (msg == NULL)
732		return NULL;
733
734	if (wps_build_version(msg) ||
735	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
736	    wps_build_enrollee_nonce(wps, msg) ||
737	    wps_build_registrar_nonce(wps, msg) ||
738	    wps_build_config_error(msg, wps->config_error) ||
739	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
740		wpabuf_free(msg);
741		return NULL;
742	}
743
744	return msg;
745}
746
747
748#ifdef CONFIG_WPS_NFC
749struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
750				  struct wpabuf **privkey,
751				  struct wpabuf **dev_pw)
752{
753	struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
754	void *dh_ctx;
755	u16 val;
756
757	pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
758	if (pw == NULL)
759		return NULL;
760
761	if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
762			     WPS_OOB_DEVICE_PASSWORD_LEN) ||
763	    random_get_bytes((u8 *) &val, sizeof(val))) {
764		wpabuf_free(pw);
765		return NULL;
766	}
767
768	dh_ctx = dh5_init(&priv, &pub);
769	if (dh_ctx == NULL) {
770		wpabuf_free(pw);
771		return NULL;
772	}
773	dh5_free(dh_ctx);
774
775	*id = 0x10 + val % 0xfff0;
776	wpabuf_free(*pubkey);
777	*pubkey = pub;
778	wpabuf_free(*privkey);
779	*privkey = priv;
780	wpabuf_free(*dev_pw);
781	*dev_pw = pw;
782
783	ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
784	if (ndef && ret) {
785		struct wpabuf *tmp;
786		tmp = ndef_build_wifi(ret);
787		wpabuf_free(ret);
788		if (tmp == NULL)
789			return NULL;
790		ret = tmp;
791	}
792
793	return ret;
794}
795#endif /* CONFIG_WPS_NFC */
796