1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Protected Setup - Enrollee 3e5b75505Sopenharmony_ci * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "crypto/crypto.h" 13e5b75505Sopenharmony_ci#include "crypto/sha256.h" 14e5b75505Sopenharmony_ci#include "crypto/random.h" 15e5b75505Sopenharmony_ci#include "wps_i.h" 16e5b75505Sopenharmony_ci#include "wps_dev_attr.h" 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_ci 19e5b75505Sopenharmony_cistatic int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg) 20e5b75505Sopenharmony_ci{ 21e5b75505Sopenharmony_ci u8 state; 22e5b75505Sopenharmony_ci if (wps->wps->ap) 23e5b75505Sopenharmony_ci state = wps->wps->wps_state; 24e5b75505Sopenharmony_ci else 25e5b75505Sopenharmony_ci state = WPS_STATE_NOT_CONFIGURED; 26e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", 27e5b75505Sopenharmony_ci state); 28e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_WPS_STATE); 29e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 1); 30e5b75505Sopenharmony_ci wpabuf_put_u8(msg, state); 31e5b75505Sopenharmony_ci return 0; 32e5b75505Sopenharmony_ci} 33e5b75505Sopenharmony_ci 34e5b75505Sopenharmony_ci 35e5b75505Sopenharmony_cistatic int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) 36e5b75505Sopenharmony_ci{ 37e5b75505Sopenharmony_ci u8 *hash; 38e5b75505Sopenharmony_ci const u8 *addr[4]; 39e5b75505Sopenharmony_ci size_t len[4]; 40e5b75505Sopenharmony_ci 41e5b75505Sopenharmony_ci if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) 42e5b75505Sopenharmony_ci return -1; 43e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN); 44e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-S2", 45e5b75505Sopenharmony_ci wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); 46e5b75505Sopenharmony_ci 47e5b75505Sopenharmony_ci if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { 48e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " 49e5b75505Sopenharmony_ci "E-Hash derivation"); 50e5b75505Sopenharmony_ci return -1; 51e5b75505Sopenharmony_ci } 52e5b75505Sopenharmony_ci 53e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * E-Hash1"); 54e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_E_HASH1); 55e5b75505Sopenharmony_ci wpabuf_put_be16(msg, SHA256_MAC_LEN); 56e5b75505Sopenharmony_ci hash = wpabuf_put(msg, SHA256_MAC_LEN); 57e5b75505Sopenharmony_ci /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ 58e5b75505Sopenharmony_ci addr[0] = wps->snonce; 59e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 60e5b75505Sopenharmony_ci addr[1] = wps->psk1; 61e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 62e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 63e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 64e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 65e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 66e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 67e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); 68e5b75505Sopenharmony_ci 69e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); 70e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_E_HASH2); 71e5b75505Sopenharmony_ci wpabuf_put_be16(msg, SHA256_MAC_LEN); 72e5b75505Sopenharmony_ci hash = wpabuf_put(msg, SHA256_MAC_LEN); 73e5b75505Sopenharmony_ci /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ 74e5b75505Sopenharmony_ci addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; 75e5b75505Sopenharmony_ci addr[1] = wps->psk2; 76e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 77e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); 78e5b75505Sopenharmony_ci 79e5b75505Sopenharmony_ci return 0; 80e5b75505Sopenharmony_ci} 81e5b75505Sopenharmony_ci 82e5b75505Sopenharmony_ci 83e5b75505Sopenharmony_cistatic int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg) 84e5b75505Sopenharmony_ci{ 85e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * E-SNonce1"); 86e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_E_SNONCE1); 87e5b75505Sopenharmony_ci wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 88e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); 89e5b75505Sopenharmony_ci return 0; 90e5b75505Sopenharmony_ci} 91e5b75505Sopenharmony_ci 92e5b75505Sopenharmony_ci 93e5b75505Sopenharmony_cistatic int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg) 94e5b75505Sopenharmony_ci{ 95e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * E-SNonce2"); 96e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_E_SNONCE2); 97e5b75505Sopenharmony_ci wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 98e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, 99e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 100e5b75505Sopenharmony_ci return 0; 101e5b75505Sopenharmony_ci} 102e5b75505Sopenharmony_ci 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m1(struct wps_data *wps) 105e5b75505Sopenharmony_ci{ 106e5b75505Sopenharmony_ci struct wpabuf *msg; 107e5b75505Sopenharmony_ci u16 config_methods; 108e5b75505Sopenharmony_ci u8 multi_ap_backhaul_sta = 0; 109e5b75505Sopenharmony_ci 110e5b75505Sopenharmony_ci if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) 111e5b75505Sopenharmony_ci return NULL; 112e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", 113e5b75505Sopenharmony_ci wps->nonce_e, WPS_NONCE_LEN); 114e5b75505Sopenharmony_ci 115e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M1"); 116e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 117e5b75505Sopenharmony_ci if (msg == NULL) 118e5b75505Sopenharmony_ci return NULL; 119e5b75505Sopenharmony_ci 120e5b75505Sopenharmony_ci config_methods = wps->wps->config_methods; 121e5b75505Sopenharmony_ci if (wps->wps->ap && !wps->pbc_in_m1 && 122e5b75505Sopenharmony_ci (wps->dev_password_len != 0 || 123e5b75505Sopenharmony_ci (config_methods & WPS_CONFIG_DISPLAY))) { 124e5b75505Sopenharmony_ci /* 125e5b75505Sopenharmony_ci * These are the methods that the AP supports as an Enrollee 126e5b75505Sopenharmony_ci * for adding external Registrars, so remove PushButton. 127e5b75505Sopenharmony_ci * 128e5b75505Sopenharmony_ci * As a workaround for Windows 7 mechanism for probing WPS 129e5b75505Sopenharmony_ci * capabilities from M1, leave PushButton option if no PIN 130e5b75505Sopenharmony_ci * method is available or if WPS configuration enables PBC 131e5b75505Sopenharmony_ci * workaround. 132e5b75505Sopenharmony_ci */ 133e5b75505Sopenharmony_ci config_methods &= ~WPS_CONFIG_PUSHBUTTON; 134e5b75505Sopenharmony_ci config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 135e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON); 136e5b75505Sopenharmony_ci } 137e5b75505Sopenharmony_ci 138e5b75505Sopenharmony_ci if (wps->multi_ap_backhaul_sta) 139e5b75505Sopenharmony_ci multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA; 140e5b75505Sopenharmony_ci 141e5b75505Sopenharmony_ci if (wps_build_version(msg) || 142e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M1) || 143e5b75505Sopenharmony_ci wps_build_uuid_e(msg, wps->uuid_e) || 144e5b75505Sopenharmony_ci wps_build_mac_addr(msg, wps->mac_addr_e) || 145e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 146e5b75505Sopenharmony_ci wps_build_public_key(wps, msg) || 147e5b75505Sopenharmony_ci wps_build_auth_type_flags(wps, msg) || 148e5b75505Sopenharmony_ci wps_build_encr_type_flags(wps, msg) || 149e5b75505Sopenharmony_ci wps_build_conn_type_flags(wps, msg) || 150e5b75505Sopenharmony_ci wps_build_config_methods(msg, config_methods) || 151e5b75505Sopenharmony_ci wps_build_wps_state(wps, msg) || 152e5b75505Sopenharmony_ci wps_build_device_attrs(&wps->wps->dev, msg) || 153e5b75505Sopenharmony_ci wps_build_rf_bands(&wps->wps->dev, msg, 154e5b75505Sopenharmony_ci wps->wps->rf_band_cb(wps->wps->cb_ctx)) || 155e5b75505Sopenharmony_ci wps_build_assoc_state(wps, msg) || 156e5b75505Sopenharmony_ci wps_build_dev_password_id(msg, wps->dev_pw_id) || 157e5b75505Sopenharmony_ci wps_build_config_error(msg, WPS_CFG_NO_ERROR) || 158e5b75505Sopenharmony_ci wps_build_os_version(&wps->wps->dev, msg) || 159e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) || 160e5b75505Sopenharmony_ci wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { 161e5b75505Sopenharmony_ci wpabuf_free(msg); 162e5b75505Sopenharmony_ci return NULL; 163e5b75505Sopenharmony_ci } 164e5b75505Sopenharmony_ci 165e5b75505Sopenharmony_ci wps->state = RECV_M2; 166e5b75505Sopenharmony_ci return msg; 167e5b75505Sopenharmony_ci} 168e5b75505Sopenharmony_ci 169e5b75505Sopenharmony_ci 170e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m3(struct wps_data *wps) 171e5b75505Sopenharmony_ci{ 172e5b75505Sopenharmony_ci struct wpabuf *msg; 173e5b75505Sopenharmony_ci 174e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M3"); 175e5b75505Sopenharmony_ci 176e5b75505Sopenharmony_ci if (wps->dev_password == NULL) { 177e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Device Password available"); 178e5b75505Sopenharmony_ci return NULL; 179e5b75505Sopenharmony_ci } 180e5b75505Sopenharmony_ci if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0) 181e5b75505Sopenharmony_ci return NULL; 182e5b75505Sopenharmony_ci 183e5b75505Sopenharmony_ci if (wps->wps->ap && random_pool_ready() != 1) { 184e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 185e5b75505Sopenharmony_ci "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used"); 186e5b75505Sopenharmony_ci return NULL; 187e5b75505Sopenharmony_ci } 188e5b75505Sopenharmony_ci 189e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 190e5b75505Sopenharmony_ci if (msg == NULL) 191e5b75505Sopenharmony_ci return NULL; 192e5b75505Sopenharmony_ci 193e5b75505Sopenharmony_ci if (wps_build_version(msg) || 194e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M3) || 195e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 196e5b75505Sopenharmony_ci wps_build_e_hash(wps, msg) || 197e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 198e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 199e5b75505Sopenharmony_ci wpabuf_free(msg); 200e5b75505Sopenharmony_ci return NULL; 201e5b75505Sopenharmony_ci } 202e5b75505Sopenharmony_ci 203e5b75505Sopenharmony_ci wps->state = RECV_M4; 204e5b75505Sopenharmony_ci return msg; 205e5b75505Sopenharmony_ci} 206e5b75505Sopenharmony_ci 207e5b75505Sopenharmony_ci 208e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m5(struct wps_data *wps) 209e5b75505Sopenharmony_ci{ 210e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 211e5b75505Sopenharmony_ci 212e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M5"); 213e5b75505Sopenharmony_ci 214e5b75505Sopenharmony_ci plain = wpabuf_alloc(200); 215e5b75505Sopenharmony_ci if (plain == NULL) 216e5b75505Sopenharmony_ci return NULL; 217e5b75505Sopenharmony_ci 218e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 219e5b75505Sopenharmony_ci if (msg == NULL) { 220e5b75505Sopenharmony_ci wpabuf_free(plain); 221e5b75505Sopenharmony_ci return NULL; 222e5b75505Sopenharmony_ci } 223e5b75505Sopenharmony_ci 224e5b75505Sopenharmony_ci if (wps_build_version(msg) || 225e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M5) || 226e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 227e5b75505Sopenharmony_ci wps_build_e_snonce1(wps, plain) || 228e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 229e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain) || 230e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 231e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 232e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 233e5b75505Sopenharmony_ci wpabuf_free(msg); 234e5b75505Sopenharmony_ci return NULL; 235e5b75505Sopenharmony_ci } 236e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 237e5b75505Sopenharmony_ci 238e5b75505Sopenharmony_ci wps->state = RECV_M6; 239e5b75505Sopenharmony_ci return msg; 240e5b75505Sopenharmony_ci} 241e5b75505Sopenharmony_ci 242e5b75505Sopenharmony_ci 243e5b75505Sopenharmony_cistatic int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg) 244e5b75505Sopenharmony_ci{ 245e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * SSID"); 246e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_SSID); 247e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wps->wps->ssid_len); 248e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len); 249e5b75505Sopenharmony_ci return 0; 250e5b75505Sopenharmony_ci} 251e5b75505Sopenharmony_ci 252e5b75505Sopenharmony_ci 253e5b75505Sopenharmony_cistatic int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg) 254e5b75505Sopenharmony_ci{ 255e5b75505Sopenharmony_ci u16 auth_type = wps->wps->ap_auth_type; 256e5b75505Sopenharmony_ci 257e5b75505Sopenharmony_ci /* 258e5b75505Sopenharmony_ci * Work around issues with Windows 7 WPS implementation not liking 259e5b75505Sopenharmony_ci * multiple Authentication Type bits in M7 AP Settings attribute by 260e5b75505Sopenharmony_ci * showing only the most secure option from current configuration. 261e5b75505Sopenharmony_ci */ 262e5b75505Sopenharmony_ci if (auth_type & WPS_AUTH_WPA2PSK) 263e5b75505Sopenharmony_ci auth_type = WPS_AUTH_WPA2PSK; 264e5b75505Sopenharmony_ci else if (auth_type & WPS_AUTH_WPAPSK) 265e5b75505Sopenharmony_ci auth_type = WPS_AUTH_WPAPSK; 266e5b75505Sopenharmony_ci else if (auth_type & WPS_AUTH_OPEN) 267e5b75505Sopenharmony_ci auth_type = WPS_AUTH_OPEN; 268e5b75505Sopenharmony_ci 269e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type); 270e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_AUTH_TYPE); 271e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 272e5b75505Sopenharmony_ci wpabuf_put_be16(msg, auth_type); 273e5b75505Sopenharmony_ci return 0; 274e5b75505Sopenharmony_ci} 275e5b75505Sopenharmony_ci 276e5b75505Sopenharmony_ci 277e5b75505Sopenharmony_cistatic int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg) 278e5b75505Sopenharmony_ci{ 279e5b75505Sopenharmony_ci u16 encr_type = wps->wps->ap_encr_type; 280e5b75505Sopenharmony_ci 281e5b75505Sopenharmony_ci /* 282e5b75505Sopenharmony_ci * Work around issues with Windows 7 WPS implementation not liking 283e5b75505Sopenharmony_ci * multiple Encryption Type bits in M7 AP Settings attribute by 284e5b75505Sopenharmony_ci * showing only the most secure option from current configuration. 285e5b75505Sopenharmony_ci */ 286e5b75505Sopenharmony_ci if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) { 287e5b75505Sopenharmony_ci if (encr_type & WPS_ENCR_AES) 288e5b75505Sopenharmony_ci encr_type = WPS_ENCR_AES; 289e5b75505Sopenharmony_ci else if (encr_type & WPS_ENCR_TKIP) 290e5b75505Sopenharmony_ci encr_type = WPS_ENCR_TKIP; 291e5b75505Sopenharmony_ci } 292e5b75505Sopenharmony_ci 293e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type); 294e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_ENCR_TYPE); 295e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 296e5b75505Sopenharmony_ci wpabuf_put_be16(msg, encr_type); 297e5b75505Sopenharmony_ci return 0; 298e5b75505Sopenharmony_ci} 299e5b75505Sopenharmony_ci 300e5b75505Sopenharmony_ci 301e5b75505Sopenharmony_cistatic int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg) 302e5b75505Sopenharmony_ci{ 303e5b75505Sopenharmony_ci if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) && 304e5b75505Sopenharmony_ci wps->wps->network_key_len == 0) { 305e5b75505Sopenharmony_ci char hex[65]; 306e5b75505Sopenharmony_ci u8 psk[32]; 307e5b75505Sopenharmony_ci /* Generate a random per-device PSK */ 308e5b75505Sopenharmony_ci if (random_pool_ready() != 1 || 309e5b75505Sopenharmony_ci random_get_bytes(psk, sizeof(psk)) < 0) { 310e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 311e5b75505Sopenharmony_ci "WPS: Could not generate random PSK"); 312e5b75505Sopenharmony_ci return -1; 313e5b75505Sopenharmony_ci } 314e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", 315e5b75505Sopenharmony_ci psk, sizeof(psk)); 316e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", 317e5b75505Sopenharmony_ci (unsigned int) wps->new_psk_len * 2); 318e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk)); 319e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_NETWORK_KEY); 320e5b75505Sopenharmony_ci wpabuf_put_be16(msg, sizeof(psk) * 2); 321e5b75505Sopenharmony_ci wpabuf_put_data(msg, hex, sizeof(psk) * 2); 322e5b75505Sopenharmony_ci if (wps->wps->registrar) { 323e5b75505Sopenharmony_ci wps_cb_new_psk(wps->wps->registrar, 324e5b75505Sopenharmony_ci wps->peer_dev.mac_addr, 325e5b75505Sopenharmony_ci wps->p2p_dev_addr, psk, sizeof(psk)); 326e5b75505Sopenharmony_ci } 327e5b75505Sopenharmony_ci return 0; 328e5b75505Sopenharmony_ci } 329e5b75505Sopenharmony_ci 330e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", 331e5b75505Sopenharmony_ci (unsigned int) wps->wps->network_key_len); 332e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_NETWORK_KEY); 333e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wps->wps->network_key_len); 334e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len); 335e5b75505Sopenharmony_ci return 0; 336e5b75505Sopenharmony_ci} 337e5b75505Sopenharmony_ci 338e5b75505Sopenharmony_ci 339e5b75505Sopenharmony_cistatic int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg) 340e5b75505Sopenharmony_ci{ 341e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * MAC Address (AP BSSID)"); 342e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_MAC_ADDR); 343e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ETH_ALEN); 344e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN); 345e5b75505Sopenharmony_ci return 0; 346e5b75505Sopenharmony_ci} 347e5b75505Sopenharmony_ci 348e5b75505Sopenharmony_ci 349e5b75505Sopenharmony_cistatic int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain) 350e5b75505Sopenharmony_ci{ 351e5b75505Sopenharmony_ci const u8 *start, *end; 352e5b75505Sopenharmony_ci int ret; 353e5b75505Sopenharmony_ci 354e5b75505Sopenharmony_ci if (wps->wps->ap_settings) { 355e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)"); 356e5b75505Sopenharmony_ci wpabuf_put_data(plain, wps->wps->ap_settings, 357e5b75505Sopenharmony_ci wps->wps->ap_settings_len); 358e5b75505Sopenharmony_ci return 0; 359e5b75505Sopenharmony_ci } 360e5b75505Sopenharmony_ci 361e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * AP Settings based on current configuration"); 362e5b75505Sopenharmony_ci start = wpabuf_put(plain, 0); 363e5b75505Sopenharmony_ci ret = wps_build_cred_ssid(wps, plain) || 364e5b75505Sopenharmony_ci wps_build_cred_mac_addr(wps, plain) || 365e5b75505Sopenharmony_ci wps_build_cred_auth_type(wps, plain) || 366e5b75505Sopenharmony_ci wps_build_cred_encr_type(wps, plain) || 367e5b75505Sopenharmony_ci wps_build_cred_network_key(wps, plain); 368e5b75505Sopenharmony_ci end = wpabuf_put(plain, 0); 369e5b75505Sopenharmony_ci 370e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Plaintext AP Settings", 371e5b75505Sopenharmony_ci start, end - start); 372e5b75505Sopenharmony_ci 373e5b75505Sopenharmony_ci return ret; 374e5b75505Sopenharmony_ci} 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci 377e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m7(struct wps_data *wps) 378e5b75505Sopenharmony_ci{ 379e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 380e5b75505Sopenharmony_ci 381e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M7"); 382e5b75505Sopenharmony_ci 383e5b75505Sopenharmony_ci plain = wpabuf_alloc(500 + wps->wps->ap_settings_len); 384e5b75505Sopenharmony_ci if (plain == NULL) 385e5b75505Sopenharmony_ci return NULL; 386e5b75505Sopenharmony_ci 387e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len); 388e5b75505Sopenharmony_ci if (msg == NULL) { 389e5b75505Sopenharmony_ci wpabuf_free(plain); 390e5b75505Sopenharmony_ci return NULL; 391e5b75505Sopenharmony_ci } 392e5b75505Sopenharmony_ci 393e5b75505Sopenharmony_ci if (wps_build_version(msg) || 394e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M7) || 395e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 396e5b75505Sopenharmony_ci wps_build_e_snonce2(wps, plain) || 397e5b75505Sopenharmony_ci (wps->wps->ap && wps_build_ap_settings(wps, plain)) || 398e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 399e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain) || 400e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 401e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 402e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 403e5b75505Sopenharmony_ci wpabuf_free(msg); 404e5b75505Sopenharmony_ci return NULL; 405e5b75505Sopenharmony_ci } 406e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 407e5b75505Sopenharmony_ci 408e5b75505Sopenharmony_ci if (wps->wps->ap && wps->wps->registrar) { 409e5b75505Sopenharmony_ci /* 410e5b75505Sopenharmony_ci * If the Registrar is only learning our current configuration, 411e5b75505Sopenharmony_ci * it may not continue protocol run to successful completion. 412e5b75505Sopenharmony_ci * Store information here to make sure it remains available. 413e5b75505Sopenharmony_ci */ 414e5b75505Sopenharmony_ci wps_device_store(wps->wps->registrar, &wps->peer_dev, 415e5b75505Sopenharmony_ci wps->uuid_r); 416e5b75505Sopenharmony_ci } 417e5b75505Sopenharmony_ci 418e5b75505Sopenharmony_ci wps->state = RECV_M8; 419e5b75505Sopenharmony_ci return msg; 420e5b75505Sopenharmony_ci} 421e5b75505Sopenharmony_ci 422e5b75505Sopenharmony_ci 423e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_wsc_done(struct wps_data *wps) 424e5b75505Sopenharmony_ci{ 425e5b75505Sopenharmony_ci struct wpabuf *msg; 426e5b75505Sopenharmony_ci 427e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done"); 428e5b75505Sopenharmony_ci 429e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 430e5b75505Sopenharmony_ci if (msg == NULL) 431e5b75505Sopenharmony_ci return NULL; 432e5b75505Sopenharmony_ci 433e5b75505Sopenharmony_ci if (wps_build_version(msg) || 434e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_WSC_DONE) || 435e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 436e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 437e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 438e5b75505Sopenharmony_ci wpabuf_free(msg); 439e5b75505Sopenharmony_ci return NULL; 440e5b75505Sopenharmony_ci } 441e5b75505Sopenharmony_ci 442e5b75505Sopenharmony_ci if (wps->wps->ap) 443e5b75505Sopenharmony_ci wps->state = RECV_ACK; 444e5b75505Sopenharmony_ci else { 445e5b75505Sopenharmony_ci wps_success_event(wps->wps, wps->peer_dev.mac_addr); 446e5b75505Sopenharmony_ci wps->state = WPS_FINISHED; 447e5b75505Sopenharmony_ci } 448e5b75505Sopenharmony_ci return msg; 449e5b75505Sopenharmony_ci} 450e5b75505Sopenharmony_ci 451e5b75505Sopenharmony_ci 452e5b75505Sopenharmony_cistruct wpabuf * wps_enrollee_get_msg(struct wps_data *wps, 453e5b75505Sopenharmony_ci enum wsc_op_code *op_code) 454e5b75505Sopenharmony_ci{ 455e5b75505Sopenharmony_ci struct wpabuf *msg; 456e5b75505Sopenharmony_ci 457e5b75505Sopenharmony_ci switch (wps->state) { 458e5b75505Sopenharmony_ci case SEND_M1: 459e5b75505Sopenharmony_ci msg = wps_build_m1(wps); 460e5b75505Sopenharmony_ci *op_code = WSC_MSG; 461e5b75505Sopenharmony_ci break; 462e5b75505Sopenharmony_ci case SEND_M3: 463e5b75505Sopenharmony_ci msg = wps_build_m3(wps); 464e5b75505Sopenharmony_ci *op_code = WSC_MSG; 465e5b75505Sopenharmony_ci break; 466e5b75505Sopenharmony_ci case SEND_M5: 467e5b75505Sopenharmony_ci msg = wps_build_m5(wps); 468e5b75505Sopenharmony_ci *op_code = WSC_MSG; 469e5b75505Sopenharmony_ci break; 470e5b75505Sopenharmony_ci case SEND_M7: 471e5b75505Sopenharmony_ci msg = wps_build_m7(wps); 472e5b75505Sopenharmony_ci *op_code = WSC_MSG; 473e5b75505Sopenharmony_ci break; 474e5b75505Sopenharmony_ci case RECEIVED_M2D: 475e5b75505Sopenharmony_ci if (wps->wps->ap) { 476e5b75505Sopenharmony_ci msg = wps_build_wsc_nack(wps); 477e5b75505Sopenharmony_ci *op_code = WSC_NACK; 478e5b75505Sopenharmony_ci break; 479e5b75505Sopenharmony_ci } 480e5b75505Sopenharmony_ci msg = wps_build_wsc_ack(wps); 481e5b75505Sopenharmony_ci *op_code = WSC_ACK; 482e5b75505Sopenharmony_ci if (msg) { 483e5b75505Sopenharmony_ci /* Another M2/M2D may be received */ 484e5b75505Sopenharmony_ci wps->state = RECV_M2; 485e5b75505Sopenharmony_ci } 486e5b75505Sopenharmony_ci break; 487e5b75505Sopenharmony_ci case SEND_WSC_NACK: 488e5b75505Sopenharmony_ci msg = wps_build_wsc_nack(wps); 489e5b75505Sopenharmony_ci *op_code = WSC_NACK; 490e5b75505Sopenharmony_ci break; 491e5b75505Sopenharmony_ci case WPS_MSG_DONE: 492e5b75505Sopenharmony_ci msg = wps_build_wsc_done(wps); 493e5b75505Sopenharmony_ci *op_code = WSC_Done; 494e5b75505Sopenharmony_ci break; 495e5b75505Sopenharmony_ci default: 496e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " 497e5b75505Sopenharmony_ci "a message", wps->state); 498e5b75505Sopenharmony_ci msg = NULL; 499e5b75505Sopenharmony_ci break; 500e5b75505Sopenharmony_ci } 501e5b75505Sopenharmony_ci 502e5b75505Sopenharmony_ci if (*op_code == WSC_MSG && msg) { 503e5b75505Sopenharmony_ci /* Save a copy of the last message for Authenticator derivation 504e5b75505Sopenharmony_ci */ 505e5b75505Sopenharmony_ci wpabuf_free(wps->last_msg); 506e5b75505Sopenharmony_ci wps->last_msg = wpabuf_dup(msg); 507e5b75505Sopenharmony_ci } 508e5b75505Sopenharmony_ci 509e5b75505Sopenharmony_ci return msg; 510e5b75505Sopenharmony_ci} 511e5b75505Sopenharmony_ci 512e5b75505Sopenharmony_ci 513e5b75505Sopenharmony_cistatic int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce) 514e5b75505Sopenharmony_ci{ 515e5b75505Sopenharmony_ci if (r_nonce == NULL) { 516e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); 517e5b75505Sopenharmony_ci return -1; 518e5b75505Sopenharmony_ci } 519e5b75505Sopenharmony_ci 520e5b75505Sopenharmony_ci os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN); 521e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", 522e5b75505Sopenharmony_ci wps->nonce_r, WPS_NONCE_LEN); 523e5b75505Sopenharmony_ci 524e5b75505Sopenharmony_ci return 0; 525e5b75505Sopenharmony_ci} 526e5b75505Sopenharmony_ci 527e5b75505Sopenharmony_ci 528e5b75505Sopenharmony_cistatic int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce) 529e5b75505Sopenharmony_ci{ 530e5b75505Sopenharmony_ci if (e_nonce == NULL) { 531e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); 532e5b75505Sopenharmony_ci return -1; 533e5b75505Sopenharmony_ci } 534e5b75505Sopenharmony_ci 535e5b75505Sopenharmony_ci if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) { 536e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received"); 537e5b75505Sopenharmony_ci return -1; 538e5b75505Sopenharmony_ci } 539e5b75505Sopenharmony_ci 540e5b75505Sopenharmony_ci return 0; 541e5b75505Sopenharmony_ci} 542e5b75505Sopenharmony_ci 543e5b75505Sopenharmony_ci 544e5b75505Sopenharmony_cistatic int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r) 545e5b75505Sopenharmony_ci{ 546e5b75505Sopenharmony_ci if (uuid_r == NULL) { 547e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No UUID-R received"); 548e5b75505Sopenharmony_ci return -1; 549e5b75505Sopenharmony_ci } 550e5b75505Sopenharmony_ci 551e5b75505Sopenharmony_ci os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN); 552e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); 553e5b75505Sopenharmony_ci 554e5b75505Sopenharmony_ci return 0; 555e5b75505Sopenharmony_ci} 556e5b75505Sopenharmony_ci 557e5b75505Sopenharmony_ci 558e5b75505Sopenharmony_cistatic int wps_process_pubkey(struct wps_data *wps, const u8 *pk, 559e5b75505Sopenharmony_ci size_t pk_len) 560e5b75505Sopenharmony_ci{ 561e5b75505Sopenharmony_ci if (pk == NULL || pk_len == 0) { 562e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); 563e5b75505Sopenharmony_ci return -1; 564e5b75505Sopenharmony_ci } 565e5b75505Sopenharmony_ci 566e5b75505Sopenharmony_ci if (wps->peer_pubkey_hash_set) { 567e5b75505Sopenharmony_ci u8 hash[WPS_HASH_LEN]; 568e5b75505Sopenharmony_ci sha256_vector(1, &pk, &pk_len, hash); 569e5b75505Sopenharmony_ci if (os_memcmp_const(hash, wps->peer_pubkey_hash, 570e5b75505Sopenharmony_ci WPS_OOB_PUBKEY_HASH_LEN) != 0) { 571e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch"); 572e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Received public key", 573e5b75505Sopenharmony_ci pk, pk_len); 574e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key " 575e5b75505Sopenharmony_ci "hash", hash, WPS_OOB_PUBKEY_HASH_LEN); 576e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash", 577e5b75505Sopenharmony_ci wps->peer_pubkey_hash, 578e5b75505Sopenharmony_ci WPS_OOB_PUBKEY_HASH_LEN); 579e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH; 580e5b75505Sopenharmony_ci return -1; 581e5b75505Sopenharmony_ci } 582e5b75505Sopenharmony_ci } 583e5b75505Sopenharmony_ci 584e5b75505Sopenharmony_ci wpabuf_free(wps->dh_pubkey_r); 585e5b75505Sopenharmony_ci wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len); 586e5b75505Sopenharmony_ci if (wps->dh_pubkey_r == NULL) 587e5b75505Sopenharmony_ci return -1; 588e5b75505Sopenharmony_ci 589e5b75505Sopenharmony_ci if (wps_derive_keys(wps) < 0) 590e5b75505Sopenharmony_ci return -1; 591e5b75505Sopenharmony_ci 592e5b75505Sopenharmony_ci return 0; 593e5b75505Sopenharmony_ci} 594e5b75505Sopenharmony_ci 595e5b75505Sopenharmony_ci 596e5b75505Sopenharmony_cistatic int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1) 597e5b75505Sopenharmony_ci{ 598e5b75505Sopenharmony_ci if (r_hash1 == NULL) { 599e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received"); 600e5b75505Sopenharmony_ci return -1; 601e5b75505Sopenharmony_ci } 602e5b75505Sopenharmony_ci 603e5b75505Sopenharmony_ci os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN); 604e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN); 605e5b75505Sopenharmony_ci 606e5b75505Sopenharmony_ci return 0; 607e5b75505Sopenharmony_ci} 608e5b75505Sopenharmony_ci 609e5b75505Sopenharmony_ci 610e5b75505Sopenharmony_cistatic int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2) 611e5b75505Sopenharmony_ci{ 612e5b75505Sopenharmony_ci if (r_hash2 == NULL) { 613e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received"); 614e5b75505Sopenharmony_ci return -1; 615e5b75505Sopenharmony_ci } 616e5b75505Sopenharmony_ci 617e5b75505Sopenharmony_ci os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN); 618e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN); 619e5b75505Sopenharmony_ci 620e5b75505Sopenharmony_ci return 0; 621e5b75505Sopenharmony_ci} 622e5b75505Sopenharmony_ci 623e5b75505Sopenharmony_ci 624e5b75505Sopenharmony_cistatic int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) 625e5b75505Sopenharmony_ci{ 626e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 627e5b75505Sopenharmony_ci const u8 *addr[4]; 628e5b75505Sopenharmony_ci size_t len[4]; 629e5b75505Sopenharmony_ci 630e5b75505Sopenharmony_ci if (r_snonce1 == NULL) { 631e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received"); 632e5b75505Sopenharmony_ci return -1; 633e5b75505Sopenharmony_ci } 634e5b75505Sopenharmony_ci 635e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1, 636e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 637e5b75505Sopenharmony_ci 638e5b75505Sopenharmony_ci /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ 639e5b75505Sopenharmony_ci addr[0] = r_snonce1; 640e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 641e5b75505Sopenharmony_ci addr[1] = wps->psk1; 642e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 643e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 644e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 645e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 646e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 647e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 648e5b75505Sopenharmony_ci 649e5b75505Sopenharmony_ci if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { 650e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " 651e5b75505Sopenharmony_ci "not match with the pre-committed value"); 652e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 653e5b75505Sopenharmony_ci wps_pwd_auth_fail_event(wps->wps, 1, 1, wps->peer_dev.mac_addr); 654e5b75505Sopenharmony_ci return -1; 655e5b75505Sopenharmony_ci } 656e5b75505Sopenharmony_ci 657e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first " 658e5b75505Sopenharmony_ci "half of the device password"); 659e5b75505Sopenharmony_ci 660e5b75505Sopenharmony_ci return 0; 661e5b75505Sopenharmony_ci} 662e5b75505Sopenharmony_ci 663e5b75505Sopenharmony_ci 664e5b75505Sopenharmony_cistatic int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) 665e5b75505Sopenharmony_ci{ 666e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 667e5b75505Sopenharmony_ci const u8 *addr[4]; 668e5b75505Sopenharmony_ci size_t len[4]; 669e5b75505Sopenharmony_ci 670e5b75505Sopenharmony_ci if (r_snonce2 == NULL) { 671e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received"); 672e5b75505Sopenharmony_ci return -1; 673e5b75505Sopenharmony_ci } 674e5b75505Sopenharmony_ci 675e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2, 676e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 677e5b75505Sopenharmony_ci 678e5b75505Sopenharmony_ci /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ 679e5b75505Sopenharmony_ci addr[0] = r_snonce2; 680e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 681e5b75505Sopenharmony_ci addr[1] = wps->psk2; 682e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 683e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 684e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 685e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 686e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 687e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 688e5b75505Sopenharmony_ci 689e5b75505Sopenharmony_ci if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { 690e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " 691e5b75505Sopenharmony_ci "not match with the pre-committed value"); 692e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 693e5b75505Sopenharmony_ci wps_pwd_auth_fail_event(wps->wps, 1, 2, wps->peer_dev.mac_addr); 694e5b75505Sopenharmony_ci return -1; 695e5b75505Sopenharmony_ci } 696e5b75505Sopenharmony_ci 697e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second " 698e5b75505Sopenharmony_ci "half of the device password"); 699e5b75505Sopenharmony_ci 700e5b75505Sopenharmony_ci return 0; 701e5b75505Sopenharmony_ci} 702e5b75505Sopenharmony_ci 703e5b75505Sopenharmony_ci 704e5b75505Sopenharmony_cistatic int wps_process_cred_e(struct wps_data *wps, const u8 *cred, 705e5b75505Sopenharmony_ci size_t cred_len, int wps2) 706e5b75505Sopenharmony_ci{ 707e5b75505Sopenharmony_ci struct wps_parse_attr attr; 708e5b75505Sopenharmony_ci struct wpabuf msg; 709e5b75505Sopenharmony_ci int ret = 0; 710e5b75505Sopenharmony_ci 711e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received Credential"); 712e5b75505Sopenharmony_ci os_memset(&wps->cred, 0, sizeof(wps->cred)); 713e5b75505Sopenharmony_ci wpabuf_set(&msg, cred, cred_len); 714e5b75505Sopenharmony_ci if (wps_parse_msg(&msg, &attr) < 0 || 715e5b75505Sopenharmony_ci wps_process_cred(&attr, &wps->cred)) 716e5b75505Sopenharmony_ci return -1; 717e5b75505Sopenharmony_ci 718e5b75505Sopenharmony_ci if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != 719e5b75505Sopenharmony_ci 0) { 720e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential (" 721e5b75505Sopenharmony_ci MACSTR ") does not match with own address (" MACSTR 722e5b75505Sopenharmony_ci ")", MAC2STR(wps->cred.mac_addr), 723e5b75505Sopenharmony_ci MAC2STR(wps->wps->dev.mac_addr)); 724e5b75505Sopenharmony_ci /* 725e5b75505Sopenharmony_ci * In theory, this could be consider fatal error, but there are 726e5b75505Sopenharmony_ci * number of deployed implementations using other address here 727e5b75505Sopenharmony_ci * due to unclarity in the specification. For interoperability 728e5b75505Sopenharmony_ci * reasons, allow this to be processed since we do not really 729e5b75505Sopenharmony_ci * use the MAC Address information for anything. 730e5b75505Sopenharmony_ci */ 731e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_STRICT 732e5b75505Sopenharmony_ci if (wps2) { 733e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " 734e5b75505Sopenharmony_ci "MAC Address in AP Settings"); 735e5b75505Sopenharmony_ci return -1; 736e5b75505Sopenharmony_ci } 737e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 738e5b75505Sopenharmony_ci } 739e5b75505Sopenharmony_ci 740e5b75505Sopenharmony_ci if (!(wps->cred.encr_type & 741e5b75505Sopenharmony_ci (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { 742e5b75505Sopenharmony_ci if (wps->cred.encr_type & WPS_ENCR_WEP) { 743e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject Credential " 744e5b75505Sopenharmony_ci "due to WEP configuration"); 745e5b75505Sopenharmony_ci wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; 746e5b75505Sopenharmony_ci return -2; 747e5b75505Sopenharmony_ci } 748e5b75505Sopenharmony_ci 749e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject Credential due to " 750e5b75505Sopenharmony_ci "invalid encr_type 0x%x", wps->cred.encr_type); 751e5b75505Sopenharmony_ci return -1; 752e5b75505Sopenharmony_ci } 753e5b75505Sopenharmony_ci 754e5b75505Sopenharmony_ci if (wps->wps->cred_cb) { 755e5b75505Sopenharmony_ci wps->cred.cred_attr = cred - 4; 756e5b75505Sopenharmony_ci wps->cred.cred_attr_len = cred_len + 4; 757e5b75505Sopenharmony_ci ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); 758e5b75505Sopenharmony_ci wps->cred.cred_attr = NULL; 759e5b75505Sopenharmony_ci wps->cred.cred_attr_len = 0; 760e5b75505Sopenharmony_ci } 761e5b75505Sopenharmony_ci 762e5b75505Sopenharmony_ci return ret; 763e5b75505Sopenharmony_ci} 764e5b75505Sopenharmony_ci 765e5b75505Sopenharmony_ci 766e5b75505Sopenharmony_cistatic int wps_process_creds(struct wps_data *wps, const u8 *cred[], 767e5b75505Sopenharmony_ci u16 cred_len[], unsigned int num_cred, int wps2) 768e5b75505Sopenharmony_ci{ 769e5b75505Sopenharmony_ci size_t i; 770e5b75505Sopenharmony_ci int ok = 0; 771e5b75505Sopenharmony_ci 772e5b75505Sopenharmony_ci if (wps->wps->ap) 773e5b75505Sopenharmony_ci return 0; 774e5b75505Sopenharmony_ci 775e5b75505Sopenharmony_ci if (num_cred == 0) { 776e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Credential attributes " 777e5b75505Sopenharmony_ci "received"); 778e5b75505Sopenharmony_ci return -1; 779e5b75505Sopenharmony_ci } 780e5b75505Sopenharmony_ci 781e5b75505Sopenharmony_ci for (i = 0; i < num_cred; i++) { 782e5b75505Sopenharmony_ci int res; 783e5b75505Sopenharmony_ci res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2); 784e5b75505Sopenharmony_ci if (res == 0) 785e5b75505Sopenharmony_ci ok++; 786e5b75505Sopenharmony_ci else if (res == -2) 787e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped"); 788e5b75505Sopenharmony_ci else 789e5b75505Sopenharmony_ci return -1; 790e5b75505Sopenharmony_ci } 791e5b75505Sopenharmony_ci 792e5b75505Sopenharmony_ci if (ok == 0) { 793e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute " 794e5b75505Sopenharmony_ci "received"); 795e5b75505Sopenharmony_ci return -1; 796e5b75505Sopenharmony_ci } 797e5b75505Sopenharmony_ci 798e5b75505Sopenharmony_ci return 0; 799e5b75505Sopenharmony_ci} 800e5b75505Sopenharmony_ci 801e5b75505Sopenharmony_ci 802e5b75505Sopenharmony_cistatic int wps_process_ap_settings_e(struct wps_data *wps, 803e5b75505Sopenharmony_ci struct wps_parse_attr *attr, 804e5b75505Sopenharmony_ci struct wpabuf *attrs, int wps2) 805e5b75505Sopenharmony_ci{ 806e5b75505Sopenharmony_ci struct wps_credential cred; 807e5b75505Sopenharmony_ci int ret = 0; 808e5b75505Sopenharmony_ci 809e5b75505Sopenharmony_ci if (!wps->wps->ap) 810e5b75505Sopenharmony_ci return 0; 811e5b75505Sopenharmony_ci 812e5b75505Sopenharmony_ci if (wps_process_ap_settings(attr, &cred) < 0) 813e5b75505Sopenharmony_ci return -1; 814e5b75505Sopenharmony_ci 815e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Received new AP configuration from " 816e5b75505Sopenharmony_ci "Registrar"); 817e5b75505Sopenharmony_ci 818e5b75505Sopenharmony_ci if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != 819e5b75505Sopenharmony_ci 0) { 820e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings (" 821e5b75505Sopenharmony_ci MACSTR ") does not match with own address (" MACSTR 822e5b75505Sopenharmony_ci ")", MAC2STR(cred.mac_addr), 823e5b75505Sopenharmony_ci MAC2STR(wps->wps->dev.mac_addr)); 824e5b75505Sopenharmony_ci /* 825e5b75505Sopenharmony_ci * In theory, this could be consider fatal error, but there are 826e5b75505Sopenharmony_ci * number of deployed implementations using other address here 827e5b75505Sopenharmony_ci * due to unclarity in the specification. For interoperability 828e5b75505Sopenharmony_ci * reasons, allow this to be processed since we do not really 829e5b75505Sopenharmony_ci * use the MAC Address information for anything. 830e5b75505Sopenharmony_ci */ 831e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_STRICT 832e5b75505Sopenharmony_ci if (wps2) { 833e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " 834e5b75505Sopenharmony_ci "MAC Address in AP Settings"); 835e5b75505Sopenharmony_ci return -1; 836e5b75505Sopenharmony_ci } 837e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 838e5b75505Sopenharmony_ci } 839e5b75505Sopenharmony_ci 840e5b75505Sopenharmony_ci if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) 841e5b75505Sopenharmony_ci { 842e5b75505Sopenharmony_ci if (cred.encr_type & WPS_ENCR_WEP) { 843e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject new AP settings " 844e5b75505Sopenharmony_ci "due to WEP configuration"); 845e5b75505Sopenharmony_ci wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; 846e5b75505Sopenharmony_ci return -1; 847e5b75505Sopenharmony_ci } 848e5b75505Sopenharmony_ci 849e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " 850e5b75505Sopenharmony_ci "invalid encr_type 0x%x", cred.encr_type); 851e5b75505Sopenharmony_ci return -1; 852e5b75505Sopenharmony_ci } 853e5b75505Sopenharmony_ci 854e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_STRICT 855e5b75505Sopenharmony_ci if (wps2) { 856e5b75505Sopenharmony_ci if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == 857e5b75505Sopenharmony_ci WPS_ENCR_TKIP || 858e5b75505Sopenharmony_ci (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 859e5b75505Sopenharmony_ci WPS_AUTH_WPAPSK) { 860e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 " 861e5b75505Sopenharmony_ci "AP Settings: WPA-Personal/TKIP only"); 862e5b75505Sopenharmony_ci wps->error_indication = 863e5b75505Sopenharmony_ci WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED; 864e5b75505Sopenharmony_ci return -1; 865e5b75505Sopenharmony_ci } 866e5b75505Sopenharmony_ci } 867e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 868e5b75505Sopenharmony_ci 869e5b75505Sopenharmony_ci if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP) 870e5b75505Sopenharmony_ci { 871e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " 872e5b75505Sopenharmony_ci "TKIP+AES"); 873e5b75505Sopenharmony_ci cred.encr_type |= WPS_ENCR_AES; 874e5b75505Sopenharmony_ci } 875e5b75505Sopenharmony_ci 876e5b75505Sopenharmony_ci if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 877e5b75505Sopenharmony_ci WPS_AUTH_WPAPSK) { 878e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " 879e5b75505Sopenharmony_ci "WPAPSK+WPA2PSK"); 880e5b75505Sopenharmony_ci cred.auth_type |= WPS_AUTH_WPA2PSK; 881e5b75505Sopenharmony_ci } 882e5b75505Sopenharmony_ci 883e5b75505Sopenharmony_ci if (wps->wps->cred_cb) { 884e5b75505Sopenharmony_ci cred.cred_attr = wpabuf_head(attrs); 885e5b75505Sopenharmony_ci cred.cred_attr_len = wpabuf_len(attrs); 886e5b75505Sopenharmony_ci ret = wps->wps->cred_cb(wps->wps->cb_ctx, &cred); 887e5b75505Sopenharmony_ci } 888e5b75505Sopenharmony_ci 889e5b75505Sopenharmony_ci return ret; 890e5b75505Sopenharmony_ci} 891e5b75505Sopenharmony_ci 892e5b75505Sopenharmony_ci 893e5b75505Sopenharmony_cistatic int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id) 894e5b75505Sopenharmony_ci{ 895e5b75505Sopenharmony_ci u16 id; 896e5b75505Sopenharmony_ci 897e5b75505Sopenharmony_ci if (dev_pw_id == NULL) { 898e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Device Password ID"); 899e5b75505Sopenharmony_ci return -1; 900e5b75505Sopenharmony_ci } 901e5b75505Sopenharmony_ci 902e5b75505Sopenharmony_ci id = WPA_GET_BE16(dev_pw_id); 903e5b75505Sopenharmony_ci if (wps->dev_pw_id == id) { 904e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id); 905e5b75505Sopenharmony_ci return 0; 906e5b75505Sopenharmony_ci } 907e5b75505Sopenharmony_ci 908e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 909e5b75505Sopenharmony_ci if ((id == DEV_PW_DEFAULT && 910e5b75505Sopenharmony_ci wps->dev_pw_id == DEV_PW_REGISTRAR_SPECIFIED) || 911e5b75505Sopenharmony_ci (id == DEV_PW_REGISTRAR_SPECIFIED && 912e5b75505Sopenharmony_ci wps->dev_pw_id == DEV_PW_DEFAULT)) { 913e5b75505Sopenharmony_ci /* 914e5b75505Sopenharmony_ci * Common P2P use cases indicate whether the PIN is from the 915e5b75505Sopenharmony_ci * client or GO using Device Password Id in M1/M2 in a way that 916e5b75505Sopenharmony_ci * does not look fully compliant with WSC specification. Anyway, 917e5b75505Sopenharmony_ci * this is deployed and needs to be allowed, so ignore changes 918e5b75505Sopenharmony_ci * between Registrar-Specified and Default PIN. 919e5b75505Sopenharmony_ci */ 920e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Allow PIN Device Password ID " 921e5b75505Sopenharmony_ci "change"); 922e5b75505Sopenharmony_ci return 0; 923e5b75505Sopenharmony_ci } 924e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 925e5b75505Sopenharmony_ci 926e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password " 927e5b75505Sopenharmony_ci "ID from %u to %u", wps->dev_pw_id, id); 928e5b75505Sopenharmony_ci 929e5b75505Sopenharmony_ci if (wps->dev_pw_id == DEV_PW_PUSHBUTTON && id == DEV_PW_DEFAULT) { 930e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 931e5b75505Sopenharmony_ci "WPS: Workaround - ignore PBC-to-PIN change"); 932e5b75505Sopenharmony_ci return 0; 933e5b75505Sopenharmony_ci } 934e5b75505Sopenharmony_ci 935e5b75505Sopenharmony_ci if (wps->alt_dev_password && wps->alt_dev_pw_id == id) { 936e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password"); 937e5b75505Sopenharmony_ci bin_clear_free(wps->dev_password, wps->dev_password_len); 938e5b75505Sopenharmony_ci wps->dev_pw_id = wps->alt_dev_pw_id; 939e5b75505Sopenharmony_ci wps->dev_password = wps->alt_dev_password; 940e5b75505Sopenharmony_ci wps->dev_password_len = wps->alt_dev_password_len; 941e5b75505Sopenharmony_ci wps->alt_dev_password = NULL; 942e5b75505Sopenharmony_ci wps->alt_dev_password_len = 0; 943e5b75505Sopenharmony_ci return 0; 944e5b75505Sopenharmony_ci } 945e5b75505Sopenharmony_ci 946e5b75505Sopenharmony_ci return -1; 947e5b75505Sopenharmony_ci} 948e5b75505Sopenharmony_ci 949e5b75505Sopenharmony_ci 950e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m2(struct wps_data *wps, 951e5b75505Sopenharmony_ci const struct wpabuf *msg, 952e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 953e5b75505Sopenharmony_ci{ 954e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M2"); 955e5b75505Sopenharmony_ci 956e5b75505Sopenharmony_ci if (wps->state != RECV_M2) { 957e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 958e5b75505Sopenharmony_ci "receiving M2", wps->state); 959e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 960e5b75505Sopenharmony_ci return WPS_CONTINUE; 961e5b75505Sopenharmony_ci } 962e5b75505Sopenharmony_ci 963e5b75505Sopenharmony_ci if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || 964e5b75505Sopenharmony_ci wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 965e5b75505Sopenharmony_ci wps_process_uuid_r(wps, attr->uuid_r) || 966e5b75505Sopenharmony_ci wps_process_dev_pw_id(wps, attr->dev_password_id)) { 967e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 968e5b75505Sopenharmony_ci return WPS_CONTINUE; 969e5b75505Sopenharmony_ci } 970e5b75505Sopenharmony_ci 971e5b75505Sopenharmony_ci /* 972e5b75505Sopenharmony_ci * Stop here on an AP as an Enrollee if AP Setup is locked unless the 973e5b75505Sopenharmony_ci * special locked mode is used to allow protocol run up to M7 in order 974e5b75505Sopenharmony_ci * to support external Registrars that only learn the current AP 975e5b75505Sopenharmony_ci * configuration without changing it. 976e5b75505Sopenharmony_ci */ 977e5b75505Sopenharmony_ci if (wps->wps->ap && 978e5b75505Sopenharmony_ci ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) || 979e5b75505Sopenharmony_ci wps->dev_password == NULL)) { 980e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " 981e5b75505Sopenharmony_ci "registration of a new Registrar"); 982e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_SETUP_LOCKED; 983e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 984e5b75505Sopenharmony_ci return WPS_CONTINUE; 985e5b75505Sopenharmony_ci } 986e5b75505Sopenharmony_ci 987e5b75505Sopenharmony_ci if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || 988e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg) || 989e5b75505Sopenharmony_ci wps_process_device_attrs(&wps->peer_dev, attr)) { 990e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 991e5b75505Sopenharmony_ci return WPS_CONTINUE; 992e5b75505Sopenharmony_ci } 993e5b75505Sopenharmony_ci 994e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 995e5b75505Sopenharmony_ci if (wps->peer_pubkey_hash_set) { 996e5b75505Sopenharmony_ci struct wpabuf *decrypted; 997e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 998e5b75505Sopenharmony_ci 999e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 1000e5b75505Sopenharmony_ci attr->encr_settings_len); 1001e5b75505Sopenharmony_ci if (decrypted == NULL) { 1002e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt " 1003e5b75505Sopenharmony_ci "Encrypted Settings attribute"); 1004e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1005e5b75505Sopenharmony_ci return WPS_CONTINUE; 1006e5b75505Sopenharmony_ci } 1007e5b75505Sopenharmony_ci 1008e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted " 1009e5b75505Sopenharmony_ci "Settings attribute"); 1010e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 1011e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, 1012e5b75505Sopenharmony_ci eattr.key_wrap_auth) || 1013e5b75505Sopenharmony_ci wps_process_creds(wps, eattr.cred, eattr.cred_len, 1014e5b75505Sopenharmony_ci eattr.num_cred, attr->version2 != NULL)) { 1015e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1016e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1017e5b75505Sopenharmony_ci return WPS_CONTINUE; 1018e5b75505Sopenharmony_ci } 1019e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1020e5b75505Sopenharmony_ci 1021e5b75505Sopenharmony_ci wps->state = WPS_MSG_DONE; 1022e5b75505Sopenharmony_ci return WPS_CONTINUE; 1023e5b75505Sopenharmony_ci } 1024e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 1025e5b75505Sopenharmony_ci 1026e5b75505Sopenharmony_ci wps->state = SEND_M3; 1027e5b75505Sopenharmony_ci return WPS_CONTINUE; 1028e5b75505Sopenharmony_ci} 1029e5b75505Sopenharmony_ci 1030e5b75505Sopenharmony_ci 1031e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m2d(struct wps_data *wps, 1032e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 1033e5b75505Sopenharmony_ci{ 1034e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M2D"); 1035e5b75505Sopenharmony_ci 1036e5b75505Sopenharmony_ci if (wps->state != RECV_M2) { 1037e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 1038e5b75505Sopenharmony_ci "receiving M2D", wps->state); 1039e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1040e5b75505Sopenharmony_ci return WPS_CONTINUE; 1041e5b75505Sopenharmony_ci } 1042e5b75505Sopenharmony_ci 1043e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", 1044e5b75505Sopenharmony_ci attr->manufacturer, attr->manufacturer_len); 1045e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", 1046e5b75505Sopenharmony_ci attr->model_name, attr->model_name_len); 1047e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", 1048e5b75505Sopenharmony_ci attr->model_number, attr->model_number_len); 1049e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", 1050e5b75505Sopenharmony_ci attr->serial_number, attr->serial_number_len); 1051e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", 1052e5b75505Sopenharmony_ci attr->dev_name, attr->dev_name_len); 1053e5b75505Sopenharmony_ci 1054e5b75505Sopenharmony_ci if (wps->wps->event_cb) { 1055e5b75505Sopenharmony_ci union wps_event_data data; 1056e5b75505Sopenharmony_ci struct wps_event_m2d *m2d = &data.m2d; 1057e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 1058e5b75505Sopenharmony_ci if (attr->config_methods) 1059e5b75505Sopenharmony_ci m2d->config_methods = 1060e5b75505Sopenharmony_ci WPA_GET_BE16(attr->config_methods); 1061e5b75505Sopenharmony_ci m2d->manufacturer = attr->manufacturer; 1062e5b75505Sopenharmony_ci m2d->manufacturer_len = attr->manufacturer_len; 1063e5b75505Sopenharmony_ci m2d->model_name = attr->model_name; 1064e5b75505Sopenharmony_ci m2d->model_name_len = attr->model_name_len; 1065e5b75505Sopenharmony_ci m2d->model_number = attr->model_number; 1066e5b75505Sopenharmony_ci m2d->model_number_len = attr->model_number_len; 1067e5b75505Sopenharmony_ci m2d->serial_number = attr->serial_number; 1068e5b75505Sopenharmony_ci m2d->serial_number_len = attr->serial_number_len; 1069e5b75505Sopenharmony_ci m2d->dev_name = attr->dev_name; 1070e5b75505Sopenharmony_ci m2d->dev_name_len = attr->dev_name_len; 1071e5b75505Sopenharmony_ci m2d->primary_dev_type = attr->primary_dev_type; 1072e5b75505Sopenharmony_ci if (attr->config_error) 1073e5b75505Sopenharmony_ci m2d->config_error = 1074e5b75505Sopenharmony_ci WPA_GET_BE16(attr->config_error); 1075e5b75505Sopenharmony_ci if (attr->dev_password_id) 1076e5b75505Sopenharmony_ci m2d->dev_password_id = 1077e5b75505Sopenharmony_ci WPA_GET_BE16(attr->dev_password_id); 1078e5b75505Sopenharmony_ci wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data); 1079e5b75505Sopenharmony_ci } 1080e5b75505Sopenharmony_ci 1081e5b75505Sopenharmony_ci wps->state = RECEIVED_M2D; 1082e5b75505Sopenharmony_ci return WPS_CONTINUE; 1083e5b75505Sopenharmony_ci} 1084e5b75505Sopenharmony_ci 1085e5b75505Sopenharmony_ci 1086e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m4(struct wps_data *wps, 1087e5b75505Sopenharmony_ci const struct wpabuf *msg, 1088e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 1089e5b75505Sopenharmony_ci{ 1090e5b75505Sopenharmony_ci struct wpabuf *decrypted; 1091e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 1092e5b75505Sopenharmony_ci 1093e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M4"); 1094e5b75505Sopenharmony_ci 1095e5b75505Sopenharmony_ci if (wps->state != RECV_M4) { 1096e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 1097e5b75505Sopenharmony_ci "receiving M4", wps->state); 1098e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1099e5b75505Sopenharmony_ci return WPS_CONTINUE; 1100e5b75505Sopenharmony_ci } 1101e5b75505Sopenharmony_ci 1102e5b75505Sopenharmony_ci if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 1103e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg) || 1104e5b75505Sopenharmony_ci wps_process_r_hash1(wps, attr->r_hash1) || 1105e5b75505Sopenharmony_ci wps_process_r_hash2(wps, attr->r_hash2)) { 1106e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1107e5b75505Sopenharmony_ci return WPS_CONTINUE; 1108e5b75505Sopenharmony_ci } 1109e5b75505Sopenharmony_ci 1110e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 1111e5b75505Sopenharmony_ci attr->encr_settings_len); 1112e5b75505Sopenharmony_ci if (decrypted == NULL) { 1113e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 1114e5b75505Sopenharmony_ci "Settings attribute"); 1115e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1116e5b75505Sopenharmony_ci return WPS_CONTINUE; 1117e5b75505Sopenharmony_ci } 1118e5b75505Sopenharmony_ci 1119e5b75505Sopenharmony_ci if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { 1120e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1121e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1122e5b75505Sopenharmony_ci return WPS_CONTINUE; 1123e5b75505Sopenharmony_ci } 1124e5b75505Sopenharmony_ci 1125e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 1126e5b75505Sopenharmony_ci "attribute"); 1127e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 1128e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 1129e5b75505Sopenharmony_ci wps_process_r_snonce1(wps, eattr.r_snonce1)) { 1130e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1131e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1132e5b75505Sopenharmony_ci return WPS_CONTINUE; 1133e5b75505Sopenharmony_ci } 1134e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1135e5b75505Sopenharmony_ci 1136e5b75505Sopenharmony_ci wps->state = SEND_M5; 1137e5b75505Sopenharmony_ci return WPS_CONTINUE; 1138e5b75505Sopenharmony_ci} 1139e5b75505Sopenharmony_ci 1140e5b75505Sopenharmony_ci 1141e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m6(struct wps_data *wps, 1142e5b75505Sopenharmony_ci const struct wpabuf *msg, 1143e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 1144e5b75505Sopenharmony_ci{ 1145e5b75505Sopenharmony_ci struct wpabuf *decrypted; 1146e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 1147e5b75505Sopenharmony_ci 1148e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M6"); 1149e5b75505Sopenharmony_ci 1150e5b75505Sopenharmony_ci if (wps->state != RECV_M6) { 1151e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 1152e5b75505Sopenharmony_ci "receiving M6", wps->state); 1153e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1154e5b75505Sopenharmony_ci return WPS_CONTINUE; 1155e5b75505Sopenharmony_ci } 1156e5b75505Sopenharmony_ci 1157e5b75505Sopenharmony_ci if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 1158e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg)) { 1159e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1160e5b75505Sopenharmony_ci return WPS_CONTINUE; 1161e5b75505Sopenharmony_ci } 1162e5b75505Sopenharmony_ci 1163e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 1164e5b75505Sopenharmony_ci attr->encr_settings_len); 1165e5b75505Sopenharmony_ci if (decrypted == NULL) { 1166e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 1167e5b75505Sopenharmony_ci "Settings attribute"); 1168e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1169e5b75505Sopenharmony_ci return WPS_CONTINUE; 1170e5b75505Sopenharmony_ci } 1171e5b75505Sopenharmony_ci 1172e5b75505Sopenharmony_ci if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { 1173e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1174e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1175e5b75505Sopenharmony_ci return WPS_CONTINUE; 1176e5b75505Sopenharmony_ci } 1177e5b75505Sopenharmony_ci 1178e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 1179e5b75505Sopenharmony_ci "attribute"); 1180e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 1181e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 1182e5b75505Sopenharmony_ci wps_process_r_snonce2(wps, eattr.r_snonce2)) { 1183e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1184e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1185e5b75505Sopenharmony_ci return WPS_CONTINUE; 1186e5b75505Sopenharmony_ci } 1187e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1188e5b75505Sopenharmony_ci 1189e5b75505Sopenharmony_ci if (wps->wps->ap) 1190e5b75505Sopenharmony_ci wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS, 1191e5b75505Sopenharmony_ci NULL); 1192e5b75505Sopenharmony_ci 1193e5b75505Sopenharmony_ci wps->state = SEND_M7; 1194e5b75505Sopenharmony_ci return WPS_CONTINUE; 1195e5b75505Sopenharmony_ci} 1196e5b75505Sopenharmony_ci 1197e5b75505Sopenharmony_ci 1198e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m8(struct wps_data *wps, 1199e5b75505Sopenharmony_ci const struct wpabuf *msg, 1200e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 1201e5b75505Sopenharmony_ci{ 1202e5b75505Sopenharmony_ci struct wpabuf *decrypted; 1203e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 1204e5b75505Sopenharmony_ci 1205e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M8"); 1206e5b75505Sopenharmony_ci 1207e5b75505Sopenharmony_ci if (wps->state != RECV_M8) { 1208e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 1209e5b75505Sopenharmony_ci "receiving M8", wps->state); 1210e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1211e5b75505Sopenharmony_ci return WPS_CONTINUE; 1212e5b75505Sopenharmony_ci } 1213e5b75505Sopenharmony_ci 1214e5b75505Sopenharmony_ci if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 1215e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg)) { 1216e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1217e5b75505Sopenharmony_ci return WPS_CONTINUE; 1218e5b75505Sopenharmony_ci } 1219e5b75505Sopenharmony_ci 1220e5b75505Sopenharmony_ci if (wps->wps->ap && wps->wps->ap_setup_locked) { 1221e5b75505Sopenharmony_ci /* 1222e5b75505Sopenharmony_ci * Stop here if special ap_setup_locked == 2 mode allowed the 1223e5b75505Sopenharmony_ci * protocol to continue beyond M2. This allows ER to learn the 1224e5b75505Sopenharmony_ci * current AP settings without changing them. 1225e5b75505Sopenharmony_ci */ 1226e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " 1227e5b75505Sopenharmony_ci "registration of a new Registrar"); 1228e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_SETUP_LOCKED; 1229e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1230e5b75505Sopenharmony_ci return WPS_CONTINUE; 1231e5b75505Sopenharmony_ci } 1232e5b75505Sopenharmony_ci 1233e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 1234e5b75505Sopenharmony_ci attr->encr_settings_len); 1235e5b75505Sopenharmony_ci if (decrypted == NULL) { 1236e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 1237e5b75505Sopenharmony_ci "Settings attribute"); 1238e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1239e5b75505Sopenharmony_ci return WPS_CONTINUE; 1240e5b75505Sopenharmony_ci } 1241e5b75505Sopenharmony_ci 1242e5b75505Sopenharmony_ci if (wps_validate_m8_encr(decrypted, wps->wps->ap, 1243e5b75505Sopenharmony_ci attr->version2 != NULL) < 0) { 1244e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1245e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1246e5b75505Sopenharmony_ci return WPS_CONTINUE; 1247e5b75505Sopenharmony_ci } 1248e5b75505Sopenharmony_ci 1249e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 1250e5b75505Sopenharmony_ci "attribute"); 1251e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 1252e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 1253e5b75505Sopenharmony_ci wps_process_creds(wps, eattr.cred, eattr.cred_len, 1254e5b75505Sopenharmony_ci eattr.num_cred, attr->version2 != NULL) || 1255e5b75505Sopenharmony_ci wps_process_ap_settings_e(wps, &eattr, decrypted, 1256e5b75505Sopenharmony_ci attr->version2 != NULL)) { 1257e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1258e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1259e5b75505Sopenharmony_ci return WPS_CONTINUE; 1260e5b75505Sopenharmony_ci } 1261e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 1262e5b75505Sopenharmony_ci 1263e5b75505Sopenharmony_ci wps->state = WPS_MSG_DONE; 1264e5b75505Sopenharmony_ci return WPS_CONTINUE; 1265e5b75505Sopenharmony_ci} 1266e5b75505Sopenharmony_ci 1267e5b75505Sopenharmony_ci 1268e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, 1269e5b75505Sopenharmony_ci const struct wpabuf *msg) 1270e5b75505Sopenharmony_ci{ 1271e5b75505Sopenharmony_ci struct wps_parse_attr attr; 1272e5b75505Sopenharmony_ci enum wps_process_res ret = WPS_CONTINUE; 1273e5b75505Sopenharmony_ci 1274e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); 1275e5b75505Sopenharmony_ci 1276e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 1277e5b75505Sopenharmony_ci return WPS_FAILURE; 1278e5b75505Sopenharmony_ci 1279e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 1280e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 1281e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 1282e5b75505Sopenharmony_ci return WPS_FAILURE; 1283e5b75505Sopenharmony_ci } 1284e5b75505Sopenharmony_ci 1285e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 1286e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 1287e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1288e5b75505Sopenharmony_ci return WPS_CONTINUE; 1289e5b75505Sopenharmony_ci } 1290e5b75505Sopenharmony_ci 1291e5b75505Sopenharmony_ci switch (*attr.msg_type) { 1292e5b75505Sopenharmony_ci case WPS_M2: 1293e5b75505Sopenharmony_ci if (wps_validate_m2(msg) < 0) 1294e5b75505Sopenharmony_ci return WPS_FAILURE; 1295e5b75505Sopenharmony_ci ret = wps_process_m2(wps, msg, &attr); 1296e5b75505Sopenharmony_ci break; 1297e5b75505Sopenharmony_ci case WPS_M2D: 1298e5b75505Sopenharmony_ci if (wps_validate_m2d(msg) < 0) 1299e5b75505Sopenharmony_ci return WPS_FAILURE; 1300e5b75505Sopenharmony_ci ret = wps_process_m2d(wps, &attr); 1301e5b75505Sopenharmony_ci break; 1302e5b75505Sopenharmony_ci case WPS_M4: 1303e5b75505Sopenharmony_ci if (wps_validate_m4(msg) < 0) 1304e5b75505Sopenharmony_ci return WPS_FAILURE; 1305e5b75505Sopenharmony_ci ret = wps_process_m4(wps, msg, &attr); 1306e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1307e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M4, wps->config_error, 1308e5b75505Sopenharmony_ci wps->error_indication, 1309e5b75505Sopenharmony_ci wps->peer_dev.mac_addr); 1310e5b75505Sopenharmony_ci break; 1311e5b75505Sopenharmony_ci case WPS_M6: 1312e5b75505Sopenharmony_ci if (wps_validate_m6(msg) < 0) 1313e5b75505Sopenharmony_ci return WPS_FAILURE; 1314e5b75505Sopenharmony_ci ret = wps_process_m6(wps, msg, &attr); 1315e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1316e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M6, wps->config_error, 1317e5b75505Sopenharmony_ci wps->error_indication, 1318e5b75505Sopenharmony_ci wps->peer_dev.mac_addr); 1319e5b75505Sopenharmony_ci break; 1320e5b75505Sopenharmony_ci case WPS_M8: 1321e5b75505Sopenharmony_ci if (wps_validate_m8(msg) < 0) 1322e5b75505Sopenharmony_ci return WPS_FAILURE; 1323e5b75505Sopenharmony_ci ret = wps_process_m8(wps, msg, &attr); 1324e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1325e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M8, wps->config_error, 1326e5b75505Sopenharmony_ci wps->error_indication, 1327e5b75505Sopenharmony_ci wps->peer_dev.mac_addr); 1328e5b75505Sopenharmony_ci break; 1329e5b75505Sopenharmony_ci default: 1330e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", 1331e5b75505Sopenharmony_ci *attr.msg_type); 1332e5b75505Sopenharmony_ci return WPS_FAILURE; 1333e5b75505Sopenharmony_ci } 1334e5b75505Sopenharmony_ci 1335e5b75505Sopenharmony_ci /* 1336e5b75505Sopenharmony_ci * Save a copy of the last message for Authenticator derivation if we 1337e5b75505Sopenharmony_ci * are continuing. However, skip M2D since it is not authenticated and 1338e5b75505Sopenharmony_ci * neither is the ACK/NACK response frame. This allows the possibly 1339e5b75505Sopenharmony_ci * following M2 to be processed correctly by using the previously sent 1340e5b75505Sopenharmony_ci * M1 in Authenticator derivation. 1341e5b75505Sopenharmony_ci */ 1342e5b75505Sopenharmony_ci if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) { 1343e5b75505Sopenharmony_ci /* Save a copy of the last message for Authenticator derivation 1344e5b75505Sopenharmony_ci */ 1345e5b75505Sopenharmony_ci wpabuf_free(wps->last_msg); 1346e5b75505Sopenharmony_ci wps->last_msg = wpabuf_dup(msg); 1347e5b75505Sopenharmony_ci } 1348e5b75505Sopenharmony_ci 1349e5b75505Sopenharmony_ci return ret; 1350e5b75505Sopenharmony_ci} 1351e5b75505Sopenharmony_ci 1352e5b75505Sopenharmony_ci 1353e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, 1354e5b75505Sopenharmony_ci const struct wpabuf *msg) 1355e5b75505Sopenharmony_ci{ 1356e5b75505Sopenharmony_ci struct wps_parse_attr attr; 1357e5b75505Sopenharmony_ci 1358e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); 1359e5b75505Sopenharmony_ci 1360e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 1361e5b75505Sopenharmony_ci return WPS_FAILURE; 1362e5b75505Sopenharmony_ci 1363e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 1364e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 1365e5b75505Sopenharmony_ci return WPS_FAILURE; 1366e5b75505Sopenharmony_ci } 1367e5b75505Sopenharmony_ci 1368e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_WSC_ACK) { 1369e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 1370e5b75505Sopenharmony_ci *attr.msg_type); 1371e5b75505Sopenharmony_ci return WPS_FAILURE; 1372e5b75505Sopenharmony_ci } 1373e5b75505Sopenharmony_ci 1374e5b75505Sopenharmony_ci if (attr.registrar_nonce == NULL || 1375e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 1376e5b75505Sopenharmony_ci { 1377e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 1378e5b75505Sopenharmony_ci return WPS_FAILURE; 1379e5b75505Sopenharmony_ci } 1380e5b75505Sopenharmony_ci 1381e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 1382e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 1383e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 1384e5b75505Sopenharmony_ci return WPS_FAILURE; 1385e5b75505Sopenharmony_ci } 1386e5b75505Sopenharmony_ci 1387e5b75505Sopenharmony_ci if (wps->state == RECV_ACK && wps->wps->ap) { 1388e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: External Registrar registration " 1389e5b75505Sopenharmony_ci "completed successfully"); 1390e5b75505Sopenharmony_ci wps_success_event(wps->wps, wps->peer_dev.mac_addr); 1391e5b75505Sopenharmony_ci wps->state = WPS_FINISHED; 1392e5b75505Sopenharmony_ci return WPS_DONE; 1393e5b75505Sopenharmony_ci } 1394e5b75505Sopenharmony_ci 1395e5b75505Sopenharmony_ci return WPS_FAILURE; 1396e5b75505Sopenharmony_ci} 1397e5b75505Sopenharmony_ci 1398e5b75505Sopenharmony_ci 1399e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, 1400e5b75505Sopenharmony_ci const struct wpabuf *msg) 1401e5b75505Sopenharmony_ci{ 1402e5b75505Sopenharmony_ci struct wps_parse_attr attr; 1403e5b75505Sopenharmony_ci u16 config_error; 1404e5b75505Sopenharmony_ci 1405e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); 1406e5b75505Sopenharmony_ci 1407e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 1408e5b75505Sopenharmony_ci return WPS_FAILURE; 1409e5b75505Sopenharmony_ci 1410e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 1411e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 1412e5b75505Sopenharmony_ci return WPS_FAILURE; 1413e5b75505Sopenharmony_ci } 1414e5b75505Sopenharmony_ci 1415e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_WSC_NACK) { 1416e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 1417e5b75505Sopenharmony_ci *attr.msg_type); 1418e5b75505Sopenharmony_ci return WPS_FAILURE; 1419e5b75505Sopenharmony_ci } 1420e5b75505Sopenharmony_ci 1421e5b75505Sopenharmony_ci if (attr.registrar_nonce == NULL || 1422e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 1423e5b75505Sopenharmony_ci { 1424e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 1425e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce", 1426e5b75505Sopenharmony_ci attr.registrar_nonce, WPS_NONCE_LEN); 1427e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce", 1428e5b75505Sopenharmony_ci wps->nonce_r, WPS_NONCE_LEN); 1429e5b75505Sopenharmony_ci return WPS_FAILURE; 1430e5b75505Sopenharmony_ci } 1431e5b75505Sopenharmony_ci 1432e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 1433e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 1434e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 1435e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce", 1436e5b75505Sopenharmony_ci attr.enrollee_nonce, WPS_NONCE_LEN); 1437e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce", 1438e5b75505Sopenharmony_ci wps->nonce_e, WPS_NONCE_LEN); 1439e5b75505Sopenharmony_ci return WPS_FAILURE; 1440e5b75505Sopenharmony_ci } 1441e5b75505Sopenharmony_ci 1442e5b75505Sopenharmony_ci if (attr.config_error == NULL) { 1443e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " 1444e5b75505Sopenharmony_ci "in WSC_NACK"); 1445e5b75505Sopenharmony_ci return WPS_FAILURE; 1446e5b75505Sopenharmony_ci } 1447e5b75505Sopenharmony_ci 1448e5b75505Sopenharmony_ci config_error = WPA_GET_BE16(attr.config_error); 1449e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with " 1450e5b75505Sopenharmony_ci "Configuration Error %d", config_error); 1451e5b75505Sopenharmony_ci 1452e5b75505Sopenharmony_ci switch (wps->state) { 1453e5b75505Sopenharmony_ci case RECV_M4: 1454e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M3, config_error, 1455e5b75505Sopenharmony_ci wps->error_indication, wps->peer_dev.mac_addr); 1456e5b75505Sopenharmony_ci break; 1457e5b75505Sopenharmony_ci case RECV_M6: 1458e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M5, config_error, 1459e5b75505Sopenharmony_ci wps->error_indication, wps->peer_dev.mac_addr); 1460e5b75505Sopenharmony_ci break; 1461e5b75505Sopenharmony_ci case RECV_M8: 1462e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M7, config_error, 1463e5b75505Sopenharmony_ci wps->error_indication, wps->peer_dev.mac_addr); 1464e5b75505Sopenharmony_ci break; 1465e5b75505Sopenharmony_ci default: 1466e5b75505Sopenharmony_ci break; 1467e5b75505Sopenharmony_ci } 1468e5b75505Sopenharmony_ci 1469e5b75505Sopenharmony_ci /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if 1470e5b75505Sopenharmony_ci * Enrollee is Authenticator */ 1471e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 1472e5b75505Sopenharmony_ci 1473e5b75505Sopenharmony_ci return WPS_FAILURE; 1474e5b75505Sopenharmony_ci} 1475e5b75505Sopenharmony_ci 1476e5b75505Sopenharmony_ci 1477e5b75505Sopenharmony_cienum wps_process_res wps_enrollee_process_msg(struct wps_data *wps, 1478e5b75505Sopenharmony_ci enum wsc_op_code op_code, 1479e5b75505Sopenharmony_ci const struct wpabuf *msg) 1480e5b75505Sopenharmony_ci{ 1481e5b75505Sopenharmony_ci 1482e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " 1483e5b75505Sopenharmony_ci "op_code=%d)", 1484e5b75505Sopenharmony_ci (unsigned long) wpabuf_len(msg), op_code); 1485e5b75505Sopenharmony_ci 1486e5b75505Sopenharmony_ci if (op_code == WSC_UPnP) { 1487e5b75505Sopenharmony_ci /* Determine the OpCode based on message type attribute */ 1488e5b75505Sopenharmony_ci struct wps_parse_attr attr; 1489e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { 1490e5b75505Sopenharmony_ci if (*attr.msg_type == WPS_WSC_ACK) 1491e5b75505Sopenharmony_ci op_code = WSC_ACK; 1492e5b75505Sopenharmony_ci else if (*attr.msg_type == WPS_WSC_NACK) 1493e5b75505Sopenharmony_ci op_code = WSC_NACK; 1494e5b75505Sopenharmony_ci } 1495e5b75505Sopenharmony_ci } 1496e5b75505Sopenharmony_ci 1497e5b75505Sopenharmony_ci switch (op_code) { 1498e5b75505Sopenharmony_ci case WSC_MSG: 1499e5b75505Sopenharmony_ci case WSC_UPnP: 1500e5b75505Sopenharmony_ci return wps_process_wsc_msg(wps, msg); 1501e5b75505Sopenharmony_ci case WSC_ACK: 1502e5b75505Sopenharmony_ci if (wps_validate_wsc_ack(msg) < 0) 1503e5b75505Sopenharmony_ci return WPS_FAILURE; 1504e5b75505Sopenharmony_ci return wps_process_wsc_ack(wps, msg); 1505e5b75505Sopenharmony_ci case WSC_NACK: 1506e5b75505Sopenharmony_ci if (wps_validate_wsc_nack(msg) < 0) 1507e5b75505Sopenharmony_ci return WPS_FAILURE; 1508e5b75505Sopenharmony_ci return wps_process_wsc_nack(wps, msg); 1509e5b75505Sopenharmony_ci default: 1510e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); 1511e5b75505Sopenharmony_ci return WPS_FAILURE; 1512e5b75505Sopenharmony_ci } 1513e5b75505Sopenharmony_ci} 1514