xref: /freebsd/contrib/wpa/src/wps/wps_enrollee.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * Wi-Fi Protected Setup - Enrollee
339beb93cSSam Leffler  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
539beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
639beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
739beb93cSSam Leffler  * published by the Free Software Foundation.
839beb93cSSam Leffler  *
939beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
1039beb93cSSam Leffler  * license.
1139beb93cSSam Leffler  *
1239beb93cSSam Leffler  * See README and COPYING for more details.
1339beb93cSSam Leffler  */
1439beb93cSSam Leffler 
1539beb93cSSam Leffler #include "includes.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #include "common.h"
1839beb93cSSam Leffler #include "sha256.h"
1939beb93cSSam Leffler #include "wps_i.h"
2039beb93cSSam Leffler #include "wps_dev_attr.h"
2139beb93cSSam Leffler 
2239beb93cSSam Leffler 
2339beb93cSSam Leffler static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
2439beb93cSSam Leffler {
2539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
2639beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
2739beb93cSSam Leffler 	wpabuf_put_be16(msg, ETH_ALEN);
2839beb93cSSam Leffler 	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
2939beb93cSSam Leffler 	return 0;
3039beb93cSSam Leffler }
3139beb93cSSam Leffler 
3239beb93cSSam Leffler 
3339beb93cSSam Leffler static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
3439beb93cSSam Leffler {
3539beb93cSSam Leffler 	u8 state;
3639beb93cSSam Leffler 	if (wps->wps->ap)
3739beb93cSSam Leffler 		state = wps->wps->wps_state;
3839beb93cSSam Leffler 	else
3939beb93cSSam Leffler 		state = WPS_STATE_NOT_CONFIGURED;
4039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
4139beb93cSSam Leffler 		   state);
4239beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_WPS_STATE);
4339beb93cSSam Leffler 	wpabuf_put_be16(msg, 1);
4439beb93cSSam Leffler 	wpabuf_put_u8(msg, WPS_STATE_NOT_CONFIGURED);
4539beb93cSSam Leffler 	return 0;
4639beb93cSSam Leffler }
4739beb93cSSam Leffler 
4839beb93cSSam Leffler 
4939beb93cSSam Leffler static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
5039beb93cSSam Leffler {
5139beb93cSSam Leffler 	u8 *hash;
5239beb93cSSam Leffler 	const u8 *addr[4];
5339beb93cSSam Leffler 	size_t len[4];
5439beb93cSSam Leffler 
5539beb93cSSam Leffler 	if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
5639beb93cSSam Leffler 		return -1;
5739beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
5839beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
5939beb93cSSam Leffler 		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
6039beb93cSSam Leffler 
6139beb93cSSam Leffler 	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
6239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
6339beb93cSSam Leffler 			   "E-Hash derivation");
6439beb93cSSam Leffler 		return -1;
6539beb93cSSam Leffler 	}
6639beb93cSSam Leffler 
6739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash1");
6839beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_E_HASH1);
6939beb93cSSam Leffler 	wpabuf_put_be16(msg, SHA256_MAC_LEN);
7039beb93cSSam Leffler 	hash = wpabuf_put(msg, SHA256_MAC_LEN);
7139beb93cSSam Leffler 	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
7239beb93cSSam Leffler 	addr[0] = wps->snonce;
7339beb93cSSam Leffler 	len[0] = WPS_SECRET_NONCE_LEN;
7439beb93cSSam Leffler 	addr[1] = wps->psk1;
7539beb93cSSam Leffler 	len[1] = WPS_PSK_LEN;
7639beb93cSSam Leffler 	addr[2] = wpabuf_head(wps->dh_pubkey_e);
7739beb93cSSam Leffler 	len[2] = wpabuf_len(wps->dh_pubkey_e);
7839beb93cSSam Leffler 	addr[3] = wpabuf_head(wps->dh_pubkey_r);
7939beb93cSSam Leffler 	len[3] = wpabuf_len(wps->dh_pubkey_r);
8039beb93cSSam Leffler 	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
8139beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
8239beb93cSSam Leffler 
8339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash2");
8439beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_E_HASH2);
8539beb93cSSam Leffler 	wpabuf_put_be16(msg, SHA256_MAC_LEN);
8639beb93cSSam Leffler 	hash = wpabuf_put(msg, SHA256_MAC_LEN);
8739beb93cSSam Leffler 	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
8839beb93cSSam Leffler 	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
8939beb93cSSam Leffler 	addr[1] = wps->psk2;
9039beb93cSSam Leffler 	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
9139beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
9239beb93cSSam Leffler 
9339beb93cSSam Leffler 	return 0;
9439beb93cSSam Leffler }
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 
9739beb93cSSam Leffler static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
9839beb93cSSam Leffler {
9939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce1");
10039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_E_SNONCE1);
10139beb93cSSam Leffler 	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
10239beb93cSSam Leffler 	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
10339beb93cSSam Leffler 	return 0;
10439beb93cSSam Leffler }
10539beb93cSSam Leffler 
10639beb93cSSam Leffler 
10739beb93cSSam Leffler static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
10839beb93cSSam Leffler {
10939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce2");
11039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_E_SNONCE2);
11139beb93cSSam Leffler 	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
11239beb93cSSam Leffler 	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
11339beb93cSSam Leffler 			WPS_SECRET_NONCE_LEN);
11439beb93cSSam Leffler 	return 0;
11539beb93cSSam Leffler }
11639beb93cSSam Leffler 
11739beb93cSSam Leffler 
11839beb93cSSam Leffler static struct wpabuf * wps_build_m1(struct wps_data *wps)
11939beb93cSSam Leffler {
12039beb93cSSam Leffler 	struct wpabuf *msg;
12139beb93cSSam Leffler 	u16 methods;
12239beb93cSSam Leffler 
12339beb93cSSam Leffler 	if (os_get_random(wps->nonce_e, WPS_NONCE_LEN) < 0)
12439beb93cSSam Leffler 		return NULL;
12539beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
12639beb93cSSam Leffler 		    wps->nonce_e, WPS_NONCE_LEN);
12739beb93cSSam Leffler 
12839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
12939beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
13039beb93cSSam Leffler 	if (msg == NULL)
13139beb93cSSam Leffler 		return NULL;
13239beb93cSSam Leffler 
13339beb93cSSam Leffler 	methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
13439beb93cSSam Leffler 	if (wps->pbc)
13539beb93cSSam Leffler 		methods |= WPS_CONFIG_PUSHBUTTON;
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 	if (wps_build_version(msg) ||
13839beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_M1) ||
13939beb93cSSam Leffler 	    wps_build_uuid_e(msg, wps->uuid_e) ||
14039beb93cSSam Leffler 	    wps_build_mac_addr(wps, msg) ||
14139beb93cSSam Leffler 	    wps_build_enrollee_nonce(wps, msg) ||
14239beb93cSSam Leffler 	    wps_build_public_key(wps, msg) ||
14339beb93cSSam Leffler 	    wps_build_auth_type_flags(wps, msg) ||
14439beb93cSSam Leffler 	    wps_build_encr_type_flags(wps, msg) ||
14539beb93cSSam Leffler 	    wps_build_conn_type_flags(wps, msg) ||
14639beb93cSSam Leffler 	    wps_build_config_methods(msg, methods) ||
14739beb93cSSam Leffler 	    wps_build_wps_state(wps, msg) ||
14839beb93cSSam Leffler 	    wps_build_device_attrs(&wps->wps->dev, msg) ||
14939beb93cSSam Leffler 	    wps_build_rf_bands(&wps->wps->dev, msg) ||
15039beb93cSSam Leffler 	    wps_build_assoc_state(wps, msg) ||
15139beb93cSSam Leffler 	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
15239beb93cSSam Leffler 	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
15339beb93cSSam Leffler 	    wps_build_os_version(&wps->wps->dev, msg)) {
15439beb93cSSam Leffler 		wpabuf_free(msg);
15539beb93cSSam Leffler 		return NULL;
15639beb93cSSam Leffler 	}
15739beb93cSSam Leffler 
15839beb93cSSam Leffler 	wps->state = RECV_M2;
15939beb93cSSam Leffler 	return msg;
16039beb93cSSam Leffler }
16139beb93cSSam Leffler 
16239beb93cSSam Leffler 
16339beb93cSSam Leffler static struct wpabuf * wps_build_m3(struct wps_data *wps)
16439beb93cSSam Leffler {
16539beb93cSSam Leffler 	struct wpabuf *msg;
16639beb93cSSam Leffler 
16739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
16839beb93cSSam Leffler 
16939beb93cSSam Leffler 	if (wps->dev_password == NULL) {
17039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
17139beb93cSSam Leffler 		return NULL;
17239beb93cSSam Leffler 	}
17339beb93cSSam Leffler 	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
17439beb93cSSam Leffler 
17539beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
17639beb93cSSam Leffler 	if (msg == NULL)
17739beb93cSSam Leffler 		return NULL;
17839beb93cSSam Leffler 
17939beb93cSSam Leffler 	if (wps_build_version(msg) ||
18039beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_M3) ||
18139beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg) ||
18239beb93cSSam Leffler 	    wps_build_e_hash(wps, msg) ||
18339beb93cSSam Leffler 	    wps_build_authenticator(wps, msg)) {
18439beb93cSSam Leffler 		wpabuf_free(msg);
18539beb93cSSam Leffler 		return NULL;
18639beb93cSSam Leffler 	}
18739beb93cSSam Leffler 
18839beb93cSSam Leffler 	wps->state = RECV_M4;
18939beb93cSSam Leffler 	return msg;
19039beb93cSSam Leffler }
19139beb93cSSam Leffler 
19239beb93cSSam Leffler 
19339beb93cSSam Leffler static struct wpabuf * wps_build_m5(struct wps_data *wps)
19439beb93cSSam Leffler {
19539beb93cSSam Leffler 	struct wpabuf *msg, *plain;
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
19839beb93cSSam Leffler 
19939beb93cSSam Leffler 	plain = wpabuf_alloc(200);
20039beb93cSSam Leffler 	if (plain == NULL)
20139beb93cSSam Leffler 		return NULL;
20239beb93cSSam Leffler 
20339beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
20439beb93cSSam Leffler 	if (msg == NULL) {
20539beb93cSSam Leffler 		wpabuf_free(plain);
20639beb93cSSam Leffler 		return NULL;
20739beb93cSSam Leffler 	}
20839beb93cSSam Leffler 
20939beb93cSSam Leffler 	if (wps_build_version(msg) ||
21039beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_M5) ||
21139beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg) ||
21239beb93cSSam Leffler 	    wps_build_e_snonce1(wps, plain) ||
21339beb93cSSam Leffler 	    wps_build_key_wrap_auth(wps, plain) ||
21439beb93cSSam Leffler 	    wps_build_encr_settings(wps, msg, plain) ||
21539beb93cSSam Leffler 	    wps_build_authenticator(wps, msg)) {
21639beb93cSSam Leffler 		wpabuf_free(plain);
21739beb93cSSam Leffler 		wpabuf_free(msg);
21839beb93cSSam Leffler 		return NULL;
21939beb93cSSam Leffler 	}
22039beb93cSSam Leffler 	wpabuf_free(plain);
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 	wps->state = RECV_M6;
22339beb93cSSam Leffler 	return msg;
22439beb93cSSam Leffler }
22539beb93cSSam Leffler 
22639beb93cSSam Leffler 
22739beb93cSSam Leffler static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
22839beb93cSSam Leffler {
22939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
23039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_SSID);
23139beb93cSSam Leffler 	wpabuf_put_be16(msg, wps->wps->ssid_len);
23239beb93cSSam Leffler 	wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
23339beb93cSSam Leffler 	return 0;
23439beb93cSSam Leffler }
23539beb93cSSam Leffler 
23639beb93cSSam Leffler 
23739beb93cSSam Leffler static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
23839beb93cSSam Leffler {
23939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type");
24039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
24139beb93cSSam Leffler 	wpabuf_put_be16(msg, 2);
24239beb93cSSam Leffler 	wpabuf_put_be16(msg, wps->wps->auth_types);
24339beb93cSSam Leffler 	return 0;
24439beb93cSSam Leffler }
24539beb93cSSam Leffler 
24639beb93cSSam Leffler 
24739beb93cSSam Leffler static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
24839beb93cSSam Leffler {
24939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type");
25039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
25139beb93cSSam Leffler 	wpabuf_put_be16(msg, 2);
25239beb93cSSam Leffler 	wpabuf_put_be16(msg, wps->wps->encr_types);
25339beb93cSSam Leffler 	return 0;
25439beb93cSSam Leffler }
25539beb93cSSam Leffler 
25639beb93cSSam Leffler 
25739beb93cSSam Leffler static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
25839beb93cSSam Leffler {
25939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
26039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
26139beb93cSSam Leffler 	wpabuf_put_be16(msg, wps->wps->network_key_len);
26239beb93cSSam Leffler 	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
26339beb93cSSam Leffler 	return 0;
26439beb93cSSam Leffler }
26539beb93cSSam Leffler 
26639beb93cSSam Leffler 
26739beb93cSSam Leffler static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
26839beb93cSSam Leffler {
26939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (AP BSSID)");
27039beb93cSSam Leffler 	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
27139beb93cSSam Leffler 	wpabuf_put_be16(msg, ETH_ALEN);
27239beb93cSSam Leffler 	wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
27339beb93cSSam Leffler 	return 0;
27439beb93cSSam Leffler }
27539beb93cSSam Leffler 
27639beb93cSSam Leffler 
27739beb93cSSam Leffler static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
27839beb93cSSam Leffler {
27939beb93cSSam Leffler 	if (wps->wps->ap_settings) {
28039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS:  * AP Settings (pre-configured)");
28139beb93cSSam Leffler 		wpabuf_put_data(plain, wps->wps->ap_settings,
28239beb93cSSam Leffler 				wps->wps->ap_settings_len);
28339beb93cSSam Leffler 		return 0;
28439beb93cSSam Leffler 	}
28539beb93cSSam Leffler 
28639beb93cSSam Leffler 	return wps_build_cred_ssid(wps, plain) ||
28739beb93cSSam Leffler 		wps_build_cred_mac_addr(wps, plain) ||
28839beb93cSSam Leffler 		wps_build_cred_auth_type(wps, plain) ||
28939beb93cSSam Leffler 		wps_build_cred_encr_type(wps, plain) ||
29039beb93cSSam Leffler 		wps_build_cred_network_key(wps, plain);
29139beb93cSSam Leffler }
29239beb93cSSam Leffler 
29339beb93cSSam Leffler 
29439beb93cSSam Leffler static struct wpabuf * wps_build_m7(struct wps_data *wps)
29539beb93cSSam Leffler {
29639beb93cSSam Leffler 	struct wpabuf *msg, *plain;
29739beb93cSSam Leffler 
29839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
29939beb93cSSam Leffler 
30039beb93cSSam Leffler 	plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
30139beb93cSSam Leffler 	if (plain == NULL)
30239beb93cSSam Leffler 		return NULL;
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
30539beb93cSSam Leffler 	if (msg == NULL) {
30639beb93cSSam Leffler 		wpabuf_free(plain);
30739beb93cSSam Leffler 		return NULL;
30839beb93cSSam Leffler 	}
30939beb93cSSam Leffler 
31039beb93cSSam Leffler 	if (wps_build_version(msg) ||
31139beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_M7) ||
31239beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg) ||
31339beb93cSSam Leffler 	    wps_build_e_snonce2(wps, plain) ||
31439beb93cSSam Leffler 	    (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
31539beb93cSSam Leffler 	    wps_build_key_wrap_auth(wps, plain) ||
31639beb93cSSam Leffler 	    wps_build_encr_settings(wps, msg, plain) ||
31739beb93cSSam Leffler 	    wps_build_authenticator(wps, msg)) {
31839beb93cSSam Leffler 		wpabuf_free(plain);
31939beb93cSSam Leffler 		wpabuf_free(msg);
32039beb93cSSam Leffler 		return NULL;
32139beb93cSSam Leffler 	}
32239beb93cSSam Leffler 	wpabuf_free(plain);
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 	wps->state = RECV_M8;
32539beb93cSSam Leffler 	return msg;
32639beb93cSSam Leffler }
32739beb93cSSam Leffler 
32839beb93cSSam Leffler 
32939beb93cSSam Leffler static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
33039beb93cSSam Leffler {
33139beb93cSSam Leffler 	struct wpabuf *msg;
33239beb93cSSam Leffler 
33339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
33439beb93cSSam Leffler 
33539beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
33639beb93cSSam Leffler 	if (msg == NULL)
33739beb93cSSam Leffler 		return NULL;
33839beb93cSSam Leffler 
33939beb93cSSam Leffler 	if (wps_build_version(msg) ||
34039beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_WSC_DONE) ||
34139beb93cSSam Leffler 	    wps_build_enrollee_nonce(wps, msg) ||
34239beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg)) {
34339beb93cSSam Leffler 		wpabuf_free(msg);
34439beb93cSSam Leffler 		return NULL;
34539beb93cSSam Leffler 	}
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 	if (wps->wps->ap)
34839beb93cSSam Leffler 		wps->state = RECV_ACK;
34939beb93cSSam Leffler 	else {
35039beb93cSSam Leffler 		wps_success_event(wps->wps);
35139beb93cSSam Leffler 		wps->state = WPS_FINISHED;
35239beb93cSSam Leffler 	}
35339beb93cSSam Leffler 	return msg;
35439beb93cSSam Leffler }
35539beb93cSSam Leffler 
35639beb93cSSam Leffler 
35739beb93cSSam Leffler static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
35839beb93cSSam Leffler {
35939beb93cSSam Leffler 	struct wpabuf *msg;
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
36239beb93cSSam Leffler 
36339beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
36439beb93cSSam Leffler 	if (msg == NULL)
36539beb93cSSam Leffler 		return NULL;
36639beb93cSSam Leffler 
36739beb93cSSam Leffler 	if (wps_build_version(msg) ||
36839beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
36939beb93cSSam Leffler 	    wps_build_enrollee_nonce(wps, msg) ||
37039beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg)) {
37139beb93cSSam Leffler 		wpabuf_free(msg);
37239beb93cSSam Leffler 		return NULL;
37339beb93cSSam Leffler 	}
37439beb93cSSam Leffler 
37539beb93cSSam Leffler 	return msg;
37639beb93cSSam Leffler }
37739beb93cSSam Leffler 
37839beb93cSSam Leffler 
37939beb93cSSam Leffler static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
38039beb93cSSam Leffler {
38139beb93cSSam Leffler 	struct wpabuf *msg;
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
38439beb93cSSam Leffler 
38539beb93cSSam Leffler 	msg = wpabuf_alloc(1000);
38639beb93cSSam Leffler 	if (msg == NULL)
38739beb93cSSam Leffler 		return NULL;
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 	if (wps_build_version(msg) ||
39039beb93cSSam Leffler 	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
39139beb93cSSam Leffler 	    wps_build_enrollee_nonce(wps, msg) ||
39239beb93cSSam Leffler 	    wps_build_registrar_nonce(wps, msg) ||
39339beb93cSSam Leffler 	    wps_build_config_error(msg, wps->config_error)) {
39439beb93cSSam Leffler 		wpabuf_free(msg);
39539beb93cSSam Leffler 		return NULL;
39639beb93cSSam Leffler 	}
39739beb93cSSam Leffler 
39839beb93cSSam Leffler 	return msg;
39939beb93cSSam Leffler }
40039beb93cSSam Leffler 
40139beb93cSSam Leffler 
40239beb93cSSam Leffler struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
40339beb93cSSam Leffler 				     enum wsc_op_code *op_code)
40439beb93cSSam Leffler {
40539beb93cSSam Leffler 	struct wpabuf *msg;
40639beb93cSSam Leffler 
40739beb93cSSam Leffler 	switch (wps->state) {
40839beb93cSSam Leffler 	case SEND_M1:
40939beb93cSSam Leffler 		msg = wps_build_m1(wps);
41039beb93cSSam Leffler 		*op_code = WSC_MSG;
41139beb93cSSam Leffler 		break;
41239beb93cSSam Leffler 	case SEND_M3:
41339beb93cSSam Leffler 		msg = wps_build_m3(wps);
41439beb93cSSam Leffler 		*op_code = WSC_MSG;
41539beb93cSSam Leffler 		break;
41639beb93cSSam Leffler 	case SEND_M5:
41739beb93cSSam Leffler 		msg = wps_build_m5(wps);
41839beb93cSSam Leffler 		*op_code = WSC_MSG;
41939beb93cSSam Leffler 		break;
42039beb93cSSam Leffler 	case SEND_M7:
42139beb93cSSam Leffler 		msg = wps_build_m7(wps);
42239beb93cSSam Leffler 		*op_code = WSC_MSG;
42339beb93cSSam Leffler 		break;
42439beb93cSSam Leffler 	case RECEIVED_M2D:
42539beb93cSSam Leffler 		if (wps->wps->ap) {
42639beb93cSSam Leffler 			msg = wps_build_wsc_nack(wps);
42739beb93cSSam Leffler 			*op_code = WSC_NACK;
42839beb93cSSam Leffler 			break;
42939beb93cSSam Leffler 		}
43039beb93cSSam Leffler 		msg = wps_build_wsc_ack(wps);
43139beb93cSSam Leffler 		*op_code = WSC_ACK;
43239beb93cSSam Leffler 		if (msg) {
43339beb93cSSam Leffler 			/* Another M2/M2D may be received */
43439beb93cSSam Leffler 			wps->state = RECV_M2;
43539beb93cSSam Leffler 		}
43639beb93cSSam Leffler 		break;
43739beb93cSSam Leffler 	case SEND_WSC_NACK:
43839beb93cSSam Leffler 		msg = wps_build_wsc_nack(wps);
43939beb93cSSam Leffler 		*op_code = WSC_NACK;
44039beb93cSSam Leffler 		break;
44139beb93cSSam Leffler 	case WPS_MSG_DONE:
44239beb93cSSam Leffler 		msg = wps_build_wsc_done(wps);
44339beb93cSSam Leffler 		*op_code = WSC_Done;
44439beb93cSSam Leffler 		break;
44539beb93cSSam Leffler 	default:
44639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
44739beb93cSSam Leffler 			   "a message", wps->state);
44839beb93cSSam Leffler 		msg = NULL;
44939beb93cSSam Leffler 		break;
45039beb93cSSam Leffler 	}
45139beb93cSSam Leffler 
45239beb93cSSam Leffler 	if (*op_code == WSC_MSG && msg) {
45339beb93cSSam Leffler 		/* Save a copy of the last message for Authenticator derivation
45439beb93cSSam Leffler 		 */
45539beb93cSSam Leffler 		wpabuf_free(wps->last_msg);
45639beb93cSSam Leffler 		wps->last_msg = wpabuf_dup(msg);
45739beb93cSSam Leffler 	}
45839beb93cSSam Leffler 
45939beb93cSSam Leffler 	return msg;
46039beb93cSSam Leffler }
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 
46339beb93cSSam Leffler static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
46439beb93cSSam Leffler {
46539beb93cSSam Leffler 	if (r_nonce == NULL) {
46639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
46739beb93cSSam Leffler 		return -1;
46839beb93cSSam Leffler 	}
46939beb93cSSam Leffler 
47039beb93cSSam Leffler 	os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
47139beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
47239beb93cSSam Leffler 		    wps->nonce_r, WPS_NONCE_LEN);
47339beb93cSSam Leffler 
47439beb93cSSam Leffler 	return 0;
47539beb93cSSam Leffler }
47639beb93cSSam Leffler 
47739beb93cSSam Leffler 
47839beb93cSSam Leffler static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
47939beb93cSSam Leffler {
48039beb93cSSam Leffler 	if (e_nonce == NULL) {
48139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
48239beb93cSSam Leffler 		return -1;
48339beb93cSSam Leffler 	}
48439beb93cSSam Leffler 
48539beb93cSSam Leffler 	if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
48639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
48739beb93cSSam Leffler 		return -1;
48839beb93cSSam Leffler 	}
48939beb93cSSam Leffler 
49039beb93cSSam Leffler 	return 0;
49139beb93cSSam Leffler }
49239beb93cSSam Leffler 
49339beb93cSSam Leffler 
49439beb93cSSam Leffler static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
49539beb93cSSam Leffler {
49639beb93cSSam Leffler 	if (uuid_r == NULL) {
49739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
49839beb93cSSam Leffler 		return -1;
49939beb93cSSam Leffler 	}
50039beb93cSSam Leffler 
50139beb93cSSam Leffler 	os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
50239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
50339beb93cSSam Leffler 
50439beb93cSSam Leffler 	return 0;
50539beb93cSSam Leffler }
50639beb93cSSam Leffler 
50739beb93cSSam Leffler 
50839beb93cSSam Leffler static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
50939beb93cSSam Leffler 			      size_t pk_len)
51039beb93cSSam Leffler {
51139beb93cSSam Leffler 	if (pk == NULL || pk_len == 0) {
51239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
51339beb93cSSam Leffler 		return -1;
51439beb93cSSam Leffler 	}
51539beb93cSSam Leffler 
51639beb93cSSam Leffler 	wpabuf_free(wps->dh_pubkey_r);
51739beb93cSSam Leffler 	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
51839beb93cSSam Leffler 	if (wps->dh_pubkey_r == NULL)
51939beb93cSSam Leffler 		return -1;
52039beb93cSSam Leffler 
52139beb93cSSam Leffler 	if (wps_derive_keys(wps) < 0)
52239beb93cSSam Leffler 		return -1;
52339beb93cSSam Leffler 
52439beb93cSSam Leffler 	if (wps->request_type == WPS_REQ_WLAN_MANAGER_REGISTRAR &&
52539beb93cSSam Leffler 	    wps_derive_mgmt_keys(wps) < 0)
52639beb93cSSam Leffler 		return -1;
52739beb93cSSam Leffler 
52839beb93cSSam Leffler 	return 0;
52939beb93cSSam Leffler }
53039beb93cSSam Leffler 
53139beb93cSSam Leffler 
53239beb93cSSam Leffler static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
53339beb93cSSam Leffler {
53439beb93cSSam Leffler 	if (r_hash1 == NULL) {
53539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
53639beb93cSSam Leffler 		return -1;
53739beb93cSSam Leffler 	}
53839beb93cSSam Leffler 
53939beb93cSSam Leffler 	os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
54039beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
54139beb93cSSam Leffler 
54239beb93cSSam Leffler 	return 0;
54339beb93cSSam Leffler }
54439beb93cSSam Leffler 
54539beb93cSSam Leffler 
54639beb93cSSam Leffler static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
54739beb93cSSam Leffler {
54839beb93cSSam Leffler 	if (r_hash2 == NULL) {
54939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
55039beb93cSSam Leffler 		return -1;
55139beb93cSSam Leffler 	}
55239beb93cSSam Leffler 
55339beb93cSSam Leffler 	os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
55439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
55539beb93cSSam Leffler 
55639beb93cSSam Leffler 	return 0;
55739beb93cSSam Leffler }
55839beb93cSSam Leffler 
55939beb93cSSam Leffler 
56039beb93cSSam Leffler static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
56139beb93cSSam Leffler {
56239beb93cSSam Leffler 	u8 hash[SHA256_MAC_LEN];
56339beb93cSSam Leffler 	const u8 *addr[4];
56439beb93cSSam Leffler 	size_t len[4];
56539beb93cSSam Leffler 
56639beb93cSSam Leffler 	if (r_snonce1 == NULL) {
56739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
56839beb93cSSam Leffler 		return -1;
56939beb93cSSam Leffler 	}
57039beb93cSSam Leffler 
57139beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
57239beb93cSSam Leffler 			WPS_SECRET_NONCE_LEN);
57339beb93cSSam Leffler 
57439beb93cSSam Leffler 	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
57539beb93cSSam Leffler 	addr[0] = r_snonce1;
57639beb93cSSam Leffler 	len[0] = WPS_SECRET_NONCE_LEN;
57739beb93cSSam Leffler 	addr[1] = wps->psk1;
57839beb93cSSam Leffler 	len[1] = WPS_PSK_LEN;
57939beb93cSSam Leffler 	addr[2] = wpabuf_head(wps->dh_pubkey_e);
58039beb93cSSam Leffler 	len[2] = wpabuf_len(wps->dh_pubkey_e);
58139beb93cSSam Leffler 	addr[3] = wpabuf_head(wps->dh_pubkey_r);
58239beb93cSSam Leffler 	len[3] = wpabuf_len(wps->dh_pubkey_r);
58339beb93cSSam Leffler 	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
58439beb93cSSam Leffler 
58539beb93cSSam Leffler 	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
58639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
58739beb93cSSam Leffler 			   "not match with the pre-committed value");
58839beb93cSSam Leffler 		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
58939beb93cSSam Leffler 		wps_pwd_auth_fail_event(wps->wps, 1, 1);
59039beb93cSSam Leffler 		return -1;
59139beb93cSSam Leffler 	}
59239beb93cSSam Leffler 
59339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
59439beb93cSSam Leffler 		   "half of the device password");
59539beb93cSSam Leffler 
59639beb93cSSam Leffler 	return 0;
59739beb93cSSam Leffler }
59839beb93cSSam Leffler 
59939beb93cSSam Leffler 
60039beb93cSSam Leffler static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
60139beb93cSSam Leffler {
60239beb93cSSam Leffler 	u8 hash[SHA256_MAC_LEN];
60339beb93cSSam Leffler 	const u8 *addr[4];
60439beb93cSSam Leffler 	size_t len[4];
60539beb93cSSam Leffler 
60639beb93cSSam Leffler 	if (r_snonce2 == NULL) {
60739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
60839beb93cSSam Leffler 		return -1;
60939beb93cSSam Leffler 	}
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
61239beb93cSSam Leffler 			WPS_SECRET_NONCE_LEN);
61339beb93cSSam Leffler 
61439beb93cSSam Leffler 	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
61539beb93cSSam Leffler 	addr[0] = r_snonce2;
61639beb93cSSam Leffler 	len[0] = WPS_SECRET_NONCE_LEN;
61739beb93cSSam Leffler 	addr[1] = wps->psk2;
61839beb93cSSam Leffler 	len[1] = WPS_PSK_LEN;
61939beb93cSSam Leffler 	addr[2] = wpabuf_head(wps->dh_pubkey_e);
62039beb93cSSam Leffler 	len[2] = wpabuf_len(wps->dh_pubkey_e);
62139beb93cSSam Leffler 	addr[3] = wpabuf_head(wps->dh_pubkey_r);
62239beb93cSSam Leffler 	len[3] = wpabuf_len(wps->dh_pubkey_r);
62339beb93cSSam Leffler 	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
62439beb93cSSam Leffler 
62539beb93cSSam Leffler 	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
62639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
62739beb93cSSam Leffler 			   "not match with the pre-committed value");
62839beb93cSSam Leffler 		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
62939beb93cSSam Leffler 		wps_pwd_auth_fail_event(wps->wps, 1, 2);
63039beb93cSSam Leffler 		return -1;
63139beb93cSSam Leffler 	}
63239beb93cSSam Leffler 
63339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
63439beb93cSSam Leffler 		   "half of the device password");
63539beb93cSSam Leffler 
63639beb93cSSam Leffler 	return 0;
63739beb93cSSam Leffler }
63839beb93cSSam Leffler 
63939beb93cSSam Leffler 
64039beb93cSSam Leffler static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
64139beb93cSSam Leffler 			      size_t cred_len)
64239beb93cSSam Leffler {
64339beb93cSSam Leffler 	struct wps_parse_attr attr;
64439beb93cSSam Leffler 	struct wpabuf msg;
64539beb93cSSam Leffler 
64639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
64739beb93cSSam Leffler 	os_memset(&wps->cred, 0, sizeof(wps->cred));
64839beb93cSSam Leffler 	wpabuf_set(&msg, cred, cred_len);
64939beb93cSSam Leffler 	if (wps_parse_msg(&msg, &attr) < 0 ||
65039beb93cSSam Leffler 	    wps_process_cred(&attr, &wps->cred))
65139beb93cSSam Leffler 		return -1;
65239beb93cSSam Leffler 
65339beb93cSSam Leffler 	if (wps->wps->cred_cb) {
65439beb93cSSam Leffler 		wps->cred.cred_attr = cred - 4;
65539beb93cSSam Leffler 		wps->cred.cred_attr_len = cred_len + 4;
65639beb93cSSam Leffler 		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
65739beb93cSSam Leffler 		wps->cred.cred_attr = NULL;
65839beb93cSSam Leffler 		wps->cred.cred_attr_len = 0;
65939beb93cSSam Leffler 	}
66039beb93cSSam Leffler 
66139beb93cSSam Leffler 	return 0;
66239beb93cSSam Leffler }
66339beb93cSSam Leffler 
66439beb93cSSam Leffler 
66539beb93cSSam Leffler static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
66639beb93cSSam Leffler 			     size_t cred_len[], size_t num_cred)
66739beb93cSSam Leffler {
66839beb93cSSam Leffler 	size_t i;
66939beb93cSSam Leffler 
67039beb93cSSam Leffler 	if (wps->wps->ap)
67139beb93cSSam Leffler 		return 0;
67239beb93cSSam Leffler 
67339beb93cSSam Leffler 	if (num_cred == 0) {
67439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
67539beb93cSSam Leffler 			   "received");
67639beb93cSSam Leffler 		return -1;
67739beb93cSSam Leffler 	}
67839beb93cSSam Leffler 
67939beb93cSSam Leffler 	for (i = 0; i < num_cred; i++) {
68039beb93cSSam Leffler 		if (wps_process_cred_e(wps, cred[i], cred_len[i]))
68139beb93cSSam Leffler 			return -1;
68239beb93cSSam Leffler 	}
68339beb93cSSam Leffler 
68439beb93cSSam Leffler 	return 0;
68539beb93cSSam Leffler }
68639beb93cSSam Leffler 
68739beb93cSSam Leffler 
68839beb93cSSam Leffler static int wps_process_ap_settings_e(struct wps_data *wps,
68939beb93cSSam Leffler 				     struct wps_parse_attr *attr,
69039beb93cSSam Leffler 				     struct wpabuf *attrs)
69139beb93cSSam Leffler {
69239beb93cSSam Leffler 	struct wps_credential cred;
69339beb93cSSam Leffler 
69439beb93cSSam Leffler 	if (!wps->wps->ap)
69539beb93cSSam Leffler 		return 0;
69639beb93cSSam Leffler 
69739beb93cSSam Leffler 	if (wps_process_ap_settings(attr, &cred) < 0)
69839beb93cSSam Leffler 		return -1;
69939beb93cSSam Leffler 
70039beb93cSSam Leffler 	wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
70139beb93cSSam Leffler 		   "Registrar");
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 	if (wps->wps->cred_cb) {
70439beb93cSSam Leffler 		cred.cred_attr = wpabuf_head(attrs);
70539beb93cSSam Leffler 		cred.cred_attr_len = wpabuf_len(attrs);
70639beb93cSSam Leffler 		wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
70739beb93cSSam Leffler 	}
70839beb93cSSam Leffler 
70939beb93cSSam Leffler 	return 0;
71039beb93cSSam Leffler }
71139beb93cSSam Leffler 
71239beb93cSSam Leffler 
71339beb93cSSam Leffler static enum wps_process_res wps_process_m2(struct wps_data *wps,
71439beb93cSSam Leffler 					   const struct wpabuf *msg,
71539beb93cSSam Leffler 					   struct wps_parse_attr *attr)
71639beb93cSSam Leffler {
71739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received M2");
71839beb93cSSam Leffler 
71939beb93cSSam Leffler 	if (wps->state != RECV_M2) {
72039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
72139beb93cSSam Leffler 			   "receiving M2", wps->state);
72239beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
72339beb93cSSam Leffler 		return WPS_CONTINUE;
72439beb93cSSam Leffler 	}
72539beb93cSSam Leffler 
72639beb93cSSam Leffler 	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
72739beb93cSSam Leffler 	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
72839beb93cSSam Leffler 	    wps_process_uuid_r(wps, attr->uuid_r) ||
72939beb93cSSam Leffler 	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
73039beb93cSSam Leffler 	    wps_process_authenticator(wps, attr->authenticator, msg)) {
73139beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
73239beb93cSSam Leffler 		return WPS_CONTINUE;
73339beb93cSSam Leffler 	}
73439beb93cSSam Leffler 
73539beb93cSSam Leffler 	if (wps->wps->ap && wps->wps->ap_setup_locked) {
73639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
73739beb93cSSam Leffler 			   "registration of a new Registrar");
73839beb93cSSam Leffler 		wps->config_error = WPS_CFG_SETUP_LOCKED;
73939beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
74039beb93cSSam Leffler 		return WPS_CONTINUE;
74139beb93cSSam Leffler 	}
74239beb93cSSam Leffler 
74339beb93cSSam Leffler 	wps->state = SEND_M3;
74439beb93cSSam Leffler 	return WPS_CONTINUE;
74539beb93cSSam Leffler }
74639beb93cSSam Leffler 
74739beb93cSSam Leffler 
74839beb93cSSam Leffler static enum wps_process_res wps_process_m2d(struct wps_data *wps,
74939beb93cSSam Leffler 					    struct wps_parse_attr *attr)
75039beb93cSSam Leffler {
75139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received M2D");
75239beb93cSSam Leffler 
75339beb93cSSam Leffler 	if (wps->state != RECV_M2) {
75439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
75539beb93cSSam Leffler 			   "receiving M2D", wps->state);
75639beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
75739beb93cSSam Leffler 		return WPS_CONTINUE;
75839beb93cSSam Leffler 	}
75939beb93cSSam Leffler 
76039beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
76139beb93cSSam Leffler 			  attr->manufacturer, attr->manufacturer_len);
76239beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
76339beb93cSSam Leffler 			  attr->model_name, attr->model_name_len);
76439beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
76539beb93cSSam Leffler 			  attr->model_number, attr->model_number_len);
76639beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
76739beb93cSSam Leffler 			  attr->serial_number, attr->serial_number_len);
76839beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
76939beb93cSSam Leffler 			  attr->dev_name, attr->dev_name_len);
77039beb93cSSam Leffler 
77139beb93cSSam Leffler 	if (wps->wps->event_cb) {
77239beb93cSSam Leffler 		union wps_event_data data;
77339beb93cSSam Leffler 		struct wps_event_m2d *m2d = &data.m2d;
77439beb93cSSam Leffler 		os_memset(&data, 0, sizeof(data));
77539beb93cSSam Leffler 		if (attr->config_methods)
77639beb93cSSam Leffler 			m2d->config_methods =
77739beb93cSSam Leffler 				WPA_GET_BE16(attr->config_methods);
77839beb93cSSam Leffler 		m2d->manufacturer = attr->manufacturer;
77939beb93cSSam Leffler 		m2d->manufacturer_len = attr->manufacturer_len;
78039beb93cSSam Leffler 		m2d->model_name = attr->model_name;
78139beb93cSSam Leffler 		m2d->model_name_len = attr->model_name_len;
78239beb93cSSam Leffler 		m2d->model_number = attr->model_number;
78339beb93cSSam Leffler 		m2d->model_number_len = attr->model_number_len;
78439beb93cSSam Leffler 		m2d->serial_number = attr->serial_number;
78539beb93cSSam Leffler 		m2d->serial_number_len = attr->serial_number_len;
78639beb93cSSam Leffler 		m2d->dev_name = attr->dev_name;
78739beb93cSSam Leffler 		m2d->dev_name_len = attr->dev_name_len;
78839beb93cSSam Leffler 		m2d->primary_dev_type = attr->primary_dev_type;
78939beb93cSSam Leffler 		if (attr->config_error)
79039beb93cSSam Leffler 			m2d->config_error =
79139beb93cSSam Leffler 				WPA_GET_BE16(attr->config_error);
79239beb93cSSam Leffler 		if (attr->dev_password_id)
79339beb93cSSam Leffler 			m2d->dev_password_id =
79439beb93cSSam Leffler 				WPA_GET_BE16(attr->dev_password_id);
79539beb93cSSam Leffler 		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
79639beb93cSSam Leffler 	}
79739beb93cSSam Leffler 
79839beb93cSSam Leffler 	wps->state = RECEIVED_M2D;
79939beb93cSSam Leffler 	return WPS_CONTINUE;
80039beb93cSSam Leffler }
80139beb93cSSam Leffler 
80239beb93cSSam Leffler 
80339beb93cSSam Leffler static enum wps_process_res wps_process_m4(struct wps_data *wps,
80439beb93cSSam Leffler 					   const struct wpabuf *msg,
80539beb93cSSam Leffler 					   struct wps_parse_attr *attr)
80639beb93cSSam Leffler {
80739beb93cSSam Leffler 	struct wpabuf *decrypted;
80839beb93cSSam Leffler 	struct wps_parse_attr eattr;
80939beb93cSSam Leffler 
81039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received M4");
81139beb93cSSam Leffler 
81239beb93cSSam Leffler 	if (wps->state != RECV_M4) {
81339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
81439beb93cSSam Leffler 			   "receiving M4", wps->state);
81539beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
81639beb93cSSam Leffler 		return WPS_CONTINUE;
81739beb93cSSam Leffler 	}
81839beb93cSSam Leffler 
81939beb93cSSam Leffler 	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
82039beb93cSSam Leffler 	    wps_process_authenticator(wps, attr->authenticator, msg) ||
82139beb93cSSam Leffler 	    wps_process_r_hash1(wps, attr->r_hash1) ||
82239beb93cSSam Leffler 	    wps_process_r_hash2(wps, attr->r_hash2)) {
82339beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
82439beb93cSSam Leffler 		return WPS_CONTINUE;
82539beb93cSSam Leffler 	}
82639beb93cSSam Leffler 
82739beb93cSSam Leffler 	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
82839beb93cSSam Leffler 					      attr->encr_settings_len);
82939beb93cSSam Leffler 	if (decrypted == NULL) {
83039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
83139beb93cSSam Leffler 			   "Settings attribute");
83239beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
83339beb93cSSam Leffler 		return WPS_CONTINUE;
83439beb93cSSam Leffler 	}
83539beb93cSSam Leffler 
83639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
83739beb93cSSam Leffler 		   "attribute");
83839beb93cSSam Leffler 	if (wps_parse_msg(decrypted, &eattr) < 0 ||
83939beb93cSSam Leffler 	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
84039beb93cSSam Leffler 	    wps_process_r_snonce1(wps, eattr.r_snonce1)) {
84139beb93cSSam Leffler 		wpabuf_free(decrypted);
84239beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
84339beb93cSSam Leffler 		return WPS_CONTINUE;
84439beb93cSSam Leffler 	}
84539beb93cSSam Leffler 	wpabuf_free(decrypted);
84639beb93cSSam Leffler 
84739beb93cSSam Leffler 	wps->state = SEND_M5;
84839beb93cSSam Leffler 	return WPS_CONTINUE;
84939beb93cSSam Leffler }
85039beb93cSSam Leffler 
85139beb93cSSam Leffler 
85239beb93cSSam Leffler static enum wps_process_res wps_process_m6(struct wps_data *wps,
85339beb93cSSam Leffler 					   const struct wpabuf *msg,
85439beb93cSSam Leffler 					   struct wps_parse_attr *attr)
85539beb93cSSam Leffler {
85639beb93cSSam Leffler 	struct wpabuf *decrypted;
85739beb93cSSam Leffler 	struct wps_parse_attr eattr;
85839beb93cSSam Leffler 
85939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received M6");
86039beb93cSSam Leffler 
86139beb93cSSam Leffler 	if (wps->state != RECV_M6) {
86239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
86339beb93cSSam Leffler 			   "receiving M6", wps->state);
86439beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
86539beb93cSSam Leffler 		return WPS_CONTINUE;
86639beb93cSSam Leffler 	}
86739beb93cSSam Leffler 
86839beb93cSSam Leffler 	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
86939beb93cSSam Leffler 	    wps_process_authenticator(wps, attr->authenticator, msg)) {
87039beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
87139beb93cSSam Leffler 		return WPS_CONTINUE;
87239beb93cSSam Leffler 	}
87339beb93cSSam Leffler 
87439beb93cSSam Leffler 	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
87539beb93cSSam Leffler 					      attr->encr_settings_len);
87639beb93cSSam Leffler 	if (decrypted == NULL) {
87739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
87839beb93cSSam Leffler 			   "Settings attribute");
87939beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
88039beb93cSSam Leffler 		return WPS_CONTINUE;
88139beb93cSSam Leffler 	}
88239beb93cSSam Leffler 
88339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
88439beb93cSSam Leffler 		   "attribute");
88539beb93cSSam Leffler 	if (wps_parse_msg(decrypted, &eattr) < 0 ||
88639beb93cSSam Leffler 	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
88739beb93cSSam Leffler 	    wps_process_r_snonce2(wps, eattr.r_snonce2)) {
88839beb93cSSam Leffler 		wpabuf_free(decrypted);
88939beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
89039beb93cSSam Leffler 		return WPS_CONTINUE;
89139beb93cSSam Leffler 	}
89239beb93cSSam Leffler 	wpabuf_free(decrypted);
89339beb93cSSam Leffler 
89439beb93cSSam Leffler 	wps->state = SEND_M7;
89539beb93cSSam Leffler 	return WPS_CONTINUE;
89639beb93cSSam Leffler }
89739beb93cSSam Leffler 
89839beb93cSSam Leffler 
89939beb93cSSam Leffler static enum wps_process_res wps_process_m8(struct wps_data *wps,
90039beb93cSSam Leffler 					   const struct wpabuf *msg,
90139beb93cSSam Leffler 					   struct wps_parse_attr *attr)
90239beb93cSSam Leffler {
90339beb93cSSam Leffler 	struct wpabuf *decrypted;
90439beb93cSSam Leffler 	struct wps_parse_attr eattr;
90539beb93cSSam Leffler 
90639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received M8");
90739beb93cSSam Leffler 
90839beb93cSSam Leffler 	if (wps->state != RECV_M8) {
90939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
91039beb93cSSam Leffler 			   "receiving M8", wps->state);
91139beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
91239beb93cSSam Leffler 		return WPS_CONTINUE;
91339beb93cSSam Leffler 	}
91439beb93cSSam Leffler 
91539beb93cSSam Leffler 	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
91639beb93cSSam Leffler 	    wps_process_authenticator(wps, attr->authenticator, msg)) {
91739beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
91839beb93cSSam Leffler 		return WPS_CONTINUE;
91939beb93cSSam Leffler 	}
92039beb93cSSam Leffler 
92139beb93cSSam Leffler 	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
92239beb93cSSam Leffler 					      attr->encr_settings_len);
92339beb93cSSam Leffler 	if (decrypted == NULL) {
92439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
92539beb93cSSam Leffler 			   "Settings attribute");
92639beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
92739beb93cSSam Leffler 		return WPS_CONTINUE;
92839beb93cSSam Leffler 	}
92939beb93cSSam Leffler 
93039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
93139beb93cSSam Leffler 		   "attribute");
93239beb93cSSam Leffler 	if (wps_parse_msg(decrypted, &eattr) < 0 ||
93339beb93cSSam Leffler 	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
93439beb93cSSam Leffler 	    wps_process_creds(wps, eattr.cred, eattr.cred_len,
93539beb93cSSam Leffler 			      eattr.num_cred) ||
93639beb93cSSam Leffler 	    wps_process_ap_settings_e(wps, &eattr, decrypted)) {
93739beb93cSSam Leffler 		wpabuf_free(decrypted);
93839beb93cSSam Leffler 		wps->state = SEND_WSC_NACK;
93939beb93cSSam Leffler 		return WPS_CONTINUE;
94039beb93cSSam Leffler 	}
94139beb93cSSam Leffler 	wpabuf_free(decrypted);
94239beb93cSSam Leffler 
94339beb93cSSam Leffler 	wps->state = WPS_MSG_DONE;
94439beb93cSSam Leffler 	return WPS_CONTINUE;
94539beb93cSSam Leffler }
94639beb93cSSam Leffler 
94739beb93cSSam Leffler 
94839beb93cSSam Leffler static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
94939beb93cSSam Leffler 						const struct wpabuf *msg)
95039beb93cSSam Leffler {
95139beb93cSSam Leffler 	struct wps_parse_attr attr;
95239beb93cSSam Leffler 	enum wps_process_res ret = WPS_CONTINUE;
95339beb93cSSam Leffler 
95439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	if (wps_parse_msg(msg, &attr) < 0)
95739beb93cSSam Leffler 		return WPS_FAILURE;
95839beb93cSSam Leffler 
95939beb93cSSam Leffler 	if (!wps_version_supported(attr.version)) {
96039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
96139beb93cSSam Leffler 			   attr.version ? *attr.version : 0);
96239beb93cSSam Leffler 		return WPS_FAILURE;
96339beb93cSSam Leffler 	}
96439beb93cSSam Leffler 
96539beb93cSSam Leffler 	if (attr.enrollee_nonce == NULL ||
96639beb93cSSam Leffler 	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
96739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
96839beb93cSSam Leffler 		return WPS_FAILURE;
96939beb93cSSam Leffler 	}
97039beb93cSSam Leffler 
97139beb93cSSam Leffler 	if (attr.msg_type == NULL) {
97239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
97339beb93cSSam Leffler 		return WPS_FAILURE;
97439beb93cSSam Leffler 	}
97539beb93cSSam Leffler 
97639beb93cSSam Leffler 	switch (*attr.msg_type) {
97739beb93cSSam Leffler 	case WPS_M2:
97839beb93cSSam Leffler 		ret = wps_process_m2(wps, msg, &attr);
97939beb93cSSam Leffler 		break;
98039beb93cSSam Leffler 	case WPS_M2D:
98139beb93cSSam Leffler 		ret = wps_process_m2d(wps, &attr);
98239beb93cSSam Leffler 		break;
98339beb93cSSam Leffler 	case WPS_M4:
98439beb93cSSam Leffler 		ret = wps_process_m4(wps, msg, &attr);
98539beb93cSSam Leffler 		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
98639beb93cSSam Leffler 			wps_fail_event(wps->wps, WPS_M4);
98739beb93cSSam Leffler 		break;
98839beb93cSSam Leffler 	case WPS_M6:
98939beb93cSSam Leffler 		ret = wps_process_m6(wps, msg, &attr);
99039beb93cSSam Leffler 		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
99139beb93cSSam Leffler 			wps_fail_event(wps->wps, WPS_M6);
99239beb93cSSam Leffler 		break;
99339beb93cSSam Leffler 	case WPS_M8:
99439beb93cSSam Leffler 		ret = wps_process_m8(wps, msg, &attr);
99539beb93cSSam Leffler 		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
99639beb93cSSam Leffler 			wps_fail_event(wps->wps, WPS_M8);
99739beb93cSSam Leffler 		break;
99839beb93cSSam Leffler 	default:
99939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
100039beb93cSSam Leffler 			   *attr.msg_type);
100139beb93cSSam Leffler 		return WPS_FAILURE;
100239beb93cSSam Leffler 	}
100339beb93cSSam Leffler 
100439beb93cSSam Leffler 	/*
100539beb93cSSam Leffler 	 * Save a copy of the last message for Authenticator derivation if we
100639beb93cSSam Leffler 	 * are continuing. However, skip M2D since it is not authenticated and
100739beb93cSSam Leffler 	 * neither is the ACK/NACK response frame. This allows the possibly
100839beb93cSSam Leffler 	 * following M2 to be processed correctly by using the previously sent
100939beb93cSSam Leffler 	 * M1 in Authenticator derivation.
101039beb93cSSam Leffler 	 */
101139beb93cSSam Leffler 	if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
101239beb93cSSam Leffler 		/* Save a copy of the last message for Authenticator derivation
101339beb93cSSam Leffler 		 */
101439beb93cSSam Leffler 		wpabuf_free(wps->last_msg);
101539beb93cSSam Leffler 		wps->last_msg = wpabuf_dup(msg);
101639beb93cSSam Leffler 	}
101739beb93cSSam Leffler 
101839beb93cSSam Leffler 	return ret;
101939beb93cSSam Leffler }
102039beb93cSSam Leffler 
102139beb93cSSam Leffler 
102239beb93cSSam Leffler static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
102339beb93cSSam Leffler 						const struct wpabuf *msg)
102439beb93cSSam Leffler {
102539beb93cSSam Leffler 	struct wps_parse_attr attr;
102639beb93cSSam Leffler 
102739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
102839beb93cSSam Leffler 
102939beb93cSSam Leffler 	if (wps_parse_msg(msg, &attr) < 0)
103039beb93cSSam Leffler 		return WPS_FAILURE;
103139beb93cSSam Leffler 
103239beb93cSSam Leffler 	if (!wps_version_supported(attr.version)) {
103339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
103439beb93cSSam Leffler 			   attr.version ? *attr.version : 0);
103539beb93cSSam Leffler 		return WPS_FAILURE;
103639beb93cSSam Leffler 	}
103739beb93cSSam Leffler 
103839beb93cSSam Leffler 	if (attr.msg_type == NULL) {
103939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
104039beb93cSSam Leffler 		return WPS_FAILURE;
104139beb93cSSam Leffler 	}
104239beb93cSSam Leffler 
104339beb93cSSam Leffler 	if (*attr.msg_type != WPS_WSC_ACK) {
104439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
104539beb93cSSam Leffler 			   *attr.msg_type);
104639beb93cSSam Leffler 		return WPS_FAILURE;
104739beb93cSSam Leffler 	}
104839beb93cSSam Leffler 
104939beb93cSSam Leffler 	if (attr.registrar_nonce == NULL ||
105039beb93cSSam Leffler 	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
105139beb93cSSam Leffler 	{
105239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
105339beb93cSSam Leffler 		return WPS_FAILURE;
105439beb93cSSam Leffler 	}
105539beb93cSSam Leffler 
105639beb93cSSam Leffler 	if (attr.enrollee_nonce == NULL ||
105739beb93cSSam Leffler 	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
105839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
105939beb93cSSam Leffler 		return WPS_FAILURE;
106039beb93cSSam Leffler 	}
106139beb93cSSam Leffler 
106239beb93cSSam Leffler 	if (wps->state == RECV_ACK && wps->wps->ap) {
106339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
106439beb93cSSam Leffler 			   "completed successfully");
106539beb93cSSam Leffler 		wps_success_event(wps->wps);
106639beb93cSSam Leffler 		wps->state = WPS_FINISHED;
106739beb93cSSam Leffler 		return WPS_DONE;
106839beb93cSSam Leffler 	}
106939beb93cSSam Leffler 
107039beb93cSSam Leffler 	return WPS_FAILURE;
107139beb93cSSam Leffler }
107239beb93cSSam Leffler 
107339beb93cSSam Leffler 
107439beb93cSSam Leffler static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
107539beb93cSSam Leffler 						 const struct wpabuf *msg)
107639beb93cSSam Leffler {
107739beb93cSSam Leffler 	struct wps_parse_attr attr;
107839beb93cSSam Leffler 
107939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
108039beb93cSSam Leffler 
108139beb93cSSam Leffler 	if (wps_parse_msg(msg, &attr) < 0)
108239beb93cSSam Leffler 		return WPS_FAILURE;
108339beb93cSSam Leffler 
108439beb93cSSam Leffler 	if (!wps_version_supported(attr.version)) {
108539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
108639beb93cSSam Leffler 			   attr.version ? *attr.version : 0);
108739beb93cSSam Leffler 		return WPS_FAILURE;
108839beb93cSSam Leffler 	}
108939beb93cSSam Leffler 
109039beb93cSSam Leffler 	if (attr.msg_type == NULL) {
109139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
109239beb93cSSam Leffler 		return WPS_FAILURE;
109339beb93cSSam Leffler 	}
109439beb93cSSam Leffler 
109539beb93cSSam Leffler 	if (*attr.msg_type != WPS_WSC_NACK) {
109639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
109739beb93cSSam Leffler 			   *attr.msg_type);
109839beb93cSSam Leffler 		return WPS_FAILURE;
109939beb93cSSam Leffler 	}
110039beb93cSSam Leffler 
110139beb93cSSam Leffler 	if (attr.registrar_nonce == NULL ||
110239beb93cSSam Leffler 	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
110339beb93cSSam Leffler 	{
110439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
110539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
110639beb93cSSam Leffler 			    attr.registrar_nonce, WPS_NONCE_LEN);
110739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
110839beb93cSSam Leffler 			    wps->nonce_r, WPS_NONCE_LEN);
110939beb93cSSam Leffler 		return WPS_FAILURE;
111039beb93cSSam Leffler 	}
111139beb93cSSam Leffler 
111239beb93cSSam Leffler 	if (attr.enrollee_nonce == NULL ||
111339beb93cSSam Leffler 	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
111439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
111539beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
111639beb93cSSam Leffler 			    attr.enrollee_nonce, WPS_NONCE_LEN);
111739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
111839beb93cSSam Leffler 			    wps->nonce_e, WPS_NONCE_LEN);
111939beb93cSSam Leffler 		return WPS_FAILURE;
112039beb93cSSam Leffler 	}
112139beb93cSSam Leffler 
112239beb93cSSam Leffler 	if (attr.config_error == NULL) {
112339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
112439beb93cSSam Leffler 			   "in WSC_NACK");
112539beb93cSSam Leffler 		return WPS_FAILURE;
112639beb93cSSam Leffler 	}
112739beb93cSSam Leffler 
112839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
112939beb93cSSam Leffler 		   "Configuration Error %d", WPA_GET_BE16(attr.config_error));
113039beb93cSSam Leffler 
113139beb93cSSam Leffler 	switch (wps->state) {
113239beb93cSSam Leffler 	case RECV_M4:
113339beb93cSSam Leffler 		wps_fail_event(wps->wps, WPS_M3);
113439beb93cSSam Leffler 		break;
113539beb93cSSam Leffler 	case RECV_M6:
113639beb93cSSam Leffler 		wps_fail_event(wps->wps, WPS_M5);
113739beb93cSSam Leffler 		break;
113839beb93cSSam Leffler 	case RECV_M8:
113939beb93cSSam Leffler 		wps_fail_event(wps->wps, WPS_M7);
114039beb93cSSam Leffler 		break;
114139beb93cSSam Leffler 	default:
114239beb93cSSam Leffler 		break;
114339beb93cSSam Leffler 	}
114439beb93cSSam Leffler 
114539beb93cSSam Leffler 	/* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
114639beb93cSSam Leffler 	 * Enrollee is Authenticator */
114739beb93cSSam Leffler 	wps->state = SEND_WSC_NACK;
114839beb93cSSam Leffler 
114939beb93cSSam Leffler 	return WPS_FAILURE;
115039beb93cSSam Leffler }
115139beb93cSSam Leffler 
115239beb93cSSam Leffler 
115339beb93cSSam Leffler enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
115439beb93cSSam Leffler 					      enum wsc_op_code op_code,
115539beb93cSSam Leffler 					      const struct wpabuf *msg)
115639beb93cSSam Leffler {
115739beb93cSSam Leffler 
115839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
115939beb93cSSam Leffler 		   "op_code=%d)",
116039beb93cSSam Leffler 		   (unsigned long) wpabuf_len(msg), op_code);
116139beb93cSSam Leffler 
116239beb93cSSam Leffler 	switch (op_code) {
116339beb93cSSam Leffler 	case WSC_MSG:
116439beb93cSSam Leffler 	case WSC_UPnP:
116539beb93cSSam Leffler 		return wps_process_wsc_msg(wps, msg);
116639beb93cSSam Leffler 	case WSC_ACK:
116739beb93cSSam Leffler 		return wps_process_wsc_ack(wps, msg);
116839beb93cSSam Leffler 	case WSC_NACK:
116939beb93cSSam Leffler 		return wps_process_wsc_nack(wps, msg);
117039beb93cSSam Leffler 	default:
117139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
117239beb93cSSam Leffler 		return WPS_FAILURE;
117339beb93cSSam Leffler 	}
117439beb93cSSam Leffler }
1175