139beb93cSSam Leffler /*
239beb93cSSam Leffler * Wi-Fi Protected Setup - Enrollee
339beb93cSSam Leffler * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "crypto/crypto.h"
13e28a4053SRui Paulo #include "crypto/sha256.h"
14f05cddf9SRui Paulo #include "crypto/random.h"
1539beb93cSSam Leffler #include "wps_i.h"
1639beb93cSSam Leffler #include "wps_dev_attr.h"
1739beb93cSSam Leffler
1839beb93cSSam Leffler
wps_build_wps_state(struct wps_data * wps,struct wpabuf * msg)1939beb93cSSam Leffler static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
2039beb93cSSam Leffler {
2139beb93cSSam Leffler u8 state;
2239beb93cSSam Leffler if (wps->wps->ap)
2339beb93cSSam Leffler state = wps->wps->wps_state;
2439beb93cSSam Leffler else
2539beb93cSSam Leffler state = WPS_STATE_NOT_CONFIGURED;
2639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)",
2739beb93cSSam Leffler state);
2839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_WPS_STATE);
2939beb93cSSam Leffler wpabuf_put_be16(msg, 1);
303157ba21SRui Paulo wpabuf_put_u8(msg, state);
3139beb93cSSam Leffler return 0;
3239beb93cSSam Leffler }
3339beb93cSSam Leffler
3439beb93cSSam Leffler
wps_build_e_hash(struct wps_data * wps,struct wpabuf * msg)3539beb93cSSam Leffler static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
3639beb93cSSam Leffler {
3739beb93cSSam Leffler u8 *hash;
3839beb93cSSam Leffler const u8 *addr[4];
3939beb93cSSam Leffler size_t len[4];
4039beb93cSSam Leffler
41f05cddf9SRui Paulo if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
4239beb93cSSam Leffler return -1;
4339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
4439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
4539beb93cSSam Leffler wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
4639beb93cSSam Leffler
4739beb93cSSam Leffler if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
4839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
4939beb93cSSam Leffler "E-Hash derivation");
5039beb93cSSam Leffler return -1;
5139beb93cSSam Leffler }
5239beb93cSSam Leffler
5339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-Hash1");
5439beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_HASH1);
5539beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN);
5639beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN);
5739beb93cSSam Leffler /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
5839beb93cSSam Leffler addr[0] = wps->snonce;
5939beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
6039beb93cSSam Leffler addr[1] = wps->psk1;
6139beb93cSSam Leffler len[1] = WPS_PSK_LEN;
6239beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
6339beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
6439beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
6539beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
6639beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
6739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
6839beb93cSSam Leffler
6939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-Hash2");
7039beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_HASH2);
7139beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN);
7239beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN);
7339beb93cSSam Leffler /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
7439beb93cSSam Leffler addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
7539beb93cSSam Leffler addr[1] = wps->psk2;
7639beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
7739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
7839beb93cSSam Leffler
7939beb93cSSam Leffler return 0;
8039beb93cSSam Leffler }
8139beb93cSSam Leffler
8239beb93cSSam Leffler
wps_build_e_snonce1(struct wps_data * wps,struct wpabuf * msg)8339beb93cSSam Leffler static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
8439beb93cSSam Leffler {
8539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-SNonce1");
8639beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_SNONCE1);
8739beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
8839beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
8939beb93cSSam Leffler return 0;
9039beb93cSSam Leffler }
9139beb93cSSam Leffler
9239beb93cSSam Leffler
wps_build_e_snonce2(struct wps_data * wps,struct wpabuf * msg)9339beb93cSSam Leffler static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
9439beb93cSSam Leffler {
9539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-SNonce2");
9639beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_SNONCE2);
9739beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
9839beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
9939beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
10039beb93cSSam Leffler return 0;
10139beb93cSSam Leffler }
10239beb93cSSam Leffler
10339beb93cSSam Leffler
wps_build_m1(struct wps_data * wps)10439beb93cSSam Leffler static struct wpabuf * wps_build_m1(struct wps_data *wps)
10539beb93cSSam Leffler {
10639beb93cSSam Leffler struct wpabuf *msg;
107f05cddf9SRui Paulo u16 config_methods;
1084bc52338SCy Schubert u8 multi_ap_backhaul_sta = 0;
10939beb93cSSam Leffler
110f05cddf9SRui Paulo if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0)
11139beb93cSSam Leffler return NULL;
11239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
11339beb93cSSam Leffler wps->nonce_e, WPS_NONCE_LEN);
11439beb93cSSam Leffler
11539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
11639beb93cSSam Leffler msg = wpabuf_alloc(1000);
11739beb93cSSam Leffler if (msg == NULL)
11839beb93cSSam Leffler return NULL;
11939beb93cSSam Leffler
120f05cddf9SRui Paulo config_methods = wps->wps->config_methods;
121f05cddf9SRui Paulo if (wps->wps->ap && !wps->pbc_in_m1 &&
122f05cddf9SRui Paulo (wps->dev_password_len != 0 ||
123f05cddf9SRui Paulo (config_methods & WPS_CONFIG_DISPLAY))) {
124f05cddf9SRui Paulo /*
125f05cddf9SRui Paulo * These are the methods that the AP supports as an Enrollee
126f05cddf9SRui Paulo * for adding external Registrars, so remove PushButton.
127f05cddf9SRui Paulo *
128f05cddf9SRui Paulo * As a workaround for Windows 7 mechanism for probing WPS
129f05cddf9SRui Paulo * capabilities from M1, leave PushButton option if no PIN
130f05cddf9SRui Paulo * method is available or if WPS configuration enables PBC
131f05cddf9SRui Paulo * workaround.
132f05cddf9SRui Paulo */
133f05cddf9SRui Paulo config_methods &= ~WPS_CONFIG_PUSHBUTTON;
134f05cddf9SRui Paulo config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
135f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON);
136f05cddf9SRui Paulo }
137f05cddf9SRui Paulo
1384bc52338SCy Schubert if (wps->multi_ap_backhaul_sta)
1394bc52338SCy Schubert multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA;
1404bc52338SCy Schubert
14139beb93cSSam Leffler if (wps_build_version(msg) ||
14239beb93cSSam Leffler wps_build_msg_type(msg, WPS_M1) ||
14339beb93cSSam Leffler wps_build_uuid_e(msg, wps->uuid_e) ||
1445b9c547cSRui Paulo wps_build_mac_addr(msg, wps->mac_addr_e) ||
14539beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
14639beb93cSSam Leffler wps_build_public_key(wps, msg) ||
14739beb93cSSam Leffler wps_build_auth_type_flags(wps, msg) ||
14839beb93cSSam Leffler wps_build_encr_type_flags(wps, msg) ||
14939beb93cSSam Leffler wps_build_conn_type_flags(wps, msg) ||
150f05cddf9SRui Paulo wps_build_config_methods(msg, config_methods) ||
15139beb93cSSam Leffler wps_build_wps_state(wps, msg) ||
15239beb93cSSam Leffler wps_build_device_attrs(&wps->wps->dev, msg) ||
1535b9c547cSRui Paulo wps_build_rf_bands(&wps->wps->dev, msg,
1545b9c547cSRui Paulo wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
15539beb93cSSam Leffler wps_build_assoc_state(wps, msg) ||
15639beb93cSSam Leffler wps_build_dev_password_id(msg, wps->dev_pw_id) ||
15739beb93cSSam Leffler wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
158f05cddf9SRui Paulo wps_build_os_version(&wps->wps->dev, msg) ||
1594bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) ||
160f05cddf9SRui Paulo wps_build_vendor_ext_m1(&wps->wps->dev, msg)) {
16139beb93cSSam Leffler wpabuf_free(msg);
16239beb93cSSam Leffler return NULL;
16339beb93cSSam Leffler }
16439beb93cSSam Leffler
16539beb93cSSam Leffler wps->state = RECV_M2;
16639beb93cSSam Leffler return msg;
16739beb93cSSam Leffler }
16839beb93cSSam Leffler
16939beb93cSSam Leffler
wps_build_m3(struct wps_data * wps)17039beb93cSSam Leffler static struct wpabuf * wps_build_m3(struct wps_data *wps)
17139beb93cSSam Leffler {
17239beb93cSSam Leffler struct wpabuf *msg;
17339beb93cSSam Leffler
17439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
17539beb93cSSam Leffler
17639beb93cSSam Leffler if (wps->dev_password == NULL) {
17739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
17839beb93cSSam Leffler return NULL;
17939beb93cSSam Leffler }
180780fb4a2SCy Schubert if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
181780fb4a2SCy Schubert return NULL;
18239beb93cSSam Leffler
1835b9c547cSRui Paulo if (wps->wps->ap && random_pool_ready() != 1) {
1845b9c547cSRui Paulo wpa_printf(MSG_INFO,
1855b9c547cSRui Paulo "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used");
1865b9c547cSRui Paulo return NULL;
1875b9c547cSRui Paulo }
1885b9c547cSRui Paulo
18939beb93cSSam Leffler msg = wpabuf_alloc(1000);
19039beb93cSSam Leffler if (msg == NULL)
19139beb93cSSam Leffler return NULL;
19239beb93cSSam Leffler
19339beb93cSSam Leffler if (wps_build_version(msg) ||
19439beb93cSSam Leffler wps_build_msg_type(msg, WPS_M3) ||
19539beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) ||
19639beb93cSSam Leffler wps_build_e_hash(wps, msg) ||
1974bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
19839beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
19939beb93cSSam Leffler wpabuf_free(msg);
20039beb93cSSam Leffler return NULL;
20139beb93cSSam Leffler }
20239beb93cSSam Leffler
20339beb93cSSam Leffler wps->state = RECV_M4;
20439beb93cSSam Leffler return msg;
20539beb93cSSam Leffler }
20639beb93cSSam Leffler
20739beb93cSSam Leffler
wps_build_m5(struct wps_data * wps)20839beb93cSSam Leffler static struct wpabuf * wps_build_m5(struct wps_data *wps)
20939beb93cSSam Leffler {
21039beb93cSSam Leffler struct wpabuf *msg, *plain;
21139beb93cSSam Leffler
21239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
21339beb93cSSam Leffler
21439beb93cSSam Leffler plain = wpabuf_alloc(200);
21539beb93cSSam Leffler if (plain == NULL)
21639beb93cSSam Leffler return NULL;
21739beb93cSSam Leffler
21839beb93cSSam Leffler msg = wpabuf_alloc(1000);
21939beb93cSSam Leffler if (msg == NULL) {
22039beb93cSSam Leffler wpabuf_free(plain);
22139beb93cSSam Leffler return NULL;
22239beb93cSSam Leffler }
22339beb93cSSam Leffler
22439beb93cSSam Leffler if (wps_build_version(msg) ||
22539beb93cSSam Leffler wps_build_msg_type(msg, WPS_M5) ||
22639beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) ||
22739beb93cSSam Leffler wps_build_e_snonce1(wps, plain) ||
22839beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) ||
22939beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) ||
2304bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
23139beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
232780fb4a2SCy Schubert wpabuf_clear_free(plain);
23339beb93cSSam Leffler wpabuf_free(msg);
23439beb93cSSam Leffler return NULL;
23539beb93cSSam Leffler }
236780fb4a2SCy Schubert wpabuf_clear_free(plain);
23739beb93cSSam Leffler
23839beb93cSSam Leffler wps->state = RECV_M6;
23939beb93cSSam Leffler return msg;
24039beb93cSSam Leffler }
24139beb93cSSam Leffler
24239beb93cSSam Leffler
wps_build_cred_ssid(struct wps_data * wps,struct wpabuf * msg)24339beb93cSSam Leffler static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
24439beb93cSSam Leffler {
24539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * SSID");
24639beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_SSID);
24739beb93cSSam Leffler wpabuf_put_be16(msg, wps->wps->ssid_len);
24839beb93cSSam Leffler wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
24939beb93cSSam Leffler return 0;
25039beb93cSSam Leffler }
25139beb93cSSam Leffler
25239beb93cSSam Leffler
wps_build_cred_auth_type(struct wps_data * wps,struct wpabuf * msg)25339beb93cSSam Leffler static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
25439beb93cSSam Leffler {
2555b9c547cSRui Paulo u16 auth_type = wps->wps->ap_auth_type;
256f05cddf9SRui Paulo
2575b9c547cSRui Paulo /*
2585b9c547cSRui Paulo * Work around issues with Windows 7 WPS implementation not liking
2595b9c547cSRui Paulo * multiple Authentication Type bits in M7 AP Settings attribute by
2605b9c547cSRui Paulo * showing only the most secure option from current configuration.
2615b9c547cSRui Paulo */
262f05cddf9SRui Paulo if (auth_type & WPS_AUTH_WPA2PSK)
263f05cddf9SRui Paulo auth_type = WPS_AUTH_WPA2PSK;
264f05cddf9SRui Paulo else if (auth_type & WPS_AUTH_WPAPSK)
265f05cddf9SRui Paulo auth_type = WPS_AUTH_WPAPSK;
266f05cddf9SRui Paulo else if (auth_type & WPS_AUTH_OPEN)
267f05cddf9SRui Paulo auth_type = WPS_AUTH_OPEN;
268f05cddf9SRui Paulo
269f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type);
27039beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
27139beb93cSSam Leffler wpabuf_put_be16(msg, 2);
272f05cddf9SRui Paulo wpabuf_put_be16(msg, auth_type);
27339beb93cSSam Leffler return 0;
27439beb93cSSam Leffler }
27539beb93cSSam Leffler
27639beb93cSSam Leffler
wps_build_cred_encr_type(struct wps_data * wps,struct wpabuf * msg)27739beb93cSSam Leffler static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
27839beb93cSSam Leffler {
2795b9c547cSRui Paulo u16 encr_type = wps->wps->ap_encr_type;
280f05cddf9SRui Paulo
2815b9c547cSRui Paulo /*
2825b9c547cSRui Paulo * Work around issues with Windows 7 WPS implementation not liking
2835b9c547cSRui Paulo * multiple Encryption Type bits in M7 AP Settings attribute by
2845b9c547cSRui Paulo * showing only the most secure option from current configuration.
2855b9c547cSRui Paulo */
2865b9c547cSRui Paulo if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
287f05cddf9SRui Paulo if (encr_type & WPS_ENCR_AES)
288f05cddf9SRui Paulo encr_type = WPS_ENCR_AES;
289f05cddf9SRui Paulo else if (encr_type & WPS_ENCR_TKIP)
290f05cddf9SRui Paulo encr_type = WPS_ENCR_TKIP;
291f05cddf9SRui Paulo }
292f05cddf9SRui Paulo
293f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type);
29439beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
29539beb93cSSam Leffler wpabuf_put_be16(msg, 2);
296f05cddf9SRui Paulo wpabuf_put_be16(msg, encr_type);
29739beb93cSSam Leffler return 0;
29839beb93cSSam Leffler }
29939beb93cSSam Leffler
30039beb93cSSam Leffler
wps_build_cred_network_key(struct wps_data * wps,struct wpabuf * msg)30139beb93cSSam Leffler static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
30239beb93cSSam Leffler {
3035b9c547cSRui Paulo if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) &&
3045b9c547cSRui Paulo wps->wps->network_key_len == 0) {
3055b9c547cSRui Paulo char hex[65];
3065b9c547cSRui Paulo u8 psk[32];
3075b9c547cSRui Paulo /* Generate a random per-device PSK */
3085b9c547cSRui Paulo if (random_pool_ready() != 1 ||
3095b9c547cSRui Paulo random_get_bytes(psk, sizeof(psk)) < 0) {
3105b9c547cSRui Paulo wpa_printf(MSG_INFO,
3115b9c547cSRui Paulo "WPS: Could not generate random PSK");
3125b9c547cSRui Paulo return -1;
3135b9c547cSRui Paulo }
3145b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
3155b9c547cSRui Paulo psk, sizeof(psk));
3165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
3175b9c547cSRui Paulo (unsigned int) wps->new_psk_len * 2);
3185b9c547cSRui Paulo wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk));
3195b9c547cSRui Paulo wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
3205b9c547cSRui Paulo wpabuf_put_be16(msg, sizeof(psk) * 2);
3215b9c547cSRui Paulo wpabuf_put_data(msg, hex, sizeof(psk) * 2);
3225b9c547cSRui Paulo if (wps->wps->registrar) {
3235b9c547cSRui Paulo wps_cb_new_psk(wps->wps->registrar,
3245b9c547cSRui Paulo wps->peer_dev.mac_addr,
3255b9c547cSRui Paulo wps->p2p_dev_addr, psk, sizeof(psk));
3265b9c547cSRui Paulo }
3275b9c547cSRui Paulo return 0;
3285b9c547cSRui Paulo }
3295b9c547cSRui Paulo
3305b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)",
3315b9c547cSRui Paulo (unsigned int) wps->wps->network_key_len);
33239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
33339beb93cSSam Leffler wpabuf_put_be16(msg, wps->wps->network_key_len);
33439beb93cSSam Leffler wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
33539beb93cSSam Leffler return 0;
33639beb93cSSam Leffler }
33739beb93cSSam Leffler
33839beb93cSSam Leffler
wps_build_cred_mac_addr(struct wps_data * wps,struct wpabuf * msg)33939beb93cSSam Leffler static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
34039beb93cSSam Leffler {
34139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * MAC Address (AP BSSID)");
34239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_MAC_ADDR);
34339beb93cSSam Leffler wpabuf_put_be16(msg, ETH_ALEN);
34439beb93cSSam Leffler wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
34539beb93cSSam Leffler return 0;
34639beb93cSSam Leffler }
34739beb93cSSam Leffler
34839beb93cSSam Leffler
wps_build_ap_settings(struct wps_data * wps,struct wpabuf * plain)34939beb93cSSam Leffler static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
35039beb93cSSam Leffler {
3515b9c547cSRui Paulo const u8 *start, *end;
3525b9c547cSRui Paulo int ret;
3535b9c547cSRui Paulo
35439beb93cSSam Leffler if (wps->wps->ap_settings) {
35539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)");
35639beb93cSSam Leffler wpabuf_put_data(plain, wps->wps->ap_settings,
35739beb93cSSam Leffler wps->wps->ap_settings_len);
35839beb93cSSam Leffler return 0;
35939beb93cSSam Leffler }
36039beb93cSSam Leffler
3615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: * AP Settings based on current configuration");
3625b9c547cSRui Paulo start = wpabuf_put(plain, 0);
3635b9c547cSRui Paulo ret = wps_build_cred_ssid(wps, plain) ||
36439beb93cSSam Leffler wps_build_cred_mac_addr(wps, plain) ||
36539beb93cSSam Leffler wps_build_cred_auth_type(wps, plain) ||
36639beb93cSSam Leffler wps_build_cred_encr_type(wps, plain) ||
36739beb93cSSam Leffler wps_build_cred_network_key(wps, plain);
3685b9c547cSRui Paulo end = wpabuf_put(plain, 0);
3695b9c547cSRui Paulo
3705b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings",
3715b9c547cSRui Paulo start, end - start);
3725b9c547cSRui Paulo
3735b9c547cSRui Paulo return ret;
37439beb93cSSam Leffler }
37539beb93cSSam Leffler
37639beb93cSSam Leffler
wps_build_m7(struct wps_data * wps)37739beb93cSSam Leffler static struct wpabuf * wps_build_m7(struct wps_data *wps)
37839beb93cSSam Leffler {
37939beb93cSSam Leffler struct wpabuf *msg, *plain;
38039beb93cSSam Leffler
38139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
38239beb93cSSam Leffler
38339beb93cSSam Leffler plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
38439beb93cSSam Leffler if (plain == NULL)
38539beb93cSSam Leffler return NULL;
38639beb93cSSam Leffler
38739beb93cSSam Leffler msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
38839beb93cSSam Leffler if (msg == NULL) {
38939beb93cSSam Leffler wpabuf_free(plain);
39039beb93cSSam Leffler return NULL;
39139beb93cSSam Leffler }
39239beb93cSSam Leffler
39339beb93cSSam Leffler if (wps_build_version(msg) ||
39439beb93cSSam Leffler wps_build_msg_type(msg, WPS_M7) ||
39539beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) ||
39639beb93cSSam Leffler wps_build_e_snonce2(wps, plain) ||
39739beb93cSSam Leffler (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
39839beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) ||
39939beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) ||
4004bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
40139beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
402780fb4a2SCy Schubert wpabuf_clear_free(plain);
40339beb93cSSam Leffler wpabuf_free(msg);
40439beb93cSSam Leffler return NULL;
40539beb93cSSam Leffler }
406780fb4a2SCy Schubert wpabuf_clear_free(plain);
40739beb93cSSam Leffler
408e28a4053SRui Paulo if (wps->wps->ap && wps->wps->registrar) {
409e28a4053SRui Paulo /*
410e28a4053SRui Paulo * If the Registrar is only learning our current configuration,
411e28a4053SRui Paulo * it may not continue protocol run to successful completion.
412e28a4053SRui Paulo * Store information here to make sure it remains available.
413e28a4053SRui Paulo */
414e28a4053SRui Paulo wps_device_store(wps->wps->registrar, &wps->peer_dev,
415e28a4053SRui Paulo wps->uuid_r);
416e28a4053SRui Paulo }
417e28a4053SRui Paulo
41839beb93cSSam Leffler wps->state = RECV_M8;
41939beb93cSSam Leffler return msg;
42039beb93cSSam Leffler }
42139beb93cSSam Leffler
42239beb93cSSam Leffler
wps_build_wsc_done(struct wps_data * wps)42339beb93cSSam Leffler static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
42439beb93cSSam Leffler {
42539beb93cSSam Leffler struct wpabuf *msg;
42639beb93cSSam Leffler
42739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
42839beb93cSSam Leffler
42939beb93cSSam Leffler msg = wpabuf_alloc(1000);
43039beb93cSSam Leffler if (msg == NULL)
43139beb93cSSam Leffler return NULL;
43239beb93cSSam Leffler
43339beb93cSSam Leffler if (wps_build_version(msg) ||
43439beb93cSSam Leffler wps_build_msg_type(msg, WPS_WSC_DONE) ||
43539beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
436f05cddf9SRui Paulo wps_build_registrar_nonce(wps, msg) ||
4374bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
43839beb93cSSam Leffler wpabuf_free(msg);
43939beb93cSSam Leffler return NULL;
44039beb93cSSam Leffler }
44139beb93cSSam Leffler
44239beb93cSSam Leffler if (wps->wps->ap)
44339beb93cSSam Leffler wps->state = RECV_ACK;
44439beb93cSSam Leffler else {
4455b9c547cSRui Paulo wps_success_event(wps->wps, wps->peer_dev.mac_addr);
44639beb93cSSam Leffler wps->state = WPS_FINISHED;
44739beb93cSSam Leffler }
44839beb93cSSam Leffler return msg;
44939beb93cSSam Leffler }
45039beb93cSSam Leffler
45139beb93cSSam Leffler
wps_enrollee_get_msg(struct wps_data * wps,enum wsc_op_code * op_code)45239beb93cSSam Leffler struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
45339beb93cSSam Leffler enum wsc_op_code *op_code)
45439beb93cSSam Leffler {
45539beb93cSSam Leffler struct wpabuf *msg;
45639beb93cSSam Leffler
45739beb93cSSam Leffler switch (wps->state) {
45839beb93cSSam Leffler case SEND_M1:
45939beb93cSSam Leffler msg = wps_build_m1(wps);
46039beb93cSSam Leffler *op_code = WSC_MSG;
46139beb93cSSam Leffler break;
46239beb93cSSam Leffler case SEND_M3:
46339beb93cSSam Leffler msg = wps_build_m3(wps);
46439beb93cSSam Leffler *op_code = WSC_MSG;
46539beb93cSSam Leffler break;
46639beb93cSSam Leffler case SEND_M5:
46739beb93cSSam Leffler msg = wps_build_m5(wps);
46839beb93cSSam Leffler *op_code = WSC_MSG;
46939beb93cSSam Leffler break;
47039beb93cSSam Leffler case SEND_M7:
47139beb93cSSam Leffler msg = wps_build_m7(wps);
47239beb93cSSam Leffler *op_code = WSC_MSG;
47339beb93cSSam Leffler break;
47439beb93cSSam Leffler case RECEIVED_M2D:
47539beb93cSSam Leffler if (wps->wps->ap) {
47639beb93cSSam Leffler msg = wps_build_wsc_nack(wps);
47739beb93cSSam Leffler *op_code = WSC_NACK;
47839beb93cSSam Leffler break;
47939beb93cSSam Leffler }
48039beb93cSSam Leffler msg = wps_build_wsc_ack(wps);
48139beb93cSSam Leffler *op_code = WSC_ACK;
48239beb93cSSam Leffler if (msg) {
48339beb93cSSam Leffler /* Another M2/M2D may be received */
48439beb93cSSam Leffler wps->state = RECV_M2;
48539beb93cSSam Leffler }
48639beb93cSSam Leffler break;
48739beb93cSSam Leffler case SEND_WSC_NACK:
48839beb93cSSam Leffler msg = wps_build_wsc_nack(wps);
48939beb93cSSam Leffler *op_code = WSC_NACK;
49039beb93cSSam Leffler break;
49139beb93cSSam Leffler case WPS_MSG_DONE:
49239beb93cSSam Leffler msg = wps_build_wsc_done(wps);
49339beb93cSSam Leffler *op_code = WSC_Done;
49439beb93cSSam Leffler break;
49539beb93cSSam Leffler default:
49639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
49739beb93cSSam Leffler "a message", wps->state);
49839beb93cSSam Leffler msg = NULL;
49939beb93cSSam Leffler break;
50039beb93cSSam Leffler }
50139beb93cSSam Leffler
50239beb93cSSam Leffler if (*op_code == WSC_MSG && msg) {
50339beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation
50439beb93cSSam Leffler */
50539beb93cSSam Leffler wpabuf_free(wps->last_msg);
50639beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg);
50739beb93cSSam Leffler }
50839beb93cSSam Leffler
50939beb93cSSam Leffler return msg;
51039beb93cSSam Leffler }
51139beb93cSSam Leffler
51239beb93cSSam Leffler
wps_process_registrar_nonce(struct wps_data * wps,const u8 * r_nonce)51339beb93cSSam Leffler static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
51439beb93cSSam Leffler {
51539beb93cSSam Leffler if (r_nonce == NULL) {
51639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
51739beb93cSSam Leffler return -1;
51839beb93cSSam Leffler }
51939beb93cSSam Leffler
52039beb93cSSam Leffler os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
52139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
52239beb93cSSam Leffler wps->nonce_r, WPS_NONCE_LEN);
52339beb93cSSam Leffler
52439beb93cSSam Leffler return 0;
52539beb93cSSam Leffler }
52639beb93cSSam Leffler
52739beb93cSSam Leffler
wps_process_enrollee_nonce(struct wps_data * wps,const u8 * e_nonce)52839beb93cSSam Leffler static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
52939beb93cSSam Leffler {
53039beb93cSSam Leffler if (e_nonce == NULL) {
53139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
53239beb93cSSam Leffler return -1;
53339beb93cSSam Leffler }
53439beb93cSSam Leffler
53539beb93cSSam Leffler if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
53639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
53739beb93cSSam Leffler return -1;
53839beb93cSSam Leffler }
53939beb93cSSam Leffler
54039beb93cSSam Leffler return 0;
54139beb93cSSam Leffler }
54239beb93cSSam Leffler
54339beb93cSSam Leffler
wps_process_uuid_r(struct wps_data * wps,const u8 * uuid_r)54439beb93cSSam Leffler static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
54539beb93cSSam Leffler {
54639beb93cSSam Leffler if (uuid_r == NULL) {
54739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
54839beb93cSSam Leffler return -1;
54939beb93cSSam Leffler }
55039beb93cSSam Leffler
55139beb93cSSam Leffler os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
55239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
55339beb93cSSam Leffler
55439beb93cSSam Leffler return 0;
55539beb93cSSam Leffler }
55639beb93cSSam Leffler
55739beb93cSSam Leffler
wps_process_pubkey(struct wps_data * wps,const u8 * pk,size_t pk_len)55839beb93cSSam Leffler static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
55939beb93cSSam Leffler size_t pk_len)
56039beb93cSSam Leffler {
56139beb93cSSam Leffler if (pk == NULL || pk_len == 0) {
56239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
56339beb93cSSam Leffler return -1;
56439beb93cSSam Leffler }
56539beb93cSSam Leffler
5665b9c547cSRui Paulo if (wps->peer_pubkey_hash_set) {
5675b9c547cSRui Paulo u8 hash[WPS_HASH_LEN];
5685b9c547cSRui Paulo sha256_vector(1, &pk, &pk_len, hash);
5695b9c547cSRui Paulo if (os_memcmp_const(hash, wps->peer_pubkey_hash,
5705b9c547cSRui Paulo WPS_OOB_PUBKEY_HASH_LEN) != 0) {
5715b9c547cSRui Paulo wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
5725b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
5735b9c547cSRui Paulo pk, pk_len);
5745b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
5755b9c547cSRui Paulo "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
5765b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
5775b9c547cSRui Paulo wps->peer_pubkey_hash,
5785b9c547cSRui Paulo WPS_OOB_PUBKEY_HASH_LEN);
5795b9c547cSRui Paulo wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
5805b9c547cSRui Paulo return -1;
5815b9c547cSRui Paulo }
5825b9c547cSRui Paulo }
5835b9c547cSRui Paulo
58439beb93cSSam Leffler wpabuf_free(wps->dh_pubkey_r);
58539beb93cSSam Leffler wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
58639beb93cSSam Leffler if (wps->dh_pubkey_r == NULL)
58739beb93cSSam Leffler return -1;
58839beb93cSSam Leffler
58939beb93cSSam Leffler if (wps_derive_keys(wps) < 0)
59039beb93cSSam Leffler return -1;
59139beb93cSSam Leffler
59239beb93cSSam Leffler return 0;
59339beb93cSSam Leffler }
59439beb93cSSam Leffler
59539beb93cSSam Leffler
wps_process_r_hash1(struct wps_data * wps,const u8 * r_hash1)59639beb93cSSam Leffler static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
59739beb93cSSam Leffler {
59839beb93cSSam Leffler if (r_hash1 == NULL) {
59939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
60039beb93cSSam Leffler return -1;
60139beb93cSSam Leffler }
60239beb93cSSam Leffler
60339beb93cSSam Leffler os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
60439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
60539beb93cSSam Leffler
60639beb93cSSam Leffler return 0;
60739beb93cSSam Leffler }
60839beb93cSSam Leffler
60939beb93cSSam Leffler
wps_process_r_hash2(struct wps_data * wps,const u8 * r_hash2)61039beb93cSSam Leffler static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
61139beb93cSSam Leffler {
61239beb93cSSam Leffler if (r_hash2 == NULL) {
61339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
61439beb93cSSam Leffler return -1;
61539beb93cSSam Leffler }
61639beb93cSSam Leffler
61739beb93cSSam Leffler os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
61839beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
61939beb93cSSam Leffler
62039beb93cSSam Leffler return 0;
62139beb93cSSam Leffler }
62239beb93cSSam Leffler
62339beb93cSSam Leffler
wps_process_r_snonce1(struct wps_data * wps,const u8 * r_snonce1)62439beb93cSSam Leffler static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
62539beb93cSSam Leffler {
62639beb93cSSam Leffler u8 hash[SHA256_MAC_LEN];
62739beb93cSSam Leffler const u8 *addr[4];
62839beb93cSSam Leffler size_t len[4];
62939beb93cSSam Leffler
63039beb93cSSam Leffler if (r_snonce1 == NULL) {
63139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
63239beb93cSSam Leffler return -1;
63339beb93cSSam Leffler }
63439beb93cSSam Leffler
63539beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
63639beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
63739beb93cSSam Leffler
63839beb93cSSam Leffler /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
63939beb93cSSam Leffler addr[0] = r_snonce1;
64039beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
64139beb93cSSam Leffler addr[1] = wps->psk1;
64239beb93cSSam Leffler len[1] = WPS_PSK_LEN;
64339beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
64439beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
64539beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
64639beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
64739beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
64839beb93cSSam Leffler
6495b9c547cSRui Paulo if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
65039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
65139beb93cSSam Leffler "not match with the pre-committed value");
65239beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
6535b9c547cSRui Paulo wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr);
65439beb93cSSam Leffler return -1;
65539beb93cSSam Leffler }
65639beb93cSSam Leffler
65739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
65839beb93cSSam Leffler "half of the device password");
65939beb93cSSam Leffler
66039beb93cSSam Leffler return 0;
66139beb93cSSam Leffler }
66239beb93cSSam Leffler
66339beb93cSSam Leffler
wps_process_r_snonce2(struct wps_data * wps,const u8 * r_snonce2)66439beb93cSSam Leffler static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
66539beb93cSSam Leffler {
66639beb93cSSam Leffler u8 hash[SHA256_MAC_LEN];
66739beb93cSSam Leffler const u8 *addr[4];
66839beb93cSSam Leffler size_t len[4];
66939beb93cSSam Leffler
67039beb93cSSam Leffler if (r_snonce2 == NULL) {
67139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
67239beb93cSSam Leffler return -1;
67339beb93cSSam Leffler }
67439beb93cSSam Leffler
67539beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
67639beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
67739beb93cSSam Leffler
67839beb93cSSam Leffler /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
67939beb93cSSam Leffler addr[0] = r_snonce2;
68039beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
68139beb93cSSam Leffler addr[1] = wps->psk2;
68239beb93cSSam Leffler len[1] = WPS_PSK_LEN;
68339beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
68439beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
68539beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
68639beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
68739beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
68839beb93cSSam Leffler
6895b9c547cSRui Paulo if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
69039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
69139beb93cSSam Leffler "not match with the pre-committed value");
69239beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
6935b9c547cSRui Paulo wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr);
69439beb93cSSam Leffler return -1;
69539beb93cSSam Leffler }
69639beb93cSSam Leffler
69739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
69839beb93cSSam Leffler "half of the device password");
69939beb93cSSam Leffler
70039beb93cSSam Leffler return 0;
70139beb93cSSam Leffler }
70239beb93cSSam Leffler
70339beb93cSSam Leffler
wps_process_cred_e(struct wps_data * wps,const u8 * cred,size_t cred_len,int wps2)70439beb93cSSam Leffler static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
705f05cddf9SRui Paulo size_t cred_len, int wps2)
70639beb93cSSam Leffler {
70739beb93cSSam Leffler struct wps_parse_attr attr;
70839beb93cSSam Leffler struct wpabuf msg;
709f05cddf9SRui Paulo int ret = 0;
71039beb93cSSam Leffler
71139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received Credential");
71239beb93cSSam Leffler os_memset(&wps->cred, 0, sizeof(wps->cred));
71339beb93cSSam Leffler wpabuf_set(&msg, cred, cred_len);
71439beb93cSSam Leffler if (wps_parse_msg(&msg, &attr) < 0 ||
71539beb93cSSam Leffler wps_process_cred(&attr, &wps->cred))
71639beb93cSSam Leffler return -1;
71739beb93cSSam Leffler
718*a90b9d01SCy Schubert if (!ether_addr_equal(wps->cred.mac_addr, wps->wps->dev.mac_addr)) {
7193157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
7203157ba21SRui Paulo MACSTR ") does not match with own address (" MACSTR
7213157ba21SRui Paulo ")", MAC2STR(wps->cred.mac_addr),
7223157ba21SRui Paulo MAC2STR(wps->wps->dev.mac_addr));
7233157ba21SRui Paulo /*
7243157ba21SRui Paulo * In theory, this could be consider fatal error, but there are
7253157ba21SRui Paulo * number of deployed implementations using other address here
7263157ba21SRui Paulo * due to unclarity in the specification. For interoperability
7273157ba21SRui Paulo * reasons, allow this to be processed since we do not really
7283157ba21SRui Paulo * use the MAC Address information for anything.
7293157ba21SRui Paulo */
730f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
731f05cddf9SRui Paulo if (wps2) {
732f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
733f05cddf9SRui Paulo "MAC Address in AP Settings");
734f05cddf9SRui Paulo return -1;
7353157ba21SRui Paulo }
736f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
737f05cddf9SRui Paulo }
738f05cddf9SRui Paulo
739f05cddf9SRui Paulo if (!(wps->cred.encr_type &
740f05cddf9SRui Paulo (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
741f05cddf9SRui Paulo if (wps->cred.encr_type & WPS_ENCR_WEP) {
742f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject Credential "
743f05cddf9SRui Paulo "due to WEP configuration");
744f05cddf9SRui Paulo wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
745f05cddf9SRui Paulo return -2;
746f05cddf9SRui Paulo }
747f05cddf9SRui Paulo
748f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
749f05cddf9SRui Paulo "invalid encr_type 0x%x", wps->cred.encr_type);
750f05cddf9SRui Paulo return -1;
751f05cddf9SRui Paulo }
7523157ba21SRui Paulo
75339beb93cSSam Leffler if (wps->wps->cred_cb) {
75439beb93cSSam Leffler wps->cred.cred_attr = cred - 4;
75539beb93cSSam Leffler wps->cred.cred_attr_len = cred_len + 4;
756f05cddf9SRui Paulo ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
75739beb93cSSam Leffler wps->cred.cred_attr = NULL;
75839beb93cSSam Leffler wps->cred.cred_attr_len = 0;
75939beb93cSSam Leffler }
76039beb93cSSam Leffler
761f05cddf9SRui Paulo return ret;
76239beb93cSSam Leffler }
76339beb93cSSam Leffler
76439beb93cSSam Leffler
wps_process_creds(struct wps_data * wps,const u8 * cred[],u16 cred_len[],unsigned int num_cred,int wps2)76539beb93cSSam Leffler static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
766325151a3SRui Paulo u16 cred_len[], unsigned int num_cred, int wps2)
76739beb93cSSam Leffler {
76839beb93cSSam Leffler size_t i;
769f05cddf9SRui Paulo int ok = 0;
77039beb93cSSam Leffler
77139beb93cSSam Leffler if (wps->wps->ap)
77239beb93cSSam Leffler return 0;
77339beb93cSSam Leffler
77439beb93cSSam Leffler if (num_cred == 0) {
77539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
77639beb93cSSam Leffler "received");
77739beb93cSSam Leffler return -1;
77839beb93cSSam Leffler }
77939beb93cSSam Leffler
78039beb93cSSam Leffler for (i = 0; i < num_cred; i++) {
781f05cddf9SRui Paulo int res;
782f05cddf9SRui Paulo res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
783f05cddf9SRui Paulo if (res == 0)
784f05cddf9SRui Paulo ok++;
785f05cddf9SRui Paulo else if (res == -2)
786f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped");
787f05cddf9SRui Paulo else
788f05cddf9SRui Paulo return -1;
789f05cddf9SRui Paulo }
790f05cddf9SRui Paulo
791f05cddf9SRui Paulo if (ok == 0) {
792f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute "
793f05cddf9SRui Paulo "received");
79439beb93cSSam Leffler return -1;
79539beb93cSSam Leffler }
79639beb93cSSam Leffler
79739beb93cSSam Leffler return 0;
79839beb93cSSam Leffler }
79939beb93cSSam Leffler
80039beb93cSSam Leffler
wps_process_ap_settings_e(struct wps_data * wps,struct wps_parse_attr * attr,struct wpabuf * attrs,int wps2)80139beb93cSSam Leffler static int wps_process_ap_settings_e(struct wps_data *wps,
80239beb93cSSam Leffler struct wps_parse_attr *attr,
803f05cddf9SRui Paulo struct wpabuf *attrs, int wps2)
80439beb93cSSam Leffler {
80539beb93cSSam Leffler struct wps_credential cred;
806325151a3SRui Paulo int ret = 0;
80739beb93cSSam Leffler
80839beb93cSSam Leffler if (!wps->wps->ap)
80939beb93cSSam Leffler return 0;
81039beb93cSSam Leffler
81139beb93cSSam Leffler if (wps_process_ap_settings(attr, &cred) < 0)
81239beb93cSSam Leffler return -1;
81339beb93cSSam Leffler
81439beb93cSSam Leffler wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
81539beb93cSSam Leffler "Registrar");
81639beb93cSSam Leffler
817*a90b9d01SCy Schubert if (!ether_addr_equal(cred.mac_addr, wps->wps->dev.mac_addr)) {
8183157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings ("
8193157ba21SRui Paulo MACSTR ") does not match with own address (" MACSTR
8203157ba21SRui Paulo ")", MAC2STR(cred.mac_addr),
8213157ba21SRui Paulo MAC2STR(wps->wps->dev.mac_addr));
8223157ba21SRui Paulo /*
8233157ba21SRui Paulo * In theory, this could be consider fatal error, but there are
8243157ba21SRui Paulo * number of deployed implementations using other address here
8253157ba21SRui Paulo * due to unclarity in the specification. For interoperability
8263157ba21SRui Paulo * reasons, allow this to be processed since we do not really
8273157ba21SRui Paulo * use the MAC Address information for anything.
8283157ba21SRui Paulo */
829f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
830f05cddf9SRui Paulo if (wps2) {
831f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
832f05cddf9SRui Paulo "MAC Address in AP Settings");
833f05cddf9SRui Paulo return -1;
8343157ba21SRui Paulo }
835f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
836f05cddf9SRui Paulo }
837f05cddf9SRui Paulo
838f05cddf9SRui Paulo if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
839f05cddf9SRui Paulo {
840f05cddf9SRui Paulo if (cred.encr_type & WPS_ENCR_WEP) {
841f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
842f05cddf9SRui Paulo "due to WEP configuration");
843f05cddf9SRui Paulo wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED;
844f05cddf9SRui Paulo return -1;
845f05cddf9SRui Paulo }
846f05cddf9SRui Paulo
847f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
848f05cddf9SRui Paulo "invalid encr_type 0x%x", cred.encr_type);
849f05cddf9SRui Paulo return -1;
850f05cddf9SRui Paulo }
851f05cddf9SRui Paulo
852f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
853f05cddf9SRui Paulo if (wps2) {
854f05cddf9SRui Paulo if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
855f05cddf9SRui Paulo WPS_ENCR_TKIP ||
856f05cddf9SRui Paulo (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
857f05cddf9SRui Paulo WPS_AUTH_WPAPSK) {
858f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 "
859f05cddf9SRui Paulo "AP Settings: WPA-Personal/TKIP only");
860f05cddf9SRui Paulo wps->error_indication =
861f05cddf9SRui Paulo WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED;
862f05cddf9SRui Paulo return -1;
863f05cddf9SRui Paulo }
864f05cddf9SRui Paulo }
865f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
866f05cddf9SRui Paulo
867f05cddf9SRui Paulo if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
868f05cddf9SRui Paulo {
869f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
870f05cddf9SRui Paulo "TKIP+AES");
871f05cddf9SRui Paulo cred.encr_type |= WPS_ENCR_AES;
872f05cddf9SRui Paulo }
873f05cddf9SRui Paulo
874f05cddf9SRui Paulo if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
875f05cddf9SRui Paulo WPS_AUTH_WPAPSK) {
876f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
877f05cddf9SRui Paulo "WPAPSK+WPA2PSK");
878f05cddf9SRui Paulo cred.auth_type |= WPS_AUTH_WPA2PSK;
879f05cddf9SRui Paulo }
8803157ba21SRui Paulo
881c1d255d3SCy Schubert #ifdef CONFIG_NO_TKIP
882c1d255d3SCy Schubert if (cred.encr_type & WPS_ENCR_TKIP) {
883c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "WPS: Disable encr_type TKIP");
884c1d255d3SCy Schubert cred.encr_type &= ~WPS_ENCR_TKIP;
885c1d255d3SCy Schubert }
886c1d255d3SCy Schubert if (cred.auth_type & WPS_AUTH_WPAPSK) {
887c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "WPS: Disable auth_type WPAPSK");
888c1d255d3SCy Schubert cred.auth_type &= ~WPS_AUTH_WPAPSK;
889c1d255d3SCy Schubert }
890c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
891c1d255d3SCy Schubert
89239beb93cSSam Leffler if (wps->wps->cred_cb) {
89339beb93cSSam Leffler cred.cred_attr = wpabuf_head(attrs);
89439beb93cSSam Leffler cred.cred_attr_len = wpabuf_len(attrs);
895325151a3SRui Paulo ret = wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
89639beb93cSSam Leffler }
89739beb93cSSam Leffler
898325151a3SRui Paulo return ret;
89939beb93cSSam Leffler }
90039beb93cSSam Leffler
90139beb93cSSam Leffler
wps_process_dev_pw_id(struct wps_data * wps,const u8 * dev_pw_id)9025b9c547cSRui Paulo static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
9035b9c547cSRui Paulo {
9045b9c547cSRui Paulo u16 id;
9055b9c547cSRui Paulo
9065b9c547cSRui Paulo if (dev_pw_id == NULL) {
9075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
9085b9c547cSRui Paulo return -1;
9095b9c547cSRui Paulo }
9105b9c547cSRui Paulo
9115b9c547cSRui Paulo id = WPA_GET_BE16(dev_pw_id);
9125b9c547cSRui Paulo if (wps->dev_pw_id == id) {
9135b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
9145b9c547cSRui Paulo return 0;
9155b9c547cSRui Paulo }
9165b9c547cSRui Paulo
9175b9c547cSRui Paulo #ifdef CONFIG_P2P
9185b9c547cSRui Paulo if ((id == DEV_PW_DEFAULT &&
9195b9c547cSRui Paulo wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) ||
9205b9c547cSRui Paulo (id == DEV_PW_REGISTRAR_SPECIFIED &&
9215b9c547cSRui Paulo wps->dev_pw_id == DEV_PW_DEFAULT)) {
9225b9c547cSRui Paulo /*
9235b9c547cSRui Paulo * Common P2P use cases indicate whether the PIN is from the
9245b9c547cSRui Paulo * client or GO using Device Password Id in M1/M2 in a way that
9255b9c547cSRui Paulo * does not look fully compliant with WSC specification. Anyway,
9265b9c547cSRui Paulo * this is deployed and needs to be allowed, so ignore changes
9275b9c547cSRui Paulo * between Registrar-Specified and Default PIN.
9285b9c547cSRui Paulo */
9295b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID "
9305b9c547cSRui Paulo "change");
9315b9c547cSRui Paulo return 0;
9325b9c547cSRui Paulo }
9335b9c547cSRui Paulo #endif /* CONFIG_P2P */
9345b9c547cSRui Paulo
9355b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
9365b9c547cSRui Paulo "ID from %u to %u", wps->dev_pw_id, id);
9375b9c547cSRui Paulo
9385b9c547cSRui Paulo if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) {
9395b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
9405b9c547cSRui Paulo "WPS: Workaround - ignore PBC-to-PIN change");
9415b9c547cSRui Paulo return 0;
9425b9c547cSRui Paulo }
9435b9c547cSRui Paulo
9445b9c547cSRui Paulo if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
9455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
9465b9c547cSRui Paulo bin_clear_free(wps->dev_password, wps->dev_password_len);
9475b9c547cSRui Paulo wps->dev_pw_id = wps->alt_dev_pw_id;
9485b9c547cSRui Paulo wps->dev_password = wps->alt_dev_password;
9495b9c547cSRui Paulo wps->dev_password_len = wps->alt_dev_password_len;
9505b9c547cSRui Paulo wps->alt_dev_password = NULL;
9515b9c547cSRui Paulo wps->alt_dev_password_len = 0;
9525b9c547cSRui Paulo return 0;
9535b9c547cSRui Paulo }
9545b9c547cSRui Paulo
9555b9c547cSRui Paulo return -1;
9565b9c547cSRui Paulo }
9575b9c547cSRui Paulo
9585b9c547cSRui Paulo
wps_process_m2(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)95939beb93cSSam Leffler static enum wps_process_res wps_process_m2(struct wps_data *wps,
96039beb93cSSam Leffler const struct wpabuf *msg,
96139beb93cSSam Leffler struct wps_parse_attr *attr)
96239beb93cSSam Leffler {
96339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M2");
96439beb93cSSam Leffler
96539beb93cSSam Leffler if (wps->state != RECV_M2) {
96639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
96739beb93cSSam Leffler "receiving M2", wps->state);
96839beb93cSSam Leffler wps->state = SEND_WSC_NACK;
96939beb93cSSam Leffler return WPS_CONTINUE;
97039beb93cSSam Leffler }
97139beb93cSSam Leffler
97239beb93cSSam Leffler if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
97339beb93cSSam Leffler wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
9745b9c547cSRui Paulo wps_process_uuid_r(wps, attr->uuid_r) ||
9755b9c547cSRui Paulo wps_process_dev_pw_id(wps, attr->dev_password_id)) {
97639beb93cSSam Leffler wps->state = SEND_WSC_NACK;
97739beb93cSSam Leffler return WPS_CONTINUE;
97839beb93cSSam Leffler }
97939beb93cSSam Leffler
980f05cddf9SRui Paulo /*
981f05cddf9SRui Paulo * Stop here on an AP as an Enrollee if AP Setup is locked unless the
982f05cddf9SRui Paulo * special locked mode is used to allow protocol run up to M7 in order
983f05cddf9SRui Paulo * to support external Registrars that only learn the current AP
984f05cddf9SRui Paulo * configuration without changing it.
985f05cddf9SRui Paulo */
986e28a4053SRui Paulo if (wps->wps->ap &&
987f05cddf9SRui Paulo ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) ||
988f05cddf9SRui Paulo wps->dev_password == NULL)) {
98939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
99039beb93cSSam Leffler "registration of a new Registrar");
99139beb93cSSam Leffler wps->config_error = WPS_CFG_SETUP_LOCKED;
99239beb93cSSam Leffler wps->state = SEND_WSC_NACK;
99339beb93cSSam Leffler return WPS_CONTINUE;
99439beb93cSSam Leffler }
99539beb93cSSam Leffler
996e28a4053SRui Paulo if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
997e28a4053SRui Paulo wps_process_authenticator(wps, attr->authenticator, msg) ||
998e28a4053SRui Paulo wps_process_device_attrs(&wps->peer_dev, attr)) {
999e28a4053SRui Paulo wps->state = SEND_WSC_NACK;
1000e28a4053SRui Paulo return WPS_CONTINUE;
1001e28a4053SRui Paulo }
1002e28a4053SRui Paulo
10035b9c547cSRui Paulo #ifdef CONFIG_WPS_NFC
10045b9c547cSRui Paulo if (wps->peer_pubkey_hash_set) {
10055b9c547cSRui Paulo struct wpabuf *decrypted;
10065b9c547cSRui Paulo struct wps_parse_attr eattr;
10075b9c547cSRui Paulo
10085b9c547cSRui Paulo decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
10095b9c547cSRui Paulo attr->encr_settings_len);
10105b9c547cSRui Paulo if (decrypted == NULL) {
10115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt "
10125b9c547cSRui Paulo "Encrypted Settings attribute");
10135b9c547cSRui Paulo wps->state = SEND_WSC_NACK;
10145b9c547cSRui Paulo return WPS_CONTINUE;
10155b9c547cSRui Paulo }
10165b9c547cSRui Paulo
10175b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted "
10185b9c547cSRui Paulo "Settings attribute");
10195b9c547cSRui Paulo if (wps_parse_msg(decrypted, &eattr) < 0 ||
10205b9c547cSRui Paulo wps_process_key_wrap_auth(wps, decrypted,
10215b9c547cSRui Paulo eattr.key_wrap_auth) ||
10225b9c547cSRui Paulo wps_process_creds(wps, eattr.cred, eattr.cred_len,
10235b9c547cSRui Paulo eattr.num_cred, attr->version2 != NULL)) {
1024780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
10255b9c547cSRui Paulo wps->state = SEND_WSC_NACK;
10265b9c547cSRui Paulo return WPS_CONTINUE;
10275b9c547cSRui Paulo }
1028780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
10295b9c547cSRui Paulo
10305b9c547cSRui Paulo wps->state = WPS_MSG_DONE;
10315b9c547cSRui Paulo return WPS_CONTINUE;
10325b9c547cSRui Paulo }
10335b9c547cSRui Paulo #endif /* CONFIG_WPS_NFC */
10345b9c547cSRui Paulo
103539beb93cSSam Leffler wps->state = SEND_M3;
103639beb93cSSam Leffler return WPS_CONTINUE;
103739beb93cSSam Leffler }
103839beb93cSSam Leffler
103939beb93cSSam Leffler
wps_process_m2d(struct wps_data * wps,struct wps_parse_attr * attr)104039beb93cSSam Leffler static enum wps_process_res wps_process_m2d(struct wps_data *wps,
104139beb93cSSam Leffler struct wps_parse_attr *attr)
104239beb93cSSam Leffler {
104339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M2D");
104439beb93cSSam Leffler
104539beb93cSSam Leffler if (wps->state != RECV_M2) {
104639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
104739beb93cSSam Leffler "receiving M2D", wps->state);
104839beb93cSSam Leffler wps->state = SEND_WSC_NACK;
104939beb93cSSam Leffler return WPS_CONTINUE;
105039beb93cSSam Leffler }
105139beb93cSSam Leffler
105239beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
105339beb93cSSam Leffler attr->manufacturer, attr->manufacturer_len);
105439beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
105539beb93cSSam Leffler attr->model_name, attr->model_name_len);
105639beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
105739beb93cSSam Leffler attr->model_number, attr->model_number_len);
105839beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
105939beb93cSSam Leffler attr->serial_number, attr->serial_number_len);
106039beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
106139beb93cSSam Leffler attr->dev_name, attr->dev_name_len);
106239beb93cSSam Leffler
106339beb93cSSam Leffler if (wps->wps->event_cb) {
106439beb93cSSam Leffler union wps_event_data data;
106539beb93cSSam Leffler struct wps_event_m2d *m2d = &data.m2d;
106639beb93cSSam Leffler os_memset(&data, 0, sizeof(data));
106739beb93cSSam Leffler if (attr->config_methods)
106839beb93cSSam Leffler m2d->config_methods =
106939beb93cSSam Leffler WPA_GET_BE16(attr->config_methods);
107039beb93cSSam Leffler m2d->manufacturer = attr->manufacturer;
107139beb93cSSam Leffler m2d->manufacturer_len = attr->manufacturer_len;
107239beb93cSSam Leffler m2d->model_name = attr->model_name;
107339beb93cSSam Leffler m2d->model_name_len = attr->model_name_len;
107439beb93cSSam Leffler m2d->model_number = attr->model_number;
107539beb93cSSam Leffler m2d->model_number_len = attr->model_number_len;
107639beb93cSSam Leffler m2d->serial_number = attr->serial_number;
107739beb93cSSam Leffler m2d->serial_number_len = attr->serial_number_len;
107839beb93cSSam Leffler m2d->dev_name = attr->dev_name;
107939beb93cSSam Leffler m2d->dev_name_len = attr->dev_name_len;
108039beb93cSSam Leffler m2d->primary_dev_type = attr->primary_dev_type;
108139beb93cSSam Leffler if (attr->config_error)
108239beb93cSSam Leffler m2d->config_error =
108339beb93cSSam Leffler WPA_GET_BE16(attr->config_error);
108439beb93cSSam Leffler if (attr->dev_password_id)
108539beb93cSSam Leffler m2d->dev_password_id =
108639beb93cSSam Leffler WPA_GET_BE16(attr->dev_password_id);
108739beb93cSSam Leffler wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
108839beb93cSSam Leffler }
108939beb93cSSam Leffler
109039beb93cSSam Leffler wps->state = RECEIVED_M2D;
109139beb93cSSam Leffler return WPS_CONTINUE;
109239beb93cSSam Leffler }
109339beb93cSSam Leffler
109439beb93cSSam Leffler
wps_process_m4(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)109539beb93cSSam Leffler static enum wps_process_res wps_process_m4(struct wps_data *wps,
109639beb93cSSam Leffler const struct wpabuf *msg,
109739beb93cSSam Leffler struct wps_parse_attr *attr)
109839beb93cSSam Leffler {
109939beb93cSSam Leffler struct wpabuf *decrypted;
110039beb93cSSam Leffler struct wps_parse_attr eattr;
110139beb93cSSam Leffler
110239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M4");
110339beb93cSSam Leffler
110439beb93cSSam Leffler if (wps->state != RECV_M4) {
110539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
110639beb93cSSam Leffler "receiving M4", wps->state);
110739beb93cSSam Leffler wps->state = SEND_WSC_NACK;
110839beb93cSSam Leffler return WPS_CONTINUE;
110939beb93cSSam Leffler }
111039beb93cSSam Leffler
111139beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
111239beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg) ||
111339beb93cSSam Leffler wps_process_r_hash1(wps, attr->r_hash1) ||
111439beb93cSSam Leffler wps_process_r_hash2(wps, attr->r_hash2)) {
111539beb93cSSam Leffler wps->state = SEND_WSC_NACK;
111639beb93cSSam Leffler return WPS_CONTINUE;
111739beb93cSSam Leffler }
111839beb93cSSam Leffler
111939beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
112039beb93cSSam Leffler attr->encr_settings_len);
112139beb93cSSam Leffler if (decrypted == NULL) {
112239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
112339beb93cSSam Leffler "Settings attribute");
112439beb93cSSam Leffler wps->state = SEND_WSC_NACK;
112539beb93cSSam Leffler return WPS_CONTINUE;
112639beb93cSSam Leffler }
112739beb93cSSam Leffler
1128f05cddf9SRui Paulo if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
1129780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
1130f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
1131f05cddf9SRui Paulo return WPS_CONTINUE;
1132f05cddf9SRui Paulo }
1133f05cddf9SRui Paulo
113439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
113539beb93cSSam Leffler "attribute");
113639beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 ||
113739beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
113839beb93cSSam Leffler wps_process_r_snonce1(wps, eattr.r_snonce1)) {
1139780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
114039beb93cSSam Leffler wps->state = SEND_WSC_NACK;
114139beb93cSSam Leffler return WPS_CONTINUE;
114239beb93cSSam Leffler }
1143780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
114439beb93cSSam Leffler
114539beb93cSSam Leffler wps->state = SEND_M5;
114639beb93cSSam Leffler return WPS_CONTINUE;
114739beb93cSSam Leffler }
114839beb93cSSam Leffler
114939beb93cSSam Leffler
wps_process_m6(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)115039beb93cSSam Leffler static enum wps_process_res wps_process_m6(struct wps_data *wps,
115139beb93cSSam Leffler const struct wpabuf *msg,
115239beb93cSSam Leffler struct wps_parse_attr *attr)
115339beb93cSSam Leffler {
115439beb93cSSam Leffler struct wpabuf *decrypted;
115539beb93cSSam Leffler struct wps_parse_attr eattr;
115639beb93cSSam Leffler
115739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M6");
115839beb93cSSam Leffler
115939beb93cSSam Leffler if (wps->state != RECV_M6) {
116039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
116139beb93cSSam Leffler "receiving M6", wps->state);
116239beb93cSSam Leffler wps->state = SEND_WSC_NACK;
116339beb93cSSam Leffler return WPS_CONTINUE;
116439beb93cSSam Leffler }
116539beb93cSSam Leffler
116639beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
116739beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) {
116839beb93cSSam Leffler wps->state = SEND_WSC_NACK;
116939beb93cSSam Leffler return WPS_CONTINUE;
117039beb93cSSam Leffler }
117139beb93cSSam Leffler
117239beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
117339beb93cSSam Leffler attr->encr_settings_len);
117439beb93cSSam Leffler if (decrypted == NULL) {
117539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
117639beb93cSSam Leffler "Settings attribute");
117739beb93cSSam Leffler wps->state = SEND_WSC_NACK;
117839beb93cSSam Leffler return WPS_CONTINUE;
117939beb93cSSam Leffler }
118039beb93cSSam Leffler
1181f05cddf9SRui Paulo if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
1182780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
1183f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
1184f05cddf9SRui Paulo return WPS_CONTINUE;
1185f05cddf9SRui Paulo }
1186f05cddf9SRui Paulo
118739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
118839beb93cSSam Leffler "attribute");
118939beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 ||
119039beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
119139beb93cSSam Leffler wps_process_r_snonce2(wps, eattr.r_snonce2)) {
1192780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
119339beb93cSSam Leffler wps->state = SEND_WSC_NACK;
119439beb93cSSam Leffler return WPS_CONTINUE;
119539beb93cSSam Leffler }
1196780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
119739beb93cSSam Leffler
1198f05cddf9SRui Paulo if (wps->wps->ap)
1199f05cddf9SRui Paulo wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
1200f05cddf9SRui Paulo NULL);
1201f05cddf9SRui Paulo
120239beb93cSSam Leffler wps->state = SEND_M7;
120339beb93cSSam Leffler return WPS_CONTINUE;
120439beb93cSSam Leffler }
120539beb93cSSam Leffler
120639beb93cSSam Leffler
wps_process_m8(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)120739beb93cSSam Leffler static enum wps_process_res wps_process_m8(struct wps_data *wps,
120839beb93cSSam Leffler const struct wpabuf *msg,
120939beb93cSSam Leffler struct wps_parse_attr *attr)
121039beb93cSSam Leffler {
121139beb93cSSam Leffler struct wpabuf *decrypted;
121239beb93cSSam Leffler struct wps_parse_attr eattr;
121339beb93cSSam Leffler
121439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M8");
121539beb93cSSam Leffler
121639beb93cSSam Leffler if (wps->state != RECV_M8) {
121739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
121839beb93cSSam Leffler "receiving M8", wps->state);
121939beb93cSSam Leffler wps->state = SEND_WSC_NACK;
122039beb93cSSam Leffler return WPS_CONTINUE;
122139beb93cSSam Leffler }
122239beb93cSSam Leffler
122339beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
122439beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) {
122539beb93cSSam Leffler wps->state = SEND_WSC_NACK;
122639beb93cSSam Leffler return WPS_CONTINUE;
122739beb93cSSam Leffler }
122839beb93cSSam Leffler
1229f05cddf9SRui Paulo if (wps->wps->ap && wps->wps->ap_setup_locked) {
1230f05cddf9SRui Paulo /*
1231f05cddf9SRui Paulo * Stop here if special ap_setup_locked == 2 mode allowed the
1232f05cddf9SRui Paulo * protocol to continue beyond M2. This allows ER to learn the
1233f05cddf9SRui Paulo * current AP settings without changing them.
1234f05cddf9SRui Paulo */
1235f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
1236f05cddf9SRui Paulo "registration of a new Registrar");
1237f05cddf9SRui Paulo wps->config_error = WPS_CFG_SETUP_LOCKED;
1238f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
1239f05cddf9SRui Paulo return WPS_CONTINUE;
1240f05cddf9SRui Paulo }
1241f05cddf9SRui Paulo
124239beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
124339beb93cSSam Leffler attr->encr_settings_len);
124439beb93cSSam Leffler if (decrypted == NULL) {
124539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
124639beb93cSSam Leffler "Settings attribute");
124739beb93cSSam Leffler wps->state = SEND_WSC_NACK;
124839beb93cSSam Leffler return WPS_CONTINUE;
124939beb93cSSam Leffler }
125039beb93cSSam Leffler
1251f05cddf9SRui Paulo if (wps_validate_m8_encr(decrypted, wps->wps->ap,
1252f05cddf9SRui Paulo attr->version2 != NULL) < 0) {
1253780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
1254f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
1255f05cddf9SRui Paulo return WPS_CONTINUE;
1256f05cddf9SRui Paulo }
1257f05cddf9SRui Paulo
125839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
125939beb93cSSam Leffler "attribute");
126039beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 ||
126139beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
126239beb93cSSam Leffler wps_process_creds(wps, eattr.cred, eattr.cred_len,
1263f05cddf9SRui Paulo eattr.num_cred, attr->version2 != NULL) ||
1264f05cddf9SRui Paulo wps_process_ap_settings_e(wps, &eattr, decrypted,
1265f05cddf9SRui Paulo attr->version2 != NULL)) {
1266780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
126739beb93cSSam Leffler wps->state = SEND_WSC_NACK;
126839beb93cSSam Leffler return WPS_CONTINUE;
126939beb93cSSam Leffler }
1270780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
127139beb93cSSam Leffler
127239beb93cSSam Leffler wps->state = WPS_MSG_DONE;
127339beb93cSSam Leffler return WPS_CONTINUE;
127439beb93cSSam Leffler }
127539beb93cSSam Leffler
127639beb93cSSam Leffler
wps_process_wsc_msg(struct wps_data * wps,const struct wpabuf * msg)127739beb93cSSam Leffler static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
127839beb93cSSam Leffler const struct wpabuf *msg)
127939beb93cSSam Leffler {
128039beb93cSSam Leffler struct wps_parse_attr attr;
128139beb93cSSam Leffler enum wps_process_res ret = WPS_CONTINUE;
128239beb93cSSam Leffler
128339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
128439beb93cSSam Leffler
128539beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
128639beb93cSSam Leffler return WPS_FAILURE;
128739beb93cSSam Leffler
128839beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
1289f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
129039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
129139beb93cSSam Leffler return WPS_FAILURE;
129239beb93cSSam Leffler }
129339beb93cSSam Leffler
129439beb93cSSam Leffler if (attr.msg_type == NULL) {
129539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
1296f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
1297f05cddf9SRui Paulo return WPS_CONTINUE;
129839beb93cSSam Leffler }
129939beb93cSSam Leffler
130039beb93cSSam Leffler switch (*attr.msg_type) {
130139beb93cSSam Leffler case WPS_M2:
1302f05cddf9SRui Paulo if (wps_validate_m2(msg) < 0)
1303f05cddf9SRui Paulo return WPS_FAILURE;
130439beb93cSSam Leffler ret = wps_process_m2(wps, msg, &attr);
130539beb93cSSam Leffler break;
130639beb93cSSam Leffler case WPS_M2D:
1307f05cddf9SRui Paulo if (wps_validate_m2d(msg) < 0)
1308f05cddf9SRui Paulo return WPS_FAILURE;
130939beb93cSSam Leffler ret = wps_process_m2d(wps, &attr);
131039beb93cSSam Leffler break;
131139beb93cSSam Leffler case WPS_M4:
1312f05cddf9SRui Paulo if (wps_validate_m4(msg) < 0)
1313f05cddf9SRui Paulo return WPS_FAILURE;
131439beb93cSSam Leffler ret = wps_process_m4(wps, msg, &attr);
131539beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
1316f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M4, wps->config_error,
13175b9c547cSRui Paulo wps->error_indication,
13185b9c547cSRui Paulo wps->peer_dev.mac_addr);
131939beb93cSSam Leffler break;
132039beb93cSSam Leffler case WPS_M6:
1321f05cddf9SRui Paulo if (wps_validate_m6(msg) < 0)
1322f05cddf9SRui Paulo return WPS_FAILURE;
132339beb93cSSam Leffler ret = wps_process_m6(wps, msg, &attr);
132439beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
1325f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M6, wps->config_error,
13265b9c547cSRui Paulo wps->error_indication,
13275b9c547cSRui Paulo wps->peer_dev.mac_addr);
132839beb93cSSam Leffler break;
132939beb93cSSam Leffler case WPS_M8:
1330f05cddf9SRui Paulo if (wps_validate_m8(msg) < 0)
1331f05cddf9SRui Paulo return WPS_FAILURE;
133239beb93cSSam Leffler ret = wps_process_m8(wps, msg, &attr);
133339beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
1334f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M8, wps->config_error,
13355b9c547cSRui Paulo wps->error_indication,
13365b9c547cSRui Paulo wps->peer_dev.mac_addr);
133739beb93cSSam Leffler break;
133839beb93cSSam Leffler default:
133939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
134039beb93cSSam Leffler *attr.msg_type);
134139beb93cSSam Leffler return WPS_FAILURE;
134239beb93cSSam Leffler }
134339beb93cSSam Leffler
134439beb93cSSam Leffler /*
134539beb93cSSam Leffler * Save a copy of the last message for Authenticator derivation if we
134639beb93cSSam Leffler * are continuing. However, skip M2D since it is not authenticated and
134739beb93cSSam Leffler * neither is the ACK/NACK response frame. This allows the possibly
134839beb93cSSam Leffler * following M2 to be processed correctly by using the previously sent
134939beb93cSSam Leffler * M1 in Authenticator derivation.
135039beb93cSSam Leffler */
135139beb93cSSam Leffler if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
135239beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation
135339beb93cSSam Leffler */
135439beb93cSSam Leffler wpabuf_free(wps->last_msg);
135539beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg);
135639beb93cSSam Leffler }
135739beb93cSSam Leffler
135839beb93cSSam Leffler return ret;
135939beb93cSSam Leffler }
136039beb93cSSam Leffler
136139beb93cSSam Leffler
wps_process_wsc_ack(struct wps_data * wps,const struct wpabuf * msg)136239beb93cSSam Leffler static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
136339beb93cSSam Leffler const struct wpabuf *msg)
136439beb93cSSam Leffler {
136539beb93cSSam Leffler struct wps_parse_attr attr;
136639beb93cSSam Leffler
136739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
136839beb93cSSam Leffler
136939beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
137039beb93cSSam Leffler return WPS_FAILURE;
137139beb93cSSam Leffler
137239beb93cSSam Leffler if (attr.msg_type == NULL) {
137339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
137439beb93cSSam Leffler return WPS_FAILURE;
137539beb93cSSam Leffler }
137639beb93cSSam Leffler
137739beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_ACK) {
137839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
137939beb93cSSam Leffler *attr.msg_type);
138039beb93cSSam Leffler return WPS_FAILURE;
138139beb93cSSam Leffler }
138239beb93cSSam Leffler
138339beb93cSSam Leffler if (attr.registrar_nonce == NULL ||
1384f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
138539beb93cSSam Leffler {
138639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
138739beb93cSSam Leffler return WPS_FAILURE;
138839beb93cSSam Leffler }
138939beb93cSSam Leffler
139039beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
1391f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
139239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
139339beb93cSSam Leffler return WPS_FAILURE;
139439beb93cSSam Leffler }
139539beb93cSSam Leffler
139639beb93cSSam Leffler if (wps->state == RECV_ACK && wps->wps->ap) {
139739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
139839beb93cSSam Leffler "completed successfully");
13995b9c547cSRui Paulo wps_success_event(wps->wps, wps->peer_dev.mac_addr);
140039beb93cSSam Leffler wps->state = WPS_FINISHED;
140139beb93cSSam Leffler return WPS_DONE;
140239beb93cSSam Leffler }
140339beb93cSSam Leffler
140439beb93cSSam Leffler return WPS_FAILURE;
140539beb93cSSam Leffler }
140639beb93cSSam Leffler
140739beb93cSSam Leffler
wps_process_wsc_nack(struct wps_data * wps,const struct wpabuf * msg)140839beb93cSSam Leffler static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
140939beb93cSSam Leffler const struct wpabuf *msg)
141039beb93cSSam Leffler {
141139beb93cSSam Leffler struct wps_parse_attr attr;
1412f05cddf9SRui Paulo u16 config_error;
141339beb93cSSam Leffler
141439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
141539beb93cSSam Leffler
141639beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
141739beb93cSSam Leffler return WPS_FAILURE;
141839beb93cSSam Leffler
141939beb93cSSam Leffler if (attr.msg_type == NULL) {
142039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
142139beb93cSSam Leffler return WPS_FAILURE;
142239beb93cSSam Leffler }
142339beb93cSSam Leffler
142439beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_NACK) {
142539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
142639beb93cSSam Leffler *attr.msg_type);
142739beb93cSSam Leffler return WPS_FAILURE;
142839beb93cSSam Leffler }
142939beb93cSSam Leffler
143039beb93cSSam Leffler if (attr.registrar_nonce == NULL ||
1431f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
143239beb93cSSam Leffler {
143339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
143439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
143539beb93cSSam Leffler attr.registrar_nonce, WPS_NONCE_LEN);
143639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
143739beb93cSSam Leffler wps->nonce_r, WPS_NONCE_LEN);
143839beb93cSSam Leffler return WPS_FAILURE;
143939beb93cSSam Leffler }
144039beb93cSSam Leffler
144139beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
1442f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
144339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
144439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
144539beb93cSSam Leffler attr.enrollee_nonce, WPS_NONCE_LEN);
144639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
144739beb93cSSam Leffler wps->nonce_e, WPS_NONCE_LEN);
144839beb93cSSam Leffler return WPS_FAILURE;
144939beb93cSSam Leffler }
145039beb93cSSam Leffler
145139beb93cSSam Leffler if (attr.config_error == NULL) {
145239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
145339beb93cSSam Leffler "in WSC_NACK");
145439beb93cSSam Leffler return WPS_FAILURE;
145539beb93cSSam Leffler }
145639beb93cSSam Leffler
1457f05cddf9SRui Paulo config_error = WPA_GET_BE16(attr.config_error);
145839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
1459f05cddf9SRui Paulo "Configuration Error %d", config_error);
146039beb93cSSam Leffler
146139beb93cSSam Leffler switch (wps->state) {
146239beb93cSSam Leffler case RECV_M4:
1463f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M3, config_error,
14645b9c547cSRui Paulo wps->error_indication, wps->peer_dev.mac_addr);
146539beb93cSSam Leffler break;
146639beb93cSSam Leffler case RECV_M6:
1467f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M5, config_error,
14685b9c547cSRui Paulo wps->error_indication, wps->peer_dev.mac_addr);
146939beb93cSSam Leffler break;
147039beb93cSSam Leffler case RECV_M8:
1471f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M7, config_error,
14725b9c547cSRui Paulo wps->error_indication, wps->peer_dev.mac_addr);
147339beb93cSSam Leffler break;
147439beb93cSSam Leffler default:
147539beb93cSSam Leffler break;
147639beb93cSSam Leffler }
147739beb93cSSam Leffler
147839beb93cSSam Leffler /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
147939beb93cSSam Leffler * Enrollee is Authenticator */
148039beb93cSSam Leffler wps->state = SEND_WSC_NACK;
148139beb93cSSam Leffler
148239beb93cSSam Leffler return WPS_FAILURE;
148339beb93cSSam Leffler }
148439beb93cSSam Leffler
148539beb93cSSam Leffler
wps_enrollee_process_msg(struct wps_data * wps,enum wsc_op_code op_code,const struct wpabuf * msg)148639beb93cSSam Leffler enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
148739beb93cSSam Leffler enum wsc_op_code op_code,
148839beb93cSSam Leffler const struct wpabuf *msg)
148939beb93cSSam Leffler {
149039beb93cSSam Leffler
149139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
149239beb93cSSam Leffler "op_code=%d)",
149339beb93cSSam Leffler (unsigned long) wpabuf_len(msg), op_code);
149439beb93cSSam Leffler
14953157ba21SRui Paulo if (op_code == WSC_UPnP) {
14963157ba21SRui Paulo /* Determine the OpCode based on message type attribute */
14973157ba21SRui Paulo struct wps_parse_attr attr;
14983157ba21SRui Paulo if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
14993157ba21SRui Paulo if (*attr.msg_type == WPS_WSC_ACK)
15003157ba21SRui Paulo op_code = WSC_ACK;
15013157ba21SRui Paulo else if (*attr.msg_type == WPS_WSC_NACK)
15023157ba21SRui Paulo op_code = WSC_NACK;
15033157ba21SRui Paulo }
15043157ba21SRui Paulo }
15053157ba21SRui Paulo
150639beb93cSSam Leffler switch (op_code) {
150739beb93cSSam Leffler case WSC_MSG:
150839beb93cSSam Leffler case WSC_UPnP:
150939beb93cSSam Leffler return wps_process_wsc_msg(wps, msg);
151039beb93cSSam Leffler case WSC_ACK:
1511f05cddf9SRui Paulo if (wps_validate_wsc_ack(msg) < 0)
1512f05cddf9SRui Paulo return WPS_FAILURE;
151339beb93cSSam Leffler return wps_process_wsc_ack(wps, msg);
151439beb93cSSam Leffler case WSC_NACK:
1515f05cddf9SRui Paulo if (wps_validate_wsc_nack(msg) < 0)
1516f05cddf9SRui Paulo return WPS_FAILURE;
151739beb93cSSam Leffler return wps_process_wsc_nack(wps, msg);
151839beb93cSSam Leffler default:
151939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
152039beb93cSSam Leffler return WPS_FAILURE;
152139beb93cSSam Leffler }
152239beb93cSSam Leffler }
1523