wps_enrollee.c revision b36ed7cd946148d829f311de8fe53ea3ffaaffe3
1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Wi-Fi Protected Setup - Enrollee
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This software may be distributed under the terms of the BSD license.
650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * See README for more details.
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "includes.h"
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "common.h"
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "crypto/crypto.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "crypto/sha256.h"
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "crypto/random.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "wps_i.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "wps_dev_attr.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	u8 state;
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap)
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		state = wps->wps->wps_state;
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	else
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		state = WPS_STATE_NOT_CONFIGURED;
2650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   state);
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_WPS_STATE);
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, 1);
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_u8(msg, state);
3150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return 0;
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
36b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	u8 *hash;
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	const u8 *addr[4];
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	size_t len[4];
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "E-Hash derivation");
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash1");
548393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius	wpabuf_put_be16(msg, ATTR_E_HASH1);
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, SHA256_MAC_LEN);
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	hash = wpabuf_put(msg, SHA256_MAC_LEN);
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[0] = wps->snonce;
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[0] = WPS_SECRET_NONCE_LEN;
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[1] = wps->psk1;
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[1] = WPS_PSK_LEN;
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[2] = wpabuf_head(wps->dh_pubkey_e);
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[2] = wpabuf_len(wps->dh_pubkey_e);
64c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	addr[3] = wpabuf_head(wps->dh_pubkey_r);
65c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	len[3] = wpabuf_len(wps->dh_pubkey_r);
66c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
67103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
68c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
69103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash2");
70c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_E_HASH2);
71c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_be16(msg, SHA256_MAC_LEN);
72103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	hash = wpabuf_put(msg, SHA256_MAC_LEN);
73b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
74c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
75c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	addr[1] = wps->psk2;
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
82c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
83c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
84b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru{
85c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce1");
86b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_E_SNONCE1);
87c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
88c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce2");
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_E_SNONCE2);
97c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
98c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
99c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			WPS_SECRET_NONCE_LEN);
100c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	return 0;
101b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
102c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
103c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic struct wpabuf * wps_build_m1(struct wps_data *wps)
105c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
106c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	struct wpabuf *msg;
107c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	u16 config_methods;
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return NULL;
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		    wps->nonce_e, WPS_NONCE_LEN);
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
11550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	msg = wpabuf_alloc(1000);
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (msg == NULL)
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return NULL;
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	config_methods = wps->wps->config_methods;
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap && !wps->pbc_in_m1 &&
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    (wps->dev_password_len != 0 ||
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	     (config_methods & WPS_CONFIG_DISPLAY))) {
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		/*
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * These are the methods that the AP supports as an Enrollee
125b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * for adding external Registrars, so remove PushButton.
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 *
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * As a workaround for Windows 7 mechanism for probing WPS
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * capabilities from M1, leave PushButton option if no PIN
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * method is available or if WPS configuration enables PBC
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * workaround.
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 */
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		config_methods &= ~WPS_CONFIG_PUSHBUTTON;
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef CONFIG_WPS2
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				    WPS_CONFIG_PHY_PUSHBUTTON);
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* CONFIG_WPS2 */
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
138103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
13950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_build_version(msg) ||
14050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_msg_type(msg, WPS_M1) ||
14150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_uuid_e(msg, wps->uuid_e) ||
14250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_mac_addr(msg, wps->mac_addr_e) ||
14350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_enrollee_nonce(wps, msg) ||
14450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_public_key(wps, msg) ||
14550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_auth_type_flags(wps, msg) ||
14650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_encr_type_flags(wps, msg) ||
14750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_conn_type_flags(wps, msg) ||
14850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_config_methods(msg, config_methods) ||
14950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_wps_state(wps, msg) ||
15050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_device_attrs(&wps->wps->dev, msg) ||
15150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_rf_bands(&wps->wps->dev, msg,
15250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			       wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
15350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_assoc_state(wps, msg) ||
15450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
155b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
15650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_os_version(&wps->wps->dev, msg) ||
15750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
15850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
15950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(msg);
160103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		return NULL;
16150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
16254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
16350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wps->state = RECV_M2;
16450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return msg;
16550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
16650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
167103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic struct wpabuf * wps_build_m3(struct wps_data *wps)
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wpabuf *msg;
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->dev_password == NULL) {
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
176b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return NULL;
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	msg = wpabuf_alloc(1000);
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (msg == NULL)
182b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return NULL;
183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_build_version(msg) ||
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_msg_type(msg, WPS_M3) ||
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_registrar_nonce(wps, msg) ||
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_e_hash(wps, msg) ||
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_authenticator(wps, msg)) {
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(msg);
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return NULL;
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wps->state = RECV_M4;
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return msg;
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic struct wpabuf * wps_build_m5(struct wps_data *wps)
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wpabuf *msg, *plain;
202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	plain = wpabuf_alloc(200);
206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (plain == NULL)
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return NULL;
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	msg = wpabuf_alloc(1000);
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (msg == NULL) {
21150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(plain);
21250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
21350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
21450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
21550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_build_version(msg) ||
21650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_msg_type(msg, WPS_M5) ||
21750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_registrar_nonce(wps, msg) ||
21850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_e_snonce1(wps, plain) ||
21950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_key_wrap_auth(wps, plain) ||
22050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_encr_settings(wps, msg, plain) ||
22150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
22227f654740f2a26ad62a5c155af9199af9e69b889claireho	    wps_build_authenticator(wps, msg)) {
22350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(plain);
22450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(msg);
22550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
22650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
22750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpabuf_free(plain);
22850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
22950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wps->state = RECV_M6;
230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return msg;
231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
236b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_SSID);
238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, wps->wps->ssid_len);
239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   wps->wps->ap_auth_type);
248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, 2);
250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, wps->wps->ap_auth_type);
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
25250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
25350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   wps->wps->ap_encr_type);
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, 2);
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, wps->wps->ap_encr_type);
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) &&
26950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps->wps->network_key_len == 0) {
27050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		char hex[65];
27150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		u8 psk[32];
27250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		/* Generate a random per-device PSK */
27350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if (random_get_bytes(psk, sizeof(psk)) < 0)
27450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			return -1;
27550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
27650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				psk, sizeof(psk));
27750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%u)",
27850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   (unsigned int) wps->new_psk_len * 2);
27950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk));
28050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
28150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_put_be16(msg, sizeof(psk) * 2);
282103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		wpabuf_put_data(msg, hex, sizeof(psk) * 2);
28350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if (wps->wps->registrar) {
28454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius			wps_cb_new_psk(wps->wps->registrar,
28550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				       wps->peer_dev.mac_addr,
28650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				       wps->p2p_dev_addr, psk, sizeof(psk));
287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		}
288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return 0;
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%u)",
292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   (unsigned int) wps->wps->network_key_len);
293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, wps->wps->network_key_len);
295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (AP BSSID)");
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_be16(msg, ETH_ALEN);
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	const u8 *start, *end;
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	int ret;
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap_settings) {
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS:  * AP Settings (pre-configured)");
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_put_data(plain, wps->wps->ap_settings,
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				wps->wps->ap_settings_len);
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return 0;
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings based on current configuration");
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	start = wpabuf_put(plain, 0);
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	ret = wps_build_cred_ssid(wps, plain) ||
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps_build_cred_mac_addr(wps, plain) ||
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps_build_cred_auth_type(wps, plain) ||
32750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps_build_cred_encr_type(wps, plain) ||
32850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps_build_cred_network_key(wps, plain);
32950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	end = wpabuf_put(plain, 0);
33050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
33150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings",
33250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			start, end - start);
33350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
33450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return ret;
33550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
33650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
33750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
33850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic struct wpabuf * wps_build_m7(struct wps_data *wps)
33950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
34050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	struct wpabuf *msg, *plain;
34150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
342103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
34350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
34454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius	plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
34550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (plain == NULL)
34650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
34750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
34850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (msg == NULL) {
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(plain);
35150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
35250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
35350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
35450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_build_version(msg) ||
35550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_msg_type(msg, WPS_M7) ||
35650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_build_registrar_nonce(wps, msg) ||
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_e_snonce2(wps, plain) ||
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_key_wrap_auth(wps, plain) ||
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_encr_settings(wps, msg, plain) ||
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_build_authenticator(wps, msg)) {
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(plain);
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(msg);
36550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_free(plain);
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap && wps->wps->registrar) {
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		/*
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * If the Registrar is only learning our current configuration,
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * it may not continue protocol run to successful completion.
373103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		 * Store information here to make sure it remains available.
37450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		 */
37550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps_device_store(wps->wps->registrar, &wps->peer_dev,
37650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				 wps->uuid_r);
37750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
37850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
37950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wps->state = RECV_M8;
38050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return msg;
38150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
38250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
38350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
38450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
38550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
38650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	struct wpabuf *msg;
38750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
388103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
38950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
39054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius	msg = wpabuf_alloc(1000);
39150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (msg == NULL)
39250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return NULL;
39350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_build_version(msg) ||
3952e615e9896b12236afe0ff2695e8afc2ee73f961claireho	    wps_build_msg_type(msg, WPS_WSC_DONE) ||
3962e615e9896b12236afe0ff2695e8afc2ee73f961claireho	    wps_build_enrollee_nonce(wps, msg) ||
3972e615e9896b12236afe0ff2695e8afc2ee73f961claireho	    wps_build_registrar_nonce(wps, msg) ||
3982e615e9896b12236afe0ff2695e8afc2ee73f961claireho	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
3992e615e9896b12236afe0ff2695e8afc2ee73f961claireho		wpabuf_free(msg);
400b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return NULL;
4012e615e9896b12236afe0ff2695e8afc2ee73f961claireho	}
4022e615e9896b12236afe0ff2695e8afc2ee73f961claireho
4032e615e9896b12236afe0ff2695e8afc2ee73f961claireho	if (wps->wps->ap)
4042e615e9896b12236afe0ff2695e8afc2ee73f961claireho		wps->state = RECV_ACK;
405b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	else {
406b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wps_success_event(wps->wps, wps->peer_dev.mac_addr);
407b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wps->state = WPS_FINISHED;
408b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
409b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	return msg;
410b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
411b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
412b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
4132e615e9896b12236afe0ff2695e8afc2ee73f961clairehostruct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
4142e615e9896b12236afe0ff2695e8afc2ee73f961claireho				     enum wsc_op_code *op_code)
4152e615e9896b12236afe0ff2695e8afc2ee73f961claireho{
4162e615e9896b12236afe0ff2695e8afc2ee73f961claireho	struct wpabuf *msg;
4172e615e9896b12236afe0ff2695e8afc2ee73f961claireho
41854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius	switch (wps->state) {
4192e615e9896b12236afe0ff2695e8afc2ee73f961claireho	case SEND_M1:
42054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		msg = wps_build_m1(wps);
4212e615e9896b12236afe0ff2695e8afc2ee73f961claireho		*op_code = WSC_MSG;
4222e615e9896b12236afe0ff2695e8afc2ee73f961claireho		break;
4232e615e9896b12236afe0ff2695e8afc2ee73f961claireho	case SEND_M3:
4242e615e9896b12236afe0ff2695e8afc2ee73f961claireho		msg = wps_build_m3(wps);
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		*op_code = WSC_MSG;
426c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
427c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case SEND_M5:
428c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		msg = wps_build_m5(wps);
429c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		*op_code = WSC_MSG;
430c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
431c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case SEND_M7:
432c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		msg = wps_build_m7(wps);
433c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		*op_code = WSC_MSG;
434c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
435c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case RECEIVED_M2D:
436c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (wps->wps->ap) {
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			msg = wps_build_wsc_nack(wps);
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			*op_code = WSC_NACK;
43927f654740f2a26ad62a5c155af9199af9e69b889claireho			break;
440c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		}
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		msg = wps_build_wsc_ack(wps);
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		*op_code = WSC_ACK;
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (msg) {
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			/* Another M2/M2D may be received */
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			wps->state = RECV_M2;
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		}
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		break;
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	case SEND_WSC_NACK:
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		msg = wps_build_wsc_nack(wps);
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		*op_code = WSC_NACK;
45127f654740f2a26ad62a5c155af9199af9e69b889claireho		break;
452b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	case WPS_MSG_DONE:
453b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		msg = wps_build_wsc_done(wps);
454b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		*op_code = WSC_Done;
455b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		break;
456b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	default:
457b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
458b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   "a message", wps->state);
459b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		msg = NULL;
460b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		break;
461b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
462b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
463b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (*op_code == WSC_MSG && msg) {
464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		/* Save a copy of the last message for Authenticator derivation
465b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 */
466b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpabuf_free(wps->last_msg);
467b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wps->last_msg = wpabuf_dup(msg);
468b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
469103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
47027f654740f2a26ad62a5c155af9199af9e69b889claireho	return msg;
47154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
47227f654740f2a26ad62a5c155af9199af9e69b889claireho
47327f654740f2a26ad62a5c155af9199af9e69b889claireho
47427f654740f2a26ad62a5c155af9199af9e69b889clairehostatic int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
47527f654740f2a26ad62a5c155af9199af9e69b889claireho{
47627f654740f2a26ad62a5c155af9199af9e69b889claireho	if (r_nonce == NULL) {
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
481c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
482c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
483c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		    wps->nonce_r, WPS_NONCE_LEN);
484c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
485c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	return 0;
486c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
487c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (e_nonce == NULL) {
492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
49327f654740f2a26ad62a5c155af9199af9e69b889claireho		return -1;
494c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
50527f654740f2a26ad62a5c155af9199af9e69b889clairehostatic int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
506b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
507b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (uuid_r == NULL) {
508b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
509b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return -1;
510b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
511b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
512b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
513b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
514b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
515b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	return 0;
516b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
517b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
518b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
519b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
520b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			      size_t pk_len)
521b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
522b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (pk == NULL || pk_len == 0) {
523b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
524b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return -1;
525b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
526103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
52727f654740f2a26ad62a5c155af9199af9e69b889claireho	if (wps->peer_pubkey_hash_set) {
52854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		u8 hash[WPS_HASH_LEN];
52927f654740f2a26ad62a5c155af9199af9e69b889claireho		sha256_vector(1, &pk, &pk_len, hash);
53027f654740f2a26ad62a5c155af9199af9e69b889claireho		if (os_memcmp(hash, wps->peer_pubkey_hash,
53127f654740f2a26ad62a5c155af9199af9e69b889claireho			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
53227f654740f2a26ad62a5c155af9199af9e69b889claireho			wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
53327f654740f2a26ad62a5c155af9199af9e69b889claireho			wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				    pk, pk_len);
535c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
536c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				    "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
537c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
538c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				    wps->peer_pubkey_hash,
539c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				    WPS_OOB_PUBKEY_HASH_LEN);
540c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
541c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			return -1;
542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		}
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_free(wps->dh_pubkey_r);
54627f654740f2a26ad62a5c155af9199af9e69b889claireho	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
547c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->dh_pubkey_r == NULL)
548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_derive_keys(wps) < 0)
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
55827f654740f2a26ad62a5c155af9199af9e69b889claireho{
559b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (r_hash1 == NULL) {
560b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
561b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return -1;
562b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
563b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
564b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
565b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
566b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
567b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	return 0;
568b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
569b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
570b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
571b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
572b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
573b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (r_hash2 == NULL) {
574b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
575103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		return -1;
57627f654740f2a26ad62a5c155af9199af9e69b889claireho	}
57754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
57827f654740f2a26ad62a5c155af9199af9e69b889claireho	os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
57927f654740f2a26ad62a5c155af9199af9e69b889claireho	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
58027f654740f2a26ad62a5c155af9199af9e69b889claireho
58127f654740f2a26ad62a5c155af9199af9e69b889claireho	return 0;
58227f654740f2a26ad62a5c155af9199af9e69b889claireho}
583c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
584c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
585c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
586c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	u8 hash[SHA256_MAC_LEN];
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	const u8 *addr[4];
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	size_t len[4];
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (r_snonce1 == NULL) {
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			WPS_SECRET_NONCE_LEN);
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[0] = r_snonce1;
601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[0] = WPS_SECRET_NONCE_LEN;
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[1] = wps->psk1;
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[1] = WPS_PSK_LEN;
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[2] = wpabuf_head(wps->dh_pubkey_e);
605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[2] = wpabuf_len(wps->dh_pubkey_e);
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	addr[3] = wpabuf_head(wps->dh_pubkey_r);
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	len[3] = wpabuf_len(wps->dh_pubkey_r);
608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "not match with the pre-committed value");
613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr);
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   "half of the device password");
620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return 0;
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	u8 hash[SHA256_MAC_LEN];
628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	const u8 *addr[4];
629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	size_t len[4];
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (r_snonce2 == NULL) {
632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
63327f654740f2a26ad62a5c155af9199af9e69b889claireho		return -1;
63427f654740f2a26ad62a5c155af9199af9e69b889claireho	}
63527f654740f2a26ad62a5c155af9199af9e69b889claireho
63627f654740f2a26ad62a5c155af9199af9e69b889claireho	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
63727f654740f2a26ad62a5c155af9199af9e69b889claireho			WPS_SECRET_NONCE_LEN);
63827f654740f2a26ad62a5c155af9199af9e69b889claireho
63927f654740f2a26ad62a5c155af9199af9e69b889claireho	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
64027f654740f2a26ad62a5c155af9199af9e69b889claireho	addr[0] = r_snonce2;
64127f654740f2a26ad62a5c155af9199af9e69b889claireho	len[0] = WPS_SECRET_NONCE_LEN;
64227f654740f2a26ad62a5c155af9199af9e69b889claireho	addr[1] = wps->psk2;
64327f654740f2a26ad62a5c155af9199af9e69b889claireho	len[1] = WPS_PSK_LEN;
64427f654740f2a26ad62a5c155af9199af9e69b889claireho	addr[2] = wpabuf_head(wps->dh_pubkey_e);
64527f654740f2a26ad62a5c155af9199af9e69b889claireho	len[2] = wpabuf_len(wps->dh_pubkey_e);
64627f654740f2a26ad62a5c155af9199af9e69b889claireho	addr[3] = wpabuf_head(wps->dh_pubkey_r);
64727f654740f2a26ad62a5c155af9199af9e69b889claireho	len[3] = wpabuf_len(wps->dh_pubkey_r);
64827f654740f2a26ad62a5c155af9199af9e69b889claireho	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
64927f654740f2a26ad62a5c155af9199af9e69b889claireho
65027f654740f2a26ad62a5c155af9199af9e69b889claireho	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
65127f654740f2a26ad62a5c155af9199af9e69b889claireho		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
65227f654740f2a26ad62a5c155af9199af9e69b889claireho			   "not match with the pre-committed value");
653103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
65427f654740f2a26ad62a5c155af9199af9e69b889claireho		wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr);
65554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		return -1;
65627f654740f2a26ad62a5c155af9199af9e69b889claireho	}
65727f654740f2a26ad62a5c155af9199af9e69b889claireho
65827f654740f2a26ad62a5c155af9199af9e69b889claireho	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
65927f654740f2a26ad62a5c155af9199af9e69b889claireho		   "half of the device password");
66027f654740f2a26ad62a5c155af9199af9e69b889claireho
66127f654740f2a26ad62a5c155af9199af9e69b889claireho	return 0;
662103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
66350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
66450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
66550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
66650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			      size_t cred_len, int wps2)
66750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
66850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	struct wps_parse_attr attr;
66950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	struct wpabuf msg;
67050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	int ret = 0;
67150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
67250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
67350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	os_memset(&wps->cred, 0, sizeof(wps->cred));
67450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpabuf_set(&msg, cred, cred_len);
67550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_parse_msg(&msg, &attr) < 0 ||
67650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_cred(&attr, &wps->cred))
67750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return -1;
67850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
67950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
68050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    0) {
68127f654740f2a26ad62a5c155af9199af9e69b889claireho		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
68250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   MACSTR ") does not match with own address (" MACSTR
68350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   ")", MAC2STR(wps->cred.mac_addr),
68450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   MAC2STR(wps->wps->dev.mac_addr));
685103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		/*
68650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		 * In theory, this could be consider fatal error, but there are
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * number of deployed implementations using other address here
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * due to unclarity in the specification. For interoperability
689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * reasons, allow this to be processed since we do not really
690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * use the MAC Address information for anything.
691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 */
692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef CONFIG_WPS_STRICT
693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (wps2) {
694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				   "MAC Address in AP Settings");
696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			return -1;
69727f654740f2a26ad62a5c155af9199af9e69b889claireho		}
698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* CONFIG_WPS_STRICT */
699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef CONFIG_WPS2
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (!(wps->cred.encr_type &
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	      (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (wps->cred.encr_type & WPS_ENCR_WEP) {
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			wpa_printf(MSG_INFO, "WPS: Reject Credential "
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				   "due to WEP configuration");
70727f654740f2a26ad62a5c155af9199af9e69b889claireho			wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
708b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			return -2;
709b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		}
710b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
711b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
712b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   "invalid encr_type 0x%x", wps->cred.encr_type);
713b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return -1;
714b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
715b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#endif /* CONFIG_WPS2 */
716b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
717b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (wps->wps->cred_cb) {
718b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wps->cred.cred_attr = cred - 4;
719103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		wps->cred.cred_attr_len = cred_len + 4;
72027f654740f2a26ad62a5c155af9199af9e69b889claireho		ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
72154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		wps->cred.cred_attr = NULL;
72227f654740f2a26ad62a5c155af9199af9e69b889claireho		wps->cred.cred_attr_len = 0;
72327f654740f2a26ad62a5c155af9199af9e69b889claireho	}
72427f654740f2a26ad62a5c155af9199af9e69b889claireho
72527f654740f2a26ad62a5c155af9199af9e69b889claireho	return ret;
72627f654740f2a26ad62a5c155af9199af9e69b889claireho}
727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_process_creds(struct wps_data *wps, const u8 *cred[],
730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			     size_t cred_len[], size_t num_cred, int wps2)
731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	size_t i;
733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	int ok = 0;
734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap)
73627f654740f2a26ad62a5c155af9199af9e69b889claireho		return 0;
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (num_cred == 0) {
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "received");
741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	for (i = 0; i < num_cred; i++) {
74527f654740f2a26ad62a5c155af9199af9e69b889claireho		int res;
746b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
747b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		if (res == 0)
748b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			ok++;
749b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		else if (res == -2)
750b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped");
751b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		else
752b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			return -1;
753b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
754b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
755b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (ok == 0) {
756103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute "
75727f654740f2a26ad62a5c155af9199af9e69b889claireho			   "received");
75854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		return -1;
75927f654740f2a26ad62a5c155af9199af9e69b889claireho	}
76027f654740f2a26ad62a5c155af9199af9e69b889claireho
76127f654740f2a26ad62a5c155af9199af9e69b889claireho	return 0;
76227f654740f2a26ad62a5c155af9199af9e69b889claireho}
76327f654740f2a26ad62a5c155af9199af9e69b889claireho
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int wps_process_ap_settings_e(struct wps_data *wps,
766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				     struct wps_parse_attr *attr,
767c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				     struct wpabuf *attrs, int wps2)
768c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_credential cred;
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
77127f654740f2a26ad62a5c155af9199af9e69b889claireho	if (!wps->wps->ap)
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return 0;
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_process_ap_settings(attr, &cred) < 0)
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return -1;
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		   "Registrar");
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
780103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
78127f654740f2a26ad62a5c155af9199af9e69b889claireho	    0) {
782b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings ("
783b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   MACSTR ") does not match with own address (" MACSTR
784b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   ")", MAC2STR(cred.mac_addr),
785b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   MAC2STR(wps->wps->dev.mac_addr));
786b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		/*
787b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * In theory, this could be consider fatal error, but there are
788b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * number of deployed implementations using other address here
789b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * due to unclarity in the specification. For interoperability
790b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * reasons, allow this to be processed since we do not really
791b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 * use the MAC Address information for anything.
792b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		 */
793103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#ifdef CONFIG_WPS_STRICT
79427f654740f2a26ad62a5c155af9199af9e69b889claireho		if (wps2) {
79554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius			wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
79627f654740f2a26ad62a5c155af9199af9e69b889claireho				   "MAC Address in AP Settings");
79727f654740f2a26ad62a5c155af9199af9e69b889claireho			return -1;
79827f654740f2a26ad62a5c155af9199af9e69b889claireho		}
79927f654740f2a26ad62a5c155af9199af9e69b889claireho#endif /* CONFIG_WPS_STRICT */
800b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
801b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
802c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#ifdef CONFIG_WPS2
803c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
804c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	{
805c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (cred.encr_type & WPS_ENCR_WEP) {
806c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
807c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				   "due to WEP configuration");
808c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
809c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			return -1;
810c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		}
811c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
812c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
813c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   "invalid encr_type 0x%x", cred.encr_type);
814c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return -1;
81527f654740f2a26ad62a5c155af9199af9e69b889claireho	}
81627f654740f2a26ad62a5c155af9199af9e69b889claireho#endif /* CONFIG_WPS2 */
817c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
818b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#ifdef CONFIG_WPS_STRICT
819c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps2) {
82050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
821c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		    WPS_ENCR_TKIP ||
822c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		    (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
823c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		    WPS_AUTH_WPAPSK) {
824c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 "
825c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				   "AP Settings: WPA-Personal/TKIP only");
826c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wps->error_indication =
827b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho				WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED;
828b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			return -1;
829b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		}
830b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
831b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#endif /* CONFIG_WPS_STRICT */
832b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
833b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#ifdef CONFIG_WPS2
834b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
835b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	{
836b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
837b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   "TKIP+AES");
838b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		cred.encr_type |= WPS_ENCR_AES;
839b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
840b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
841b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
842b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	    WPS_AUTH_WPAPSK) {
843b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
844b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			   "WPAPSK+WPA2PSK");
845103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		cred.auth_type |= WPS_AUTH_WPA2PSK;
84627f654740f2a26ad62a5c155af9199af9e69b889claireho	}
84754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#endif /* CONFIG_WPS2 */
84827f654740f2a26ad62a5c155af9199af9e69b889claireho
84927f654740f2a26ad62a5c155af9199af9e69b889claireho	if (wps->wps->cred_cb) {
85027f654740f2a26ad62a5c155af9199af9e69b889claireho		cred.cred_attr = wpabuf_head(attrs);
85127f654740f2a26ad62a5c155af9199af9e69b889claireho		cred.cred_attr_len = wpabuf_len(attrs);
85227f654740f2a26ad62a5c155af9199af9e69b889claireho		wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
85327f654740f2a26ad62a5c155af9199af9e69b889claireho	}
854b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
855b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	return 0;
856b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
857b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
858b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
859b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
860b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
861b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	u16 id;
862b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
863b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (dev_pw_id == NULL) {
864b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
865103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		return -1;
86627f654740f2a26ad62a5c155af9199af9e69b889claireho	}
86754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
86827f654740f2a26ad62a5c155af9199af9e69b889claireho	id = WPA_GET_BE16(dev_pw_id);
86927f654740f2a26ad62a5c155af9199af9e69b889claireho	if (wps->dev_pw_id == id) {
87027f654740f2a26ad62a5c155af9199af9e69b889claireho		wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
87127f654740f2a26ad62a5c155af9199af9e69b889claireho		return 0;
87227f654740f2a26ad62a5c155af9199af9e69b889claireho	}
87327f654740f2a26ad62a5c155af9199af9e69b889claireho
87427f654740f2a26ad62a5c155af9199af9e69b889claireho#ifdef CONFIG_P2P
875c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if ((id == DEV_PW_DEFAULT &&
876c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	     wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) ||
877c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    (id == DEV_PW_REGISTRAR_SPECIFIED &&
878c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	     wps->dev_pw_id == DEV_PW_DEFAULT)) {
879c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		/*
88027f654740f2a26ad62a5c155af9199af9e69b889claireho		 * Common P2P use cases indicate whether the PIN is from the
881b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		 * client or GO using Device Password Id in M1/M2 in a way that
882c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		 * does not look fully compliant with WSC specification. Anyway,
88350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		 * this is deployed and needs to be allowed, so ignore changes
884c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		 * between Registrar-Specified and Default PIN.
885c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		 */
886c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID "
88727f654740f2a26ad62a5c155af9199af9e69b889claireho			   "change");
888b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return 0;
889b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
890b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#endif /* CONFIG_P2P */
891b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
892b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
893b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		   "ID from %u to %u", wps->dev_pw_id, id);
894b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
895103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
89627f654740f2a26ad62a5c155af9199af9e69b889claireho		wpa_printf(MSG_DEBUG,
89754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius			   "WPS: Workaround - ignore PBC-to-PIN change");
89827f654740f2a26ad62a5c155af9199af9e69b889claireho		return 0;
89927f654740f2a26ad62a5c155af9199af9e69b889claireho	}
900c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
901c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
902c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
903c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		os_free(wps->dev_password);
904c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->dev_pw_id = wps->alt_dev_pw_id;
905c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->dev_password = wps->alt_dev_password;
906c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->dev_password_len = wps->alt_dev_password_len;
907c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->alt_dev_password = NULL;
90827f654740f2a26ad62a5c155af9199af9e69b889claireho		wps->alt_dev_password_len = 0;
909b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		return 0;
910c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
91150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
912c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	return -1;
913c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
914c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
915c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
916b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic enum wps_process_res wps_process_m2(struct wps_data *wps,
917b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho					   const struct wpabuf *msg,
918b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho					   struct wps_parse_attr *attr)
919b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
920b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	wpa_printf(MSG_DEBUG, "WPS: Received M2");
921b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
922b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (wps->state != RECV_M2) {
923b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
924103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius			   "receiving M2", wps->state);
92527f654740f2a26ad62a5c155af9199af9e69b889claireho		wps->state = SEND_WSC_NACK;
92654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		return WPS_CONTINUE;
92727f654740f2a26ad62a5c155af9199af9e69b889claireho	}
92827f654740f2a26ad62a5c155af9199af9e69b889claireho
92927f654740f2a26ad62a5c155af9199af9e69b889claireho	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
93027f654740f2a26ad62a5c155af9199af9e69b889claireho	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
931c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    wps_process_uuid_r(wps, attr->uuid_r) ||
932c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    wps_process_dev_pw_id(wps, attr->dev_password_id)) {
933c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
934c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_CONTINUE;
935c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
936c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
937c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	/*
938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	 * Stop here on an AP as an Enrollee if AP Setup is locked unless the
939c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	 * special locked mode is used to allow protocol run up to M7 in order
94050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	 * to support external Registrars that only learn the current AP
941c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	 * configuration without changing it.
942c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	 */
943c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->wps->ap &&
944c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) ||
945c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	     wps->dev_password == NULL)) {
946c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
947c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   "registration of a new Registrar");
948c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->config_error = WPS_CFG_SETUP_LOCKED;
949c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
950c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_CONTINUE;
951c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
952c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
953c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
954c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    wps_process_authenticator(wps, attr->authenticator, msg) ||
955c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    wps_process_device_attrs(&wps->peer_dev, attr)) {
956c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
957c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_CONTINUE;
958c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
959c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
960c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#ifdef CONFIG_WPS_NFC
961c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->peer_pubkey_hash_set) {
962b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		struct wpabuf *decrypted;
963c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		struct wps_parse_attr eattr;
96450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
965c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
966c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru						      attr->encr_settings_len);
967c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (decrypted == NULL) {
968c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt "
969c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				   "Encrypted Settings attribute");
970c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wps->state = SEND_WSC_NACK;
971c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			return WPS_CONTINUE;
972c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		}
973c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
974c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted "
975c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   "Settings attribute");
976c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (wps_parse_msg(decrypted, &eattr) < 0 ||
977b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		    wps_process_key_wrap_auth(wps, decrypted,
978c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru					      eattr.key_wrap_auth) ||
97950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		    wps_process_creds(wps, eattr.cred, eattr.cred_len,
980c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				      eattr.num_cred, attr->version2 != NULL)) {
981c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wpabuf_free(decrypted);
982c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			wps->state = SEND_WSC_NACK;
983c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			return WPS_CONTINUE;
984c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		}
985c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpabuf_free(decrypted);
986c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
987c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->state = WPS_MSG_DONE;
988c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_CONTINUE;
989c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
990c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#endif /* CONFIG_WPS_NFC */
991c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
992c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wps->state = SEND_M3;
993c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	return WPS_CONTINUE;
994c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
995b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
996c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
99750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic enum wps_process_res wps_process_m2d(struct wps_data *wps,
998c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru					    struct wps_parse_attr *attr)
999c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
1000c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received M2D");
1001c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1002c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->state != RECV_M2) {
1003c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
1004c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   "receiving M2D", wps->state);
1005c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1006c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_CONTINUE;
1007c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1008c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1009c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
1010b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			  attr->manufacturer, attr->manufacturer_len);
1011c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
101250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			  attr->model_name, attr->model_name_len);
1013c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
1014c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			  attr->model_number, attr->model_number_len);
1015c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
1016c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			  attr->serial_number, attr->serial_number_len);
1017c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
1018c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			  attr->dev_name, attr->dev_name_len);
1019c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1020c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (wps->wps->event_cb) {
1021c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		union wps_event_data data;
1022c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		struct wps_event_m2d *m2d = &data.m2d;
1023c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		os_memset(&data, 0, sizeof(data));
1024c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (attr->config_methods)
1025b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			m2d->config_methods =
1026c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				WPA_GET_BE16(attr->config_methods);
102750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		m2d->manufacturer = attr->manufacturer;
1028c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->manufacturer_len = attr->manufacturer_len;
1029c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->model_name = attr->model_name;
1030c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->model_name_len = attr->model_name_len;
1031c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->model_number = attr->model_number;
1032c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->model_number_len = attr->model_number_len;
1033c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		m2d->serial_number = attr->serial_number;
1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		m2d->serial_number_len = attr->serial_number_len;
1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		m2d->dev_name = attr->dev_name;
1036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		m2d->dev_name_len = attr->dev_name_len;
1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		m2d->primary_dev_type = attr->primary_dev_type;
1038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (attr->config_error)
1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			m2d->config_error =
1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				WPA_GET_BE16(attr->config_error);
1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (attr->dev_password_id)
1042b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			m2d->dev_password_id =
1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				WPA_GET_BE16(attr->dev_password_id);
1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
1045b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wps->state = RECEIVED_M2D;
1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return WPS_CONTINUE;
1049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1051b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic enum wps_process_res wps_process_m4(struct wps_data *wps,
1053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   const struct wpabuf *msg,
1054b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   struct wps_parse_attr *attr)
1055b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1056b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wpabuf *decrypted;
1057b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_parse_attr eattr;
1058b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1059b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received M4");
1060b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1061b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->state != RECV_M4) {
1062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "receiving M4", wps->state);
1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1066b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
106750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
106850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
106950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_authenticator(wps, attr->authenticator, msg) ||
107050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_r_hash1(wps, attr->r_hash1) ||
107150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_r_hash2(wps, attr->r_hash2)) {
107250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
107350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
107450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
107550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
107650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
107750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho					      attr->encr_settings_len);
107850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (decrypted == NULL) {
107950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
108050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   "Settings attribute");
108150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
108250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
108350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
108450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
108550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
1086103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		wpabuf_free(decrypted);
108750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
108854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		return WPS_CONTINUE;
108950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
109050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
109150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
109250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		   "attribute");
1093b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_parse_msg(decrypted, &eattr) < 0 ||
1094b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
1095b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_process_r_snonce1(wps, eattr.r_snonce1)) {
1096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(decrypted);
1097b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1098b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1099b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_free(decrypted);
1101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wps->state = SEND_M5;
1103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return WPS_CONTINUE;
1104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic enum wps_process_res wps_process_m6(struct wps_data *wps,
1108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   const struct wpabuf *msg,
1109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   struct wps_parse_attr *attr)
1110b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho{
1111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wpabuf *decrypted;
1112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_parse_attr eattr;
1113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received M6");
1115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->state != RECV_M6) {
1117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
1118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "receiving M6", wps->state);
1119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
1124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_process_authenticator(wps, attr->authenticator, msg)) {
1125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
112650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
112750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
112850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
112950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
113050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho					      attr->encr_settings_len);
113150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (decrypted == NULL) {
113250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
113350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   "Settings attribute");
113450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
113550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
113650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
113750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
113850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
113950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(decrypted);
114050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
114150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
114250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
114350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
114450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
1145103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		   "attribute");
114650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_parse_msg(decrypted, &eattr) < 0 ||
114754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
114850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_r_snonce2(wps, eattr.r_snonce2)) {
114950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(decrypted);
115050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
115150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
115250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
1153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpabuf_free(decrypted);
1154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap)
1156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
1157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				   NULL);
1158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wps->state = SEND_M7;
1160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return WPS_CONTINUE;
1161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic enum wps_process_res wps_process_m8(struct wps_data *wps,
1165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   const struct wpabuf *msg,
1166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					   struct wps_parse_attr *attr)
1167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wpabuf *decrypted;
1169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_parse_attr eattr;
1170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received M8");
1172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->state != RECV_M8) {
1174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
1175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "receiving M8", wps->state);
1176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
1181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    wps_process_authenticator(wps, attr->authenticator, msg)) {
1182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps->wps->ap && wps->wps->ap_setup_locked) {
1187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		/*
1188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * Stop here if special ap_setup_locked == 2 mode allowed the
1189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * protocol to continue beyond M2. This allows ER to learn the
1190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 * current AP settings without changing them.
1191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 */
1192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
1193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   "registration of a new Registrar");
1194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->config_error = WPS_CFG_SETUP_LOCKED;
1195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
1200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru					      attr->encr_settings_len);
120150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (decrypted == NULL) {
120250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
120350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   "Settings attribute");
120450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
120550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
120650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
120750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
120850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_validate_m8_encr(decrypted, wps->wps->ap,
120950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				 attr->version2 != NULL) < 0) {
121050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(decrypted);
121150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
121250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
121350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
121450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
121550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
121650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		   "attribute");
121750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_parse_msg(decrypted, &eattr) < 0 ||
121850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
121950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_creds(wps, eattr.cred, eattr.cred_len,
122050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			      eattr.num_cred, attr->version2 != NULL) ||
122150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    wps_process_ap_settings_e(wps, &eattr, decrypted,
122250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				      attr->version2 != NULL)) {
122350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpabuf_free(decrypted);
122450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = SEND_WSC_NACK;
122550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_CONTINUE;
122650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
1227103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius	wpabuf_free(decrypted);
122850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
122954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius	wps->state = WPS_MSG_DONE;
123050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return WPS_CONTINUE;
123150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
123250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
123350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
1234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
1235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru						const struct wpabuf *msg)
1236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_parse_attr attr;
1238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	enum wps_process_res ret = WPS_CONTINUE;
1239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
1241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_parse_msg(msg, &attr) < 0)
1243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (attr.enrollee_nonce == NULL ||
1246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
1247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
1248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (attr.msg_type == NULL) {
1252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
1253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->state = SEND_WSC_NACK;
1254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_CONTINUE;
1255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	switch (*attr.msg_type) {
1258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	case WPS_M2:
1259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (wps_validate_m2(msg) < 0)
1260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			return WPS_FAILURE;
1261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		ret = wps_process_m2(wps, msg, &attr);
1262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		break;
1263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	case WPS_M2D:
1264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (wps_validate_m2d(msg) < 0)
126550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			return WPS_FAILURE;
126650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		ret = wps_process_m2d(wps, &attr);
126750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		break;
126850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	case WPS_M4:
126950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if (wps_validate_m4(msg) < 0)
127050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			return WPS_FAILURE;
127150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		ret = wps_process_m4(wps, msg, &attr);
127250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
127350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			wps_fail_event(wps->wps, WPS_M4, wps->config_error,
127450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				       wps->error_indication,
127550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				       wps->peer_dev.mac_addr);
1276b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		break;
1277b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	case WPS_M6:
1278b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		if (wps_validate_m6(msg) < 0)
127950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			return WPS_FAILURE;
128050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		ret = wps_process_m6(wps, msg, &attr);
1281103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
128250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			wps_fail_event(wps->wps, WPS_M6, wps->config_error,
128354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius				       wps->error_indication,
128450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho				       wps->peer_dev.mac_addr);
128527f654740f2a26ad62a5c155af9199af9e69b889claireho		break;
128627f654740f2a26ad62a5c155af9199af9e69b889claireho	case WPS_M8:
1287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (wps_validate_m8(msg) < 0)
1288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			return WPS_FAILURE;
1289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		ret = wps_process_m8(wps, msg, &attr);
1290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
1291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			wps_fail_event(wps->wps, WPS_M8, wps->config_error,
1292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru				       wps->error_indication,
1293b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho				       wps->peer_dev.mac_addr);
1294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		break;
129550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	default:
1296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
1297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   *attr.msg_type);
1298b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		return WPS_FAILURE;
1299b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	}
1300b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1301b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	/*
1302b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 * Save a copy of the last message for Authenticator derivation if we
1303b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 * are continuing. However, skip M2D since it is not authenticated and
1304b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 * neither is the ACK/NACK response frame. This allows the possibly
1305b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 * following M2 to be processed correctly by using the previously sent
1306b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 * M1 in Authenticator derivation.
1307b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	 */
1308b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho	if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
1309b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho		/* Save a copy of the last message for Authenticator derivation
1310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		 */
1311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpabuf_free(wps->last_msg);
1312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wps->last_msg = wpabuf_dup(msg);
1313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	return ret;
1316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
1320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru						const struct wpabuf *msg)
1321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	struct wps_parse_attr attr;
1323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
1325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (wps_parse_msg(msg, &attr) < 0)
1327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (attr.msg_type == NULL) {
1330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
1331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (*attr.msg_type != WPS_WSC_ACK) {
1335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
1336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru			   *attr.msg_type);
1337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (attr.registrar_nonce == NULL ||
1341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
1342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	{
1343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
1344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru		return WPS_FAILURE;
1345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	}
1346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru	if (attr.enrollee_nonce == NULL ||
134850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
134950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
135050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_FAILURE;
135150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
135250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
135350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps->state == RECV_ACK && wps->wps->ap) {
135450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
135550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			   "completed successfully");
135650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps_success_event(wps->wps, wps->peer_dev.mac_addr);
135750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wps->state = WPS_FINISHED;
135850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_DONE;
135950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
136050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
136150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	return WPS_FAILURE;
136250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
136350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
136450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
136550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
136650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho						 const struct wpabuf *msg)
136750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho{
136850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	struct wps_parse_attr attr;
136950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	u16 config_error;
137050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
137150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
1372103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
137350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (wps_parse_msg(msg, &attr) < 0)
137454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius		return WPS_FAILURE;
137550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
137650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (attr.msg_type == NULL) {
137750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
137850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		return WPS_FAILURE;
137950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	}
1380c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1381c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (*attr.msg_type != WPS_WSC_NACK) {
1382c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
1383c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   *attr.msg_type);
1384c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_FAILURE;
1385c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1386c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1387c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (attr.registrar_nonce == NULL ||
1388c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
1389c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	{
1390c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
1391c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
1392c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			    attr.registrar_nonce, WPS_NONCE_LEN);
1393c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
1394c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			    wps->nonce_r, WPS_NONCE_LEN);
1395c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_FAILURE;
1396c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1397c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1398c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (attr.enrollee_nonce == NULL ||
1399c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
1400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
1401c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
140250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho			    attr.enrollee_nonce, WPS_NONCE_LEN);
1403c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
1404c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			    wps->nonce_e, WPS_NONCE_LEN);
1405c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_FAILURE;
1406c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1407c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1408c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	if (attr.config_error == NULL) {
1409c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
1410c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			   "in WSC_NACK");
1411c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_FAILURE;
1412c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1413c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru	config_error = WPA_GET_BE16(attr.config_error);
1415c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
141650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho		   "Configuration Error %d", config_error);
1417c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1418c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	switch (wps->state) {
1419c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case RECV_M4:
1420c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps_fail_event(wps->wps, WPS_M3, config_error,
1421b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho			       wps->error_indication, wps->peer_dev.mac_addr);
1422c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
1423c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case RECV_M6:
1424c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps_fail_event(wps->wps, WPS_M5, config_error,
1425c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			       wps->error_indication, wps->peer_dev.mac_addr);
1426c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
1427c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case RECV_M8:
1428c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wps_fail_event(wps->wps, WPS_M7, config_error,
1429c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			       wps->error_indication, wps->peer_dev.mac_addr);
1430c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
1431c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	default:
1432c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		break;
1433c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
143459d709d503bab6e2b61931737e662dd293b40578ccornelius
143559d709d503bab6e2b61931737e662dd293b40578ccornelius	/* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
1436c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	 * Enrollee is Authenticator */
1437c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wps->state = SEND_WSC_NACK;
1438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1439c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	return WPS_FAILURE;
144050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
1441c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1442c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1443c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruenum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
1444c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru					      enum wsc_op_code op_code,
1445c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru					      const struct wpabuf *msg)
1446c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
1447c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1448c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
1449c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		   "op_code=%d)",
1450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru		   (unsigned long) wpabuf_len(msg), op_code);
1451c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
145250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho	if (op_code == WSC_UPnP) {
1453c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		/* Determine the OpCode based on message type attribute */
1454c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		struct wps_parse_attr attr;
1455c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
1456c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			if (*attr.msg_type == WPS_WSC_ACK)
1457c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				op_code = WSC_ACK;
1458c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			else if (*attr.msg_type == WPS_WSC_NACK)
1459c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru				op_code = WSC_NACK;
1460c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		}
1461c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1462c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1463c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	switch (op_code) {
1464c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case WSC_MSG:
1465c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case WSC_UPnP:
1466c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return wps_process_wsc_msg(wps, msg);
1467c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case WSC_ACK:
1468c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (wps_validate_wsc_ack(msg) < 0)
1469c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru			return WPS_FAILURE;
1470c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return wps_process_wsc_ack(wps, msg);
1471c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	case WSC_NACK:
1472c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		if (wps_validate_wsc_nack(msg) < 0)
1473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru			return WPS_FAILURE;
1474c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return wps_process_wsc_nack(wps, msg);
1475c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	default:
1476c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
1477c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru		return WPS_FAILURE;
1478c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru	}
1479c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1480c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru