139beb93cSSam Leffler /* 239beb93cSSam Leffler * Wi-Fi Protected Setup - Enrollee 339beb93cSSam Leffler * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui 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" 14*f05cddf9SRui Paulo #include "crypto/random.h" 1539beb93cSSam Leffler #include "wps_i.h" 1639beb93cSSam Leffler #include "wps_dev_attr.h" 1739beb93cSSam Leffler 1839beb93cSSam Leffler 1939beb93cSSam Leffler static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg) 2039beb93cSSam Leffler { 2139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * MAC Address"); 2239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_MAC_ADDR); 2339beb93cSSam Leffler wpabuf_put_be16(msg, ETH_ALEN); 2439beb93cSSam Leffler wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN); 2539beb93cSSam Leffler return 0; 2639beb93cSSam Leffler } 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg) 3039beb93cSSam Leffler { 3139beb93cSSam Leffler u8 state; 3239beb93cSSam Leffler if (wps->wps->ap) 3339beb93cSSam Leffler state = wps->wps->wps_state; 3439beb93cSSam Leffler else 3539beb93cSSam Leffler state = WPS_STATE_NOT_CONFIGURED; 3639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", 3739beb93cSSam Leffler state); 3839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_WPS_STATE); 3939beb93cSSam Leffler wpabuf_put_be16(msg, 1); 403157ba21SRui Paulo wpabuf_put_u8(msg, state); 4139beb93cSSam Leffler return 0; 4239beb93cSSam Leffler } 4339beb93cSSam Leffler 4439beb93cSSam Leffler 4539beb93cSSam Leffler static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) 4639beb93cSSam Leffler { 4739beb93cSSam Leffler u8 *hash; 4839beb93cSSam Leffler const u8 *addr[4]; 4939beb93cSSam Leffler size_t len[4]; 5039beb93cSSam Leffler 51*f05cddf9SRui Paulo if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) 5239beb93cSSam Leffler return -1; 5339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN); 5439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-S2", 5539beb93cSSam Leffler wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); 5639beb93cSSam Leffler 5739beb93cSSam Leffler if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { 5839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " 5939beb93cSSam Leffler "E-Hash derivation"); 6039beb93cSSam Leffler return -1; 6139beb93cSSam Leffler } 6239beb93cSSam Leffler 6339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-Hash1"); 6439beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_HASH1); 6539beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN); 6639beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN); 6739beb93cSSam Leffler /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ 6839beb93cSSam Leffler addr[0] = wps->snonce; 6939beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN; 7039beb93cSSam Leffler addr[1] = wps->psk1; 7139beb93cSSam Leffler len[1] = WPS_PSK_LEN; 7239beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e); 7339beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e); 7439beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r); 7539beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r); 7639beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 7739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); 7839beb93cSSam Leffler 7939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); 8039beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_HASH2); 8139beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN); 8239beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN); 8339beb93cSSam Leffler /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ 8439beb93cSSam Leffler addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; 8539beb93cSSam Leffler addr[1] = wps->psk2; 8639beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 8739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); 8839beb93cSSam Leffler 8939beb93cSSam Leffler return 0; 9039beb93cSSam Leffler } 9139beb93cSSam Leffler 9239beb93cSSam Leffler 9339beb93cSSam Leffler static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg) 9439beb93cSSam Leffler { 9539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-SNonce1"); 9639beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_SNONCE1); 9739beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 9839beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); 9939beb93cSSam Leffler return 0; 10039beb93cSSam Leffler } 10139beb93cSSam Leffler 10239beb93cSSam Leffler 10339beb93cSSam Leffler static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg) 10439beb93cSSam Leffler { 10539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * E-SNonce2"); 10639beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_E_SNONCE2); 10739beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 10839beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, 10939beb93cSSam Leffler WPS_SECRET_NONCE_LEN); 11039beb93cSSam Leffler return 0; 11139beb93cSSam Leffler } 11239beb93cSSam Leffler 11339beb93cSSam Leffler 11439beb93cSSam Leffler static struct wpabuf * wps_build_m1(struct wps_data *wps) 11539beb93cSSam Leffler { 11639beb93cSSam Leffler struct wpabuf *msg; 117*f05cddf9SRui Paulo u16 config_methods; 11839beb93cSSam Leffler 119*f05cddf9SRui Paulo if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) 12039beb93cSSam Leffler return NULL; 12139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", 12239beb93cSSam Leffler wps->nonce_e, WPS_NONCE_LEN); 12339beb93cSSam Leffler 12439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M1"); 12539beb93cSSam Leffler msg = wpabuf_alloc(1000); 12639beb93cSSam Leffler if (msg == NULL) 12739beb93cSSam Leffler return NULL; 12839beb93cSSam Leffler 129*f05cddf9SRui Paulo config_methods = wps->wps->config_methods; 130*f05cddf9SRui Paulo if (wps->wps->ap && !wps->pbc_in_m1 && 131*f05cddf9SRui Paulo (wps->dev_password_len != 0 || 132*f05cddf9SRui Paulo (config_methods & WPS_CONFIG_DISPLAY))) { 133*f05cddf9SRui Paulo /* 134*f05cddf9SRui Paulo * These are the methods that the AP supports as an Enrollee 135*f05cddf9SRui Paulo * for adding external Registrars, so remove PushButton. 136*f05cddf9SRui Paulo * 137*f05cddf9SRui Paulo * As a workaround for Windows 7 mechanism for probing WPS 138*f05cddf9SRui Paulo * capabilities from M1, leave PushButton option if no PIN 139*f05cddf9SRui Paulo * method is available or if WPS configuration enables PBC 140*f05cddf9SRui Paulo * workaround. 141*f05cddf9SRui Paulo */ 142*f05cddf9SRui Paulo config_methods &= ~WPS_CONFIG_PUSHBUTTON; 143*f05cddf9SRui Paulo #ifdef CONFIG_WPS2 144*f05cddf9SRui Paulo config_methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 145*f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON); 146*f05cddf9SRui Paulo #endif /* CONFIG_WPS2 */ 147*f05cddf9SRui Paulo } 148*f05cddf9SRui Paulo 14939beb93cSSam Leffler if (wps_build_version(msg) || 15039beb93cSSam Leffler wps_build_msg_type(msg, WPS_M1) || 15139beb93cSSam Leffler wps_build_uuid_e(msg, wps->uuid_e) || 15239beb93cSSam Leffler wps_build_mac_addr(wps, msg) || 15339beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) || 15439beb93cSSam Leffler wps_build_public_key(wps, msg) || 15539beb93cSSam Leffler wps_build_auth_type_flags(wps, msg) || 15639beb93cSSam Leffler wps_build_encr_type_flags(wps, msg) || 15739beb93cSSam Leffler wps_build_conn_type_flags(wps, msg) || 158*f05cddf9SRui Paulo wps_build_config_methods(msg, config_methods) || 15939beb93cSSam Leffler wps_build_wps_state(wps, msg) || 16039beb93cSSam Leffler wps_build_device_attrs(&wps->wps->dev, msg) || 16139beb93cSSam Leffler wps_build_rf_bands(&wps->wps->dev, msg) || 16239beb93cSSam Leffler wps_build_assoc_state(wps, msg) || 16339beb93cSSam Leffler wps_build_dev_password_id(msg, wps->dev_pw_id) || 16439beb93cSSam Leffler wps_build_config_error(msg, WPS_CFG_NO_ERROR) || 165*f05cddf9SRui Paulo wps_build_os_version(&wps->wps->dev, msg) || 166*f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0) || 167*f05cddf9SRui Paulo wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { 16839beb93cSSam Leffler wpabuf_free(msg); 16939beb93cSSam Leffler return NULL; 17039beb93cSSam Leffler } 17139beb93cSSam Leffler 17239beb93cSSam Leffler wps->state = RECV_M2; 17339beb93cSSam Leffler return msg; 17439beb93cSSam Leffler } 17539beb93cSSam Leffler 17639beb93cSSam Leffler 17739beb93cSSam Leffler static struct wpabuf * wps_build_m3(struct wps_data *wps) 17839beb93cSSam Leffler { 17939beb93cSSam Leffler struct wpabuf *msg; 18039beb93cSSam Leffler 18139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M3"); 18239beb93cSSam Leffler 18339beb93cSSam Leffler if (wps->dev_password == NULL) { 18439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Device Password available"); 18539beb93cSSam Leffler return NULL; 18639beb93cSSam Leffler } 18739beb93cSSam Leffler wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); 18839beb93cSSam Leffler 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) || 197*f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 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 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) || 230*f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0) || 23139beb93cSSam Leffler wps_build_authenticator(wps, msg)) { 23239beb93cSSam Leffler wpabuf_free(plain); 23339beb93cSSam Leffler wpabuf_free(msg); 23439beb93cSSam Leffler return NULL; 23539beb93cSSam Leffler } 23639beb93cSSam Leffler wpabuf_free(plain); 23739beb93cSSam Leffler 23839beb93cSSam Leffler wps->state = RECV_M6; 23939beb93cSSam Leffler return msg; 24039beb93cSSam Leffler } 24139beb93cSSam Leffler 24239beb93cSSam Leffler 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 25339beb93cSSam Leffler static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg) 25439beb93cSSam Leffler { 255*f05cddf9SRui Paulo u16 auth_type = wps->wps->auth_types; 256*f05cddf9SRui Paulo 257*f05cddf9SRui Paulo /* Select the best authentication type */ 258*f05cddf9SRui Paulo if (auth_type & WPS_AUTH_WPA2PSK) 259*f05cddf9SRui Paulo auth_type = WPS_AUTH_WPA2PSK; 260*f05cddf9SRui Paulo else if (auth_type & WPS_AUTH_WPAPSK) 261*f05cddf9SRui Paulo auth_type = WPS_AUTH_WPAPSK; 262*f05cddf9SRui Paulo else if (auth_type & WPS_AUTH_OPEN) 263*f05cddf9SRui Paulo auth_type = WPS_AUTH_OPEN; 264*f05cddf9SRui Paulo else if (auth_type & WPS_AUTH_SHARED) 265*f05cddf9SRui Paulo auth_type = WPS_AUTH_SHARED; 266*f05cddf9SRui Paulo 267*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type); 26839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_AUTH_TYPE); 26939beb93cSSam Leffler wpabuf_put_be16(msg, 2); 270*f05cddf9SRui Paulo wpabuf_put_be16(msg, auth_type); 27139beb93cSSam Leffler return 0; 27239beb93cSSam Leffler } 27339beb93cSSam Leffler 27439beb93cSSam Leffler 27539beb93cSSam Leffler static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg) 27639beb93cSSam Leffler { 277*f05cddf9SRui Paulo u16 encr_type = wps->wps->encr_types; 278*f05cddf9SRui Paulo 279*f05cddf9SRui Paulo /* Select the best encryption type */ 280*f05cddf9SRui Paulo if (wps->wps->auth_types & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) { 281*f05cddf9SRui Paulo if (encr_type & WPS_ENCR_AES) 282*f05cddf9SRui Paulo encr_type = WPS_ENCR_AES; 283*f05cddf9SRui Paulo else if (encr_type & WPS_ENCR_TKIP) 284*f05cddf9SRui Paulo encr_type = WPS_ENCR_TKIP; 285*f05cddf9SRui Paulo } else { 286*f05cddf9SRui Paulo if (encr_type & WPS_ENCR_WEP) 287*f05cddf9SRui Paulo encr_type = WPS_ENCR_WEP; 288*f05cddf9SRui Paulo else if (encr_type & WPS_ENCR_NONE) 289*f05cddf9SRui Paulo encr_type = WPS_ENCR_NONE; 290*f05cddf9SRui Paulo } 291*f05cddf9SRui Paulo 292*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type); 29339beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_ENCR_TYPE); 29439beb93cSSam Leffler wpabuf_put_be16(msg, 2); 295*f05cddf9SRui Paulo wpabuf_put_be16(msg, encr_type); 29639beb93cSSam Leffler return 0; 29739beb93cSSam Leffler } 29839beb93cSSam Leffler 29939beb93cSSam Leffler 30039beb93cSSam Leffler static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg) 30139beb93cSSam Leffler { 30239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Network Key"); 30339beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_NETWORK_KEY); 30439beb93cSSam Leffler wpabuf_put_be16(msg, wps->wps->network_key_len); 30539beb93cSSam Leffler wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len); 30639beb93cSSam Leffler return 0; 30739beb93cSSam Leffler } 30839beb93cSSam Leffler 30939beb93cSSam Leffler 31039beb93cSSam Leffler static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg) 31139beb93cSSam Leffler { 31239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * MAC Address (AP BSSID)"); 31339beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_MAC_ADDR); 31439beb93cSSam Leffler wpabuf_put_be16(msg, ETH_ALEN); 31539beb93cSSam Leffler wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN); 31639beb93cSSam Leffler return 0; 31739beb93cSSam Leffler } 31839beb93cSSam Leffler 31939beb93cSSam Leffler 32039beb93cSSam Leffler static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain) 32139beb93cSSam Leffler { 32239beb93cSSam Leffler if (wps->wps->ap_settings) { 32339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)"); 32439beb93cSSam Leffler wpabuf_put_data(plain, wps->wps->ap_settings, 32539beb93cSSam Leffler wps->wps->ap_settings_len); 32639beb93cSSam Leffler return 0; 32739beb93cSSam Leffler } 32839beb93cSSam Leffler 32939beb93cSSam Leffler return wps_build_cred_ssid(wps, plain) || 33039beb93cSSam Leffler wps_build_cred_mac_addr(wps, plain) || 33139beb93cSSam Leffler wps_build_cred_auth_type(wps, plain) || 33239beb93cSSam Leffler wps_build_cred_encr_type(wps, plain) || 33339beb93cSSam Leffler wps_build_cred_network_key(wps, plain); 33439beb93cSSam Leffler } 33539beb93cSSam Leffler 33639beb93cSSam Leffler 33739beb93cSSam Leffler static struct wpabuf * wps_build_m7(struct wps_data *wps) 33839beb93cSSam Leffler { 33939beb93cSSam Leffler struct wpabuf *msg, *plain; 34039beb93cSSam Leffler 34139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M7"); 34239beb93cSSam Leffler 34339beb93cSSam Leffler plain = wpabuf_alloc(500 + wps->wps->ap_settings_len); 34439beb93cSSam Leffler if (plain == NULL) 34539beb93cSSam Leffler return NULL; 34639beb93cSSam Leffler 34739beb93cSSam Leffler msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len); 34839beb93cSSam Leffler if (msg == NULL) { 34939beb93cSSam Leffler wpabuf_free(plain); 35039beb93cSSam Leffler return NULL; 35139beb93cSSam Leffler } 35239beb93cSSam Leffler 35339beb93cSSam Leffler if (wps_build_version(msg) || 35439beb93cSSam Leffler wps_build_msg_type(msg, WPS_M7) || 35539beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) || 35639beb93cSSam Leffler wps_build_e_snonce2(wps, plain) || 35739beb93cSSam Leffler (wps->wps->ap && wps_build_ap_settings(wps, plain)) || 35839beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) || 35939beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) || 360*f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0) || 36139beb93cSSam Leffler wps_build_authenticator(wps, msg)) { 36239beb93cSSam Leffler wpabuf_free(plain); 36339beb93cSSam Leffler wpabuf_free(msg); 36439beb93cSSam Leffler return NULL; 36539beb93cSSam Leffler } 36639beb93cSSam Leffler wpabuf_free(plain); 36739beb93cSSam Leffler 368e28a4053SRui Paulo if (wps->wps->ap && wps->wps->registrar) { 369e28a4053SRui Paulo /* 370e28a4053SRui Paulo * If the Registrar is only learning our current configuration, 371e28a4053SRui Paulo * it may not continue protocol run to successful completion. 372e28a4053SRui Paulo * Store information here to make sure it remains available. 373e28a4053SRui Paulo */ 374e28a4053SRui Paulo wps_device_store(wps->wps->registrar, &wps->peer_dev, 375e28a4053SRui Paulo wps->uuid_r); 376e28a4053SRui Paulo } 377e28a4053SRui Paulo 37839beb93cSSam Leffler wps->state = RECV_M8; 37939beb93cSSam Leffler return msg; 38039beb93cSSam Leffler } 38139beb93cSSam Leffler 38239beb93cSSam Leffler 38339beb93cSSam Leffler static struct wpabuf * wps_build_wsc_done(struct wps_data *wps) 38439beb93cSSam Leffler { 38539beb93cSSam Leffler struct wpabuf *msg; 38639beb93cSSam Leffler 38739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done"); 38839beb93cSSam Leffler 38939beb93cSSam Leffler msg = wpabuf_alloc(1000); 39039beb93cSSam Leffler if (msg == NULL) 39139beb93cSSam Leffler return NULL; 39239beb93cSSam Leffler 39339beb93cSSam Leffler if (wps_build_version(msg) || 39439beb93cSSam Leffler wps_build_msg_type(msg, WPS_WSC_DONE) || 39539beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) || 396*f05cddf9SRui Paulo wps_build_registrar_nonce(wps, msg) || 397*f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 39839beb93cSSam Leffler wpabuf_free(msg); 39939beb93cSSam Leffler return NULL; 40039beb93cSSam Leffler } 40139beb93cSSam Leffler 40239beb93cSSam Leffler if (wps->wps->ap) 40339beb93cSSam Leffler wps->state = RECV_ACK; 40439beb93cSSam Leffler else { 40539beb93cSSam Leffler wps_success_event(wps->wps); 40639beb93cSSam Leffler wps->state = WPS_FINISHED; 40739beb93cSSam Leffler } 40839beb93cSSam Leffler return msg; 40939beb93cSSam Leffler } 41039beb93cSSam Leffler 41139beb93cSSam Leffler 41239beb93cSSam Leffler struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps, 41339beb93cSSam Leffler enum wsc_op_code *op_code) 41439beb93cSSam Leffler { 41539beb93cSSam Leffler struct wpabuf *msg; 41639beb93cSSam Leffler 41739beb93cSSam Leffler switch (wps->state) { 41839beb93cSSam Leffler case SEND_M1: 41939beb93cSSam Leffler msg = wps_build_m1(wps); 42039beb93cSSam Leffler *op_code = WSC_MSG; 42139beb93cSSam Leffler break; 42239beb93cSSam Leffler case SEND_M3: 42339beb93cSSam Leffler msg = wps_build_m3(wps); 42439beb93cSSam Leffler *op_code = WSC_MSG; 42539beb93cSSam Leffler break; 42639beb93cSSam Leffler case SEND_M5: 42739beb93cSSam Leffler msg = wps_build_m5(wps); 42839beb93cSSam Leffler *op_code = WSC_MSG; 42939beb93cSSam Leffler break; 43039beb93cSSam Leffler case SEND_M7: 43139beb93cSSam Leffler msg = wps_build_m7(wps); 43239beb93cSSam Leffler *op_code = WSC_MSG; 43339beb93cSSam Leffler break; 43439beb93cSSam Leffler case RECEIVED_M2D: 43539beb93cSSam Leffler if (wps->wps->ap) { 43639beb93cSSam Leffler msg = wps_build_wsc_nack(wps); 43739beb93cSSam Leffler *op_code = WSC_NACK; 43839beb93cSSam Leffler break; 43939beb93cSSam Leffler } 44039beb93cSSam Leffler msg = wps_build_wsc_ack(wps); 44139beb93cSSam Leffler *op_code = WSC_ACK; 44239beb93cSSam Leffler if (msg) { 44339beb93cSSam Leffler /* Another M2/M2D may be received */ 44439beb93cSSam Leffler wps->state = RECV_M2; 44539beb93cSSam Leffler } 44639beb93cSSam Leffler break; 44739beb93cSSam Leffler case SEND_WSC_NACK: 44839beb93cSSam Leffler msg = wps_build_wsc_nack(wps); 44939beb93cSSam Leffler *op_code = WSC_NACK; 45039beb93cSSam Leffler break; 45139beb93cSSam Leffler case WPS_MSG_DONE: 45239beb93cSSam Leffler msg = wps_build_wsc_done(wps); 45339beb93cSSam Leffler *op_code = WSC_Done; 45439beb93cSSam Leffler break; 45539beb93cSSam Leffler default: 45639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " 45739beb93cSSam Leffler "a message", wps->state); 45839beb93cSSam Leffler msg = NULL; 45939beb93cSSam Leffler break; 46039beb93cSSam Leffler } 46139beb93cSSam Leffler 46239beb93cSSam Leffler if (*op_code == WSC_MSG && msg) { 46339beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation 46439beb93cSSam Leffler */ 46539beb93cSSam Leffler wpabuf_free(wps->last_msg); 46639beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg); 46739beb93cSSam Leffler } 46839beb93cSSam Leffler 46939beb93cSSam Leffler return msg; 47039beb93cSSam Leffler } 47139beb93cSSam Leffler 47239beb93cSSam Leffler 47339beb93cSSam Leffler static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce) 47439beb93cSSam Leffler { 47539beb93cSSam Leffler if (r_nonce == NULL) { 47639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); 47739beb93cSSam Leffler return -1; 47839beb93cSSam Leffler } 47939beb93cSSam Leffler 48039beb93cSSam Leffler os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN); 48139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", 48239beb93cSSam Leffler wps->nonce_r, WPS_NONCE_LEN); 48339beb93cSSam Leffler 48439beb93cSSam Leffler return 0; 48539beb93cSSam Leffler } 48639beb93cSSam Leffler 48739beb93cSSam Leffler 48839beb93cSSam Leffler static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce) 48939beb93cSSam Leffler { 49039beb93cSSam Leffler if (e_nonce == NULL) { 49139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); 49239beb93cSSam Leffler return -1; 49339beb93cSSam Leffler } 49439beb93cSSam Leffler 49539beb93cSSam Leffler if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) { 49639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received"); 49739beb93cSSam Leffler return -1; 49839beb93cSSam Leffler } 49939beb93cSSam Leffler 50039beb93cSSam Leffler return 0; 50139beb93cSSam Leffler } 50239beb93cSSam Leffler 50339beb93cSSam Leffler 50439beb93cSSam Leffler static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r) 50539beb93cSSam Leffler { 50639beb93cSSam Leffler if (uuid_r == NULL) { 50739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No UUID-R received"); 50839beb93cSSam Leffler return -1; 50939beb93cSSam Leffler } 51039beb93cSSam Leffler 51139beb93cSSam Leffler os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN); 51239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); 51339beb93cSSam Leffler 51439beb93cSSam Leffler return 0; 51539beb93cSSam Leffler } 51639beb93cSSam Leffler 51739beb93cSSam Leffler 51839beb93cSSam Leffler static int wps_process_pubkey(struct wps_data *wps, const u8 *pk, 51939beb93cSSam Leffler size_t pk_len) 52039beb93cSSam Leffler { 52139beb93cSSam Leffler if (pk == NULL || pk_len == 0) { 52239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); 52339beb93cSSam Leffler return -1; 52439beb93cSSam Leffler } 52539beb93cSSam Leffler 52639beb93cSSam Leffler wpabuf_free(wps->dh_pubkey_r); 52739beb93cSSam Leffler wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len); 52839beb93cSSam Leffler if (wps->dh_pubkey_r == NULL) 52939beb93cSSam Leffler return -1; 53039beb93cSSam Leffler 53139beb93cSSam Leffler if (wps_derive_keys(wps) < 0) 53239beb93cSSam Leffler return -1; 53339beb93cSSam Leffler 53439beb93cSSam Leffler return 0; 53539beb93cSSam Leffler } 53639beb93cSSam Leffler 53739beb93cSSam Leffler 53839beb93cSSam Leffler static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1) 53939beb93cSSam Leffler { 54039beb93cSSam Leffler if (r_hash1 == NULL) { 54139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received"); 54239beb93cSSam Leffler return -1; 54339beb93cSSam Leffler } 54439beb93cSSam Leffler 54539beb93cSSam Leffler os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN); 54639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN); 54739beb93cSSam Leffler 54839beb93cSSam Leffler return 0; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler 55139beb93cSSam Leffler 55239beb93cSSam Leffler static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2) 55339beb93cSSam Leffler { 55439beb93cSSam Leffler if (r_hash2 == NULL) { 55539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received"); 55639beb93cSSam Leffler return -1; 55739beb93cSSam Leffler } 55839beb93cSSam Leffler 55939beb93cSSam Leffler os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN); 56039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN); 56139beb93cSSam Leffler 56239beb93cSSam Leffler return 0; 56339beb93cSSam Leffler } 56439beb93cSSam Leffler 56539beb93cSSam Leffler 56639beb93cSSam Leffler static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) 56739beb93cSSam Leffler { 56839beb93cSSam Leffler u8 hash[SHA256_MAC_LEN]; 56939beb93cSSam Leffler const u8 *addr[4]; 57039beb93cSSam Leffler size_t len[4]; 57139beb93cSSam Leffler 57239beb93cSSam Leffler if (r_snonce1 == NULL) { 57339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received"); 57439beb93cSSam Leffler return -1; 57539beb93cSSam Leffler } 57639beb93cSSam Leffler 57739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1, 57839beb93cSSam Leffler WPS_SECRET_NONCE_LEN); 57939beb93cSSam Leffler 58039beb93cSSam Leffler /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ 58139beb93cSSam Leffler addr[0] = r_snonce1; 58239beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN; 58339beb93cSSam Leffler addr[1] = wps->psk1; 58439beb93cSSam Leffler len[1] = WPS_PSK_LEN; 58539beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e); 58639beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e); 58739beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r); 58839beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r); 58939beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 59039beb93cSSam Leffler 59139beb93cSSam Leffler if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { 59239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " 59339beb93cSSam Leffler "not match with the pre-committed value"); 59439beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 59539beb93cSSam Leffler wps_pwd_auth_fail_event(wps->wps, 1, 1); 59639beb93cSSam Leffler return -1; 59739beb93cSSam Leffler } 59839beb93cSSam Leffler 59939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first " 60039beb93cSSam Leffler "half of the device password"); 60139beb93cSSam Leffler 60239beb93cSSam Leffler return 0; 60339beb93cSSam Leffler } 60439beb93cSSam Leffler 60539beb93cSSam Leffler 60639beb93cSSam Leffler static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) 60739beb93cSSam Leffler { 60839beb93cSSam Leffler u8 hash[SHA256_MAC_LEN]; 60939beb93cSSam Leffler const u8 *addr[4]; 61039beb93cSSam Leffler size_t len[4]; 61139beb93cSSam Leffler 61239beb93cSSam Leffler if (r_snonce2 == NULL) { 61339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received"); 61439beb93cSSam Leffler return -1; 61539beb93cSSam Leffler } 61639beb93cSSam Leffler 61739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2, 61839beb93cSSam Leffler WPS_SECRET_NONCE_LEN); 61939beb93cSSam Leffler 62039beb93cSSam Leffler /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ 62139beb93cSSam Leffler addr[0] = r_snonce2; 62239beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN; 62339beb93cSSam Leffler addr[1] = wps->psk2; 62439beb93cSSam Leffler len[1] = WPS_PSK_LEN; 62539beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e); 62639beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e); 62739beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r); 62839beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r); 62939beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 63039beb93cSSam Leffler 63139beb93cSSam Leffler if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { 63239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " 63339beb93cSSam Leffler "not match with the pre-committed value"); 63439beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 63539beb93cSSam Leffler wps_pwd_auth_fail_event(wps->wps, 1, 2); 63639beb93cSSam Leffler return -1; 63739beb93cSSam Leffler } 63839beb93cSSam Leffler 63939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second " 64039beb93cSSam Leffler "half of the device password"); 64139beb93cSSam Leffler 64239beb93cSSam Leffler return 0; 64339beb93cSSam Leffler } 64439beb93cSSam Leffler 64539beb93cSSam Leffler 64639beb93cSSam Leffler static int wps_process_cred_e(struct wps_data *wps, const u8 *cred, 647*f05cddf9SRui Paulo size_t cred_len, int wps2) 64839beb93cSSam Leffler { 64939beb93cSSam Leffler struct wps_parse_attr attr; 65039beb93cSSam Leffler struct wpabuf msg; 651*f05cddf9SRui Paulo int ret = 0; 65239beb93cSSam Leffler 65339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received Credential"); 65439beb93cSSam Leffler os_memset(&wps->cred, 0, sizeof(wps->cred)); 65539beb93cSSam Leffler wpabuf_set(&msg, cred, cred_len); 65639beb93cSSam Leffler if (wps_parse_msg(&msg, &attr) < 0 || 65739beb93cSSam Leffler wps_process_cred(&attr, &wps->cred)) 65839beb93cSSam Leffler return -1; 65939beb93cSSam Leffler 6603157ba21SRui Paulo if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != 6613157ba21SRui Paulo 0) { 6623157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential (" 6633157ba21SRui Paulo MACSTR ") does not match with own address (" MACSTR 6643157ba21SRui Paulo ")", MAC2STR(wps->cred.mac_addr), 6653157ba21SRui Paulo MAC2STR(wps->wps->dev.mac_addr)); 6663157ba21SRui Paulo /* 6673157ba21SRui Paulo * In theory, this could be consider fatal error, but there are 6683157ba21SRui Paulo * number of deployed implementations using other address here 6693157ba21SRui Paulo * due to unclarity in the specification. For interoperability 6703157ba21SRui Paulo * reasons, allow this to be processed since we do not really 6713157ba21SRui Paulo * use the MAC Address information for anything. 6723157ba21SRui Paulo */ 673*f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 674*f05cddf9SRui Paulo if (wps2) { 675*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " 676*f05cddf9SRui Paulo "MAC Address in AP Settings"); 677*f05cddf9SRui Paulo return -1; 6783157ba21SRui Paulo } 679*f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 680*f05cddf9SRui Paulo } 681*f05cddf9SRui Paulo 682*f05cddf9SRui Paulo #ifdef CONFIG_WPS2 683*f05cddf9SRui Paulo if (!(wps->cred.encr_type & 684*f05cddf9SRui Paulo (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) { 685*f05cddf9SRui Paulo if (wps->cred.encr_type & WPS_ENCR_WEP) { 686*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject Credential " 687*f05cddf9SRui Paulo "due to WEP configuration"); 688*f05cddf9SRui Paulo wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; 689*f05cddf9SRui Paulo return -2; 690*f05cddf9SRui Paulo } 691*f05cddf9SRui Paulo 692*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject Credential due to " 693*f05cddf9SRui Paulo "invalid encr_type 0x%x", wps->cred.encr_type); 694*f05cddf9SRui Paulo return -1; 695*f05cddf9SRui Paulo } 696*f05cddf9SRui Paulo #endif /* CONFIG_WPS2 */ 6973157ba21SRui Paulo 69839beb93cSSam Leffler if (wps->wps->cred_cb) { 69939beb93cSSam Leffler wps->cred.cred_attr = cred - 4; 70039beb93cSSam Leffler wps->cred.cred_attr_len = cred_len + 4; 701*f05cddf9SRui Paulo ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); 70239beb93cSSam Leffler wps->cred.cred_attr = NULL; 70339beb93cSSam Leffler wps->cred.cred_attr_len = 0; 70439beb93cSSam Leffler } 70539beb93cSSam Leffler 706*f05cddf9SRui Paulo return ret; 70739beb93cSSam Leffler } 70839beb93cSSam Leffler 70939beb93cSSam Leffler 71039beb93cSSam Leffler static int wps_process_creds(struct wps_data *wps, const u8 *cred[], 711*f05cddf9SRui Paulo size_t cred_len[], size_t num_cred, int wps2) 71239beb93cSSam Leffler { 71339beb93cSSam Leffler size_t i; 714*f05cddf9SRui Paulo int ok = 0; 71539beb93cSSam Leffler 71639beb93cSSam Leffler if (wps->wps->ap) 71739beb93cSSam Leffler return 0; 71839beb93cSSam Leffler 71939beb93cSSam Leffler if (num_cred == 0) { 72039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Credential attributes " 72139beb93cSSam Leffler "received"); 72239beb93cSSam Leffler return -1; 72339beb93cSSam Leffler } 72439beb93cSSam Leffler 72539beb93cSSam Leffler for (i = 0; i < num_cred; i++) { 726*f05cddf9SRui Paulo int res; 727*f05cddf9SRui Paulo res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2); 728*f05cddf9SRui Paulo if (res == 0) 729*f05cddf9SRui Paulo ok++; 730*f05cddf9SRui Paulo else if (res == -2) 731*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped"); 732*f05cddf9SRui Paulo else 733*f05cddf9SRui Paulo return -1; 734*f05cddf9SRui Paulo } 735*f05cddf9SRui Paulo 736*f05cddf9SRui Paulo if (ok == 0) { 737*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute " 738*f05cddf9SRui Paulo "received"); 73939beb93cSSam Leffler return -1; 74039beb93cSSam Leffler } 74139beb93cSSam Leffler 74239beb93cSSam Leffler return 0; 74339beb93cSSam Leffler } 74439beb93cSSam Leffler 74539beb93cSSam Leffler 74639beb93cSSam Leffler static int wps_process_ap_settings_e(struct wps_data *wps, 74739beb93cSSam Leffler struct wps_parse_attr *attr, 748*f05cddf9SRui Paulo struct wpabuf *attrs, int wps2) 74939beb93cSSam Leffler { 75039beb93cSSam Leffler struct wps_credential cred; 75139beb93cSSam Leffler 75239beb93cSSam Leffler if (!wps->wps->ap) 75339beb93cSSam Leffler return 0; 75439beb93cSSam Leffler 75539beb93cSSam Leffler if (wps_process_ap_settings(attr, &cred) < 0) 75639beb93cSSam Leffler return -1; 75739beb93cSSam Leffler 75839beb93cSSam Leffler wpa_printf(MSG_INFO, "WPS: Received new AP configuration from " 75939beb93cSSam Leffler "Registrar"); 76039beb93cSSam Leffler 7613157ba21SRui Paulo if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != 7623157ba21SRui Paulo 0) { 7633157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings (" 7643157ba21SRui Paulo MACSTR ") does not match with own address (" MACSTR 7653157ba21SRui Paulo ")", MAC2STR(cred.mac_addr), 7663157ba21SRui Paulo MAC2STR(wps->wps->dev.mac_addr)); 7673157ba21SRui Paulo /* 7683157ba21SRui Paulo * In theory, this could be consider fatal error, but there are 7693157ba21SRui Paulo * number of deployed implementations using other address here 7703157ba21SRui Paulo * due to unclarity in the specification. For interoperability 7713157ba21SRui Paulo * reasons, allow this to be processed since we do not really 7723157ba21SRui Paulo * use the MAC Address information for anything. 7733157ba21SRui Paulo */ 774*f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 775*f05cddf9SRui Paulo if (wps2) { 776*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Do not accept incorrect " 777*f05cddf9SRui Paulo "MAC Address in AP Settings"); 778*f05cddf9SRui Paulo return -1; 7793157ba21SRui Paulo } 780*f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 781*f05cddf9SRui Paulo } 782*f05cddf9SRui Paulo 783*f05cddf9SRui Paulo #ifdef CONFIG_WPS2 784*f05cddf9SRui Paulo if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) 785*f05cddf9SRui Paulo { 786*f05cddf9SRui Paulo if (cred.encr_type & WPS_ENCR_WEP) { 787*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings " 788*f05cddf9SRui Paulo "due to WEP configuration"); 789*f05cddf9SRui Paulo wps->error_indication = WPS_EI_SECURITY_WEP_PROHIBITED; 790*f05cddf9SRui Paulo return -1; 791*f05cddf9SRui Paulo } 792*f05cddf9SRui Paulo 793*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " 794*f05cddf9SRui Paulo "invalid encr_type 0x%x", cred.encr_type); 795*f05cddf9SRui Paulo return -1; 796*f05cddf9SRui Paulo } 797*f05cddf9SRui Paulo #endif /* CONFIG_WPS2 */ 798*f05cddf9SRui Paulo 799*f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 800*f05cddf9SRui Paulo if (wps2) { 801*f05cddf9SRui Paulo if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == 802*f05cddf9SRui Paulo WPS_ENCR_TKIP || 803*f05cddf9SRui Paulo (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 804*f05cddf9SRui Paulo WPS_AUTH_WPAPSK) { 805*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 " 806*f05cddf9SRui Paulo "AP Settings: WPA-Personal/TKIP only"); 807*f05cddf9SRui Paulo wps->error_indication = 808*f05cddf9SRui Paulo WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED; 809*f05cddf9SRui Paulo return -1; 810*f05cddf9SRui Paulo } 811*f05cddf9SRui Paulo } 812*f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 813*f05cddf9SRui Paulo 814*f05cddf9SRui Paulo #ifdef CONFIG_WPS2 815*f05cddf9SRui Paulo if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP) 816*f05cddf9SRui Paulo { 817*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " 818*f05cddf9SRui Paulo "TKIP+AES"); 819*f05cddf9SRui Paulo cred.encr_type |= WPS_ENCR_AES; 820*f05cddf9SRui Paulo } 821*f05cddf9SRui Paulo 822*f05cddf9SRui Paulo if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 823*f05cddf9SRui Paulo WPS_AUTH_WPAPSK) { 824*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " 825*f05cddf9SRui Paulo "WPAPSK+WPA2PSK"); 826*f05cddf9SRui Paulo cred.auth_type |= WPS_AUTH_WPA2PSK; 827*f05cddf9SRui Paulo } 828*f05cddf9SRui Paulo #endif /* CONFIG_WPS2 */ 8293157ba21SRui Paulo 83039beb93cSSam Leffler if (wps->wps->cred_cb) { 83139beb93cSSam Leffler cred.cred_attr = wpabuf_head(attrs); 83239beb93cSSam Leffler cred.cred_attr_len = wpabuf_len(attrs); 83339beb93cSSam Leffler wps->wps->cred_cb(wps->wps->cb_ctx, &cred); 83439beb93cSSam Leffler } 83539beb93cSSam Leffler 83639beb93cSSam Leffler return 0; 83739beb93cSSam Leffler } 83839beb93cSSam Leffler 83939beb93cSSam Leffler 84039beb93cSSam Leffler static enum wps_process_res wps_process_m2(struct wps_data *wps, 84139beb93cSSam Leffler const struct wpabuf *msg, 84239beb93cSSam Leffler struct wps_parse_attr *attr) 84339beb93cSSam Leffler { 84439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M2"); 84539beb93cSSam Leffler 84639beb93cSSam Leffler if (wps->state != RECV_M2) { 84739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 84839beb93cSSam Leffler "receiving M2", wps->state); 84939beb93cSSam Leffler wps->state = SEND_WSC_NACK; 85039beb93cSSam Leffler return WPS_CONTINUE; 85139beb93cSSam Leffler } 85239beb93cSSam Leffler 85339beb93cSSam Leffler if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || 85439beb93cSSam Leffler wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 855e28a4053SRui Paulo wps_process_uuid_r(wps, attr->uuid_r)) { 85639beb93cSSam Leffler wps->state = SEND_WSC_NACK; 85739beb93cSSam Leffler return WPS_CONTINUE; 85839beb93cSSam Leffler } 85939beb93cSSam Leffler 860*f05cddf9SRui Paulo /* 861*f05cddf9SRui Paulo * Stop here on an AP as an Enrollee if AP Setup is locked unless the 862*f05cddf9SRui Paulo * special locked mode is used to allow protocol run up to M7 in order 863*f05cddf9SRui Paulo * to support external Registrars that only learn the current AP 864*f05cddf9SRui Paulo * configuration without changing it. 865*f05cddf9SRui Paulo */ 866e28a4053SRui Paulo if (wps->wps->ap && 867*f05cddf9SRui Paulo ((wps->wps->ap_setup_locked && wps->wps->ap_setup_locked != 2) || 868*f05cddf9SRui Paulo wps->dev_password == NULL)) { 86939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " 87039beb93cSSam Leffler "registration of a new Registrar"); 87139beb93cSSam Leffler wps->config_error = WPS_CFG_SETUP_LOCKED; 87239beb93cSSam Leffler wps->state = SEND_WSC_NACK; 87339beb93cSSam Leffler return WPS_CONTINUE; 87439beb93cSSam Leffler } 87539beb93cSSam Leffler 876e28a4053SRui Paulo if (wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || 877e28a4053SRui Paulo wps_process_authenticator(wps, attr->authenticator, msg) || 878e28a4053SRui Paulo wps_process_device_attrs(&wps->peer_dev, attr)) { 879e28a4053SRui Paulo wps->state = SEND_WSC_NACK; 880e28a4053SRui Paulo return WPS_CONTINUE; 881e28a4053SRui Paulo } 882e28a4053SRui Paulo 88339beb93cSSam Leffler wps->state = SEND_M3; 88439beb93cSSam Leffler return WPS_CONTINUE; 88539beb93cSSam Leffler } 88639beb93cSSam Leffler 88739beb93cSSam Leffler 88839beb93cSSam Leffler static enum wps_process_res wps_process_m2d(struct wps_data *wps, 88939beb93cSSam Leffler struct wps_parse_attr *attr) 89039beb93cSSam Leffler { 89139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M2D"); 89239beb93cSSam Leffler 89339beb93cSSam Leffler if (wps->state != RECV_M2) { 89439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 89539beb93cSSam Leffler "receiving M2D", wps->state); 89639beb93cSSam Leffler wps->state = SEND_WSC_NACK; 89739beb93cSSam Leffler return WPS_CONTINUE; 89839beb93cSSam Leffler } 89939beb93cSSam Leffler 90039beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", 90139beb93cSSam Leffler attr->manufacturer, attr->manufacturer_len); 90239beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", 90339beb93cSSam Leffler attr->model_name, attr->model_name_len); 90439beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", 90539beb93cSSam Leffler attr->model_number, attr->model_number_len); 90639beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", 90739beb93cSSam Leffler attr->serial_number, attr->serial_number_len); 90839beb93cSSam Leffler wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", 90939beb93cSSam Leffler attr->dev_name, attr->dev_name_len); 91039beb93cSSam Leffler 91139beb93cSSam Leffler if (wps->wps->event_cb) { 91239beb93cSSam Leffler union wps_event_data data; 91339beb93cSSam Leffler struct wps_event_m2d *m2d = &data.m2d; 91439beb93cSSam Leffler os_memset(&data, 0, sizeof(data)); 91539beb93cSSam Leffler if (attr->config_methods) 91639beb93cSSam Leffler m2d->config_methods = 91739beb93cSSam Leffler WPA_GET_BE16(attr->config_methods); 91839beb93cSSam Leffler m2d->manufacturer = attr->manufacturer; 91939beb93cSSam Leffler m2d->manufacturer_len = attr->manufacturer_len; 92039beb93cSSam Leffler m2d->model_name = attr->model_name; 92139beb93cSSam Leffler m2d->model_name_len = attr->model_name_len; 92239beb93cSSam Leffler m2d->model_number = attr->model_number; 92339beb93cSSam Leffler m2d->model_number_len = attr->model_number_len; 92439beb93cSSam Leffler m2d->serial_number = attr->serial_number; 92539beb93cSSam Leffler m2d->serial_number_len = attr->serial_number_len; 92639beb93cSSam Leffler m2d->dev_name = attr->dev_name; 92739beb93cSSam Leffler m2d->dev_name_len = attr->dev_name_len; 92839beb93cSSam Leffler m2d->primary_dev_type = attr->primary_dev_type; 92939beb93cSSam Leffler if (attr->config_error) 93039beb93cSSam Leffler m2d->config_error = 93139beb93cSSam Leffler WPA_GET_BE16(attr->config_error); 93239beb93cSSam Leffler if (attr->dev_password_id) 93339beb93cSSam Leffler m2d->dev_password_id = 93439beb93cSSam Leffler WPA_GET_BE16(attr->dev_password_id); 93539beb93cSSam Leffler wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data); 93639beb93cSSam Leffler } 93739beb93cSSam Leffler 93839beb93cSSam Leffler wps->state = RECEIVED_M2D; 93939beb93cSSam Leffler return WPS_CONTINUE; 94039beb93cSSam Leffler } 94139beb93cSSam Leffler 94239beb93cSSam Leffler 94339beb93cSSam Leffler static enum wps_process_res wps_process_m4(struct wps_data *wps, 94439beb93cSSam Leffler const struct wpabuf *msg, 94539beb93cSSam Leffler struct wps_parse_attr *attr) 94639beb93cSSam Leffler { 94739beb93cSSam Leffler struct wpabuf *decrypted; 94839beb93cSSam Leffler struct wps_parse_attr eattr; 94939beb93cSSam Leffler 95039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M4"); 95139beb93cSSam Leffler 95239beb93cSSam Leffler if (wps->state != RECV_M4) { 95339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 95439beb93cSSam Leffler "receiving M4", wps->state); 95539beb93cSSam Leffler wps->state = SEND_WSC_NACK; 95639beb93cSSam Leffler return WPS_CONTINUE; 95739beb93cSSam Leffler } 95839beb93cSSam Leffler 95939beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 96039beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg) || 96139beb93cSSam Leffler wps_process_r_hash1(wps, attr->r_hash1) || 96239beb93cSSam Leffler wps_process_r_hash2(wps, attr->r_hash2)) { 96339beb93cSSam Leffler wps->state = SEND_WSC_NACK; 96439beb93cSSam Leffler return WPS_CONTINUE; 96539beb93cSSam Leffler } 96639beb93cSSam Leffler 96739beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 96839beb93cSSam Leffler attr->encr_settings_len); 96939beb93cSSam Leffler if (decrypted == NULL) { 97039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 97139beb93cSSam Leffler "Settings attribute"); 97239beb93cSSam Leffler wps->state = SEND_WSC_NACK; 97339beb93cSSam Leffler return WPS_CONTINUE; 97439beb93cSSam Leffler } 97539beb93cSSam Leffler 976*f05cddf9SRui Paulo if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) { 977*f05cddf9SRui Paulo wpabuf_free(decrypted); 978*f05cddf9SRui Paulo wps->state = SEND_WSC_NACK; 979*f05cddf9SRui Paulo return WPS_CONTINUE; 980*f05cddf9SRui Paulo } 981*f05cddf9SRui Paulo 98239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 98339beb93cSSam Leffler "attribute"); 98439beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 || 98539beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 98639beb93cSSam Leffler wps_process_r_snonce1(wps, eattr.r_snonce1)) { 98739beb93cSSam Leffler wpabuf_free(decrypted); 98839beb93cSSam Leffler wps->state = SEND_WSC_NACK; 98939beb93cSSam Leffler return WPS_CONTINUE; 99039beb93cSSam Leffler } 99139beb93cSSam Leffler wpabuf_free(decrypted); 99239beb93cSSam Leffler 99339beb93cSSam Leffler wps->state = SEND_M5; 99439beb93cSSam Leffler return WPS_CONTINUE; 99539beb93cSSam Leffler } 99639beb93cSSam Leffler 99739beb93cSSam Leffler 99839beb93cSSam Leffler static enum wps_process_res wps_process_m6(struct wps_data *wps, 99939beb93cSSam Leffler const struct wpabuf *msg, 100039beb93cSSam Leffler struct wps_parse_attr *attr) 100139beb93cSSam Leffler { 100239beb93cSSam Leffler struct wpabuf *decrypted; 100339beb93cSSam Leffler struct wps_parse_attr eattr; 100439beb93cSSam Leffler 100539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M6"); 100639beb93cSSam Leffler 100739beb93cSSam Leffler if (wps->state != RECV_M6) { 100839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 100939beb93cSSam Leffler "receiving M6", wps->state); 101039beb93cSSam Leffler wps->state = SEND_WSC_NACK; 101139beb93cSSam Leffler return WPS_CONTINUE; 101239beb93cSSam Leffler } 101339beb93cSSam Leffler 101439beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 101539beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) { 101639beb93cSSam Leffler wps->state = SEND_WSC_NACK; 101739beb93cSSam Leffler return WPS_CONTINUE; 101839beb93cSSam Leffler } 101939beb93cSSam Leffler 102039beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 102139beb93cSSam Leffler attr->encr_settings_len); 102239beb93cSSam Leffler if (decrypted == NULL) { 102339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 102439beb93cSSam Leffler "Settings attribute"); 102539beb93cSSam Leffler wps->state = SEND_WSC_NACK; 102639beb93cSSam Leffler return WPS_CONTINUE; 102739beb93cSSam Leffler } 102839beb93cSSam Leffler 1029*f05cddf9SRui Paulo if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) { 1030*f05cddf9SRui Paulo wpabuf_free(decrypted); 1031*f05cddf9SRui Paulo wps->state = SEND_WSC_NACK; 1032*f05cddf9SRui Paulo return WPS_CONTINUE; 1033*f05cddf9SRui Paulo } 1034*f05cddf9SRui Paulo 103539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 103639beb93cSSam Leffler "attribute"); 103739beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 || 103839beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 103939beb93cSSam Leffler wps_process_r_snonce2(wps, eattr.r_snonce2)) { 104039beb93cSSam Leffler wpabuf_free(decrypted); 104139beb93cSSam Leffler wps->state = SEND_WSC_NACK; 104239beb93cSSam Leffler return WPS_CONTINUE; 104339beb93cSSam Leffler } 104439beb93cSSam Leffler wpabuf_free(decrypted); 104539beb93cSSam Leffler 1046*f05cddf9SRui Paulo if (wps->wps->ap) 1047*f05cddf9SRui Paulo wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS, 1048*f05cddf9SRui Paulo NULL); 1049*f05cddf9SRui Paulo 105039beb93cSSam Leffler wps->state = SEND_M7; 105139beb93cSSam Leffler return WPS_CONTINUE; 105239beb93cSSam Leffler } 105339beb93cSSam Leffler 105439beb93cSSam Leffler 105539beb93cSSam Leffler static enum wps_process_res wps_process_m8(struct wps_data *wps, 105639beb93cSSam Leffler const struct wpabuf *msg, 105739beb93cSSam Leffler struct wps_parse_attr *attr) 105839beb93cSSam Leffler { 105939beb93cSSam Leffler struct wpabuf *decrypted; 106039beb93cSSam Leffler struct wps_parse_attr eattr; 106139beb93cSSam Leffler 106239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M8"); 106339beb93cSSam Leffler 106439beb93cSSam Leffler if (wps->state != RECV_M8) { 106539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 106639beb93cSSam Leffler "receiving M8", wps->state); 106739beb93cSSam Leffler wps->state = SEND_WSC_NACK; 106839beb93cSSam Leffler return WPS_CONTINUE; 106939beb93cSSam Leffler } 107039beb93cSSam Leffler 107139beb93cSSam Leffler if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 107239beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) { 107339beb93cSSam Leffler wps->state = SEND_WSC_NACK; 107439beb93cSSam Leffler return WPS_CONTINUE; 107539beb93cSSam Leffler } 107639beb93cSSam Leffler 1077*f05cddf9SRui Paulo if (wps->wps->ap && wps->wps->ap_setup_locked) { 1078*f05cddf9SRui Paulo /* 1079*f05cddf9SRui Paulo * Stop here if special ap_setup_locked == 2 mode allowed the 1080*f05cddf9SRui Paulo * protocol to continue beyond M2. This allows ER to learn the 1081*f05cddf9SRui Paulo * current AP settings without changing them. 1082*f05cddf9SRui Paulo */ 1083*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse " 1084*f05cddf9SRui Paulo "registration of a new Registrar"); 1085*f05cddf9SRui Paulo wps->config_error = WPS_CFG_SETUP_LOCKED; 1086*f05cddf9SRui Paulo wps->state = SEND_WSC_NACK; 1087*f05cddf9SRui Paulo return WPS_CONTINUE; 1088*f05cddf9SRui Paulo } 1089*f05cddf9SRui Paulo 109039beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 109139beb93cSSam Leffler attr->encr_settings_len); 109239beb93cSSam Leffler if (decrypted == NULL) { 109339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 109439beb93cSSam Leffler "Settings attribute"); 109539beb93cSSam Leffler wps->state = SEND_WSC_NACK; 109639beb93cSSam Leffler return WPS_CONTINUE; 109739beb93cSSam Leffler } 109839beb93cSSam Leffler 1099*f05cddf9SRui Paulo if (wps_validate_m8_encr(decrypted, wps->wps->ap, 1100*f05cddf9SRui Paulo attr->version2 != NULL) < 0) { 1101*f05cddf9SRui Paulo wpabuf_free(decrypted); 1102*f05cddf9SRui Paulo wps->state = SEND_WSC_NACK; 1103*f05cddf9SRui Paulo return WPS_CONTINUE; 1104*f05cddf9SRui Paulo } 1105*f05cddf9SRui Paulo 110639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 110739beb93cSSam Leffler "attribute"); 110839beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 || 110939beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 111039beb93cSSam Leffler wps_process_creds(wps, eattr.cred, eattr.cred_len, 1111*f05cddf9SRui Paulo eattr.num_cred, attr->version2 != NULL) || 1112*f05cddf9SRui Paulo wps_process_ap_settings_e(wps, &eattr, decrypted, 1113*f05cddf9SRui Paulo attr->version2 != NULL)) { 111439beb93cSSam Leffler wpabuf_free(decrypted); 111539beb93cSSam Leffler wps->state = SEND_WSC_NACK; 111639beb93cSSam Leffler return WPS_CONTINUE; 111739beb93cSSam Leffler } 111839beb93cSSam Leffler wpabuf_free(decrypted); 111939beb93cSSam Leffler 112039beb93cSSam Leffler wps->state = WPS_MSG_DONE; 112139beb93cSSam Leffler return WPS_CONTINUE; 112239beb93cSSam Leffler } 112339beb93cSSam Leffler 112439beb93cSSam Leffler 112539beb93cSSam Leffler static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, 112639beb93cSSam Leffler const struct wpabuf *msg) 112739beb93cSSam Leffler { 112839beb93cSSam Leffler struct wps_parse_attr attr; 112939beb93cSSam Leffler enum wps_process_res ret = WPS_CONTINUE; 113039beb93cSSam Leffler 113139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); 113239beb93cSSam Leffler 113339beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0) 113439beb93cSSam Leffler return WPS_FAILURE; 113539beb93cSSam Leffler 113639beb93cSSam Leffler if (attr.enrollee_nonce == NULL || 1137*f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 113839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 113939beb93cSSam Leffler return WPS_FAILURE; 114039beb93cSSam Leffler } 114139beb93cSSam Leffler 114239beb93cSSam Leffler if (attr.msg_type == NULL) { 114339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 1144*f05cddf9SRui Paulo wps->state = SEND_WSC_NACK; 1145*f05cddf9SRui Paulo return WPS_CONTINUE; 114639beb93cSSam Leffler } 114739beb93cSSam Leffler 114839beb93cSSam Leffler switch (*attr.msg_type) { 114939beb93cSSam Leffler case WPS_M2: 1150*f05cddf9SRui Paulo if (wps_validate_m2(msg) < 0) 1151*f05cddf9SRui Paulo return WPS_FAILURE; 115239beb93cSSam Leffler ret = wps_process_m2(wps, msg, &attr); 115339beb93cSSam Leffler break; 115439beb93cSSam Leffler case WPS_M2D: 1155*f05cddf9SRui Paulo if (wps_validate_m2d(msg) < 0) 1156*f05cddf9SRui Paulo return WPS_FAILURE; 115739beb93cSSam Leffler ret = wps_process_m2d(wps, &attr); 115839beb93cSSam Leffler break; 115939beb93cSSam Leffler case WPS_M4: 1160*f05cddf9SRui Paulo if (wps_validate_m4(msg) < 0) 1161*f05cddf9SRui Paulo return WPS_FAILURE; 116239beb93cSSam Leffler ret = wps_process_m4(wps, msg, &attr); 116339beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1164*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M4, wps->config_error, 1165*f05cddf9SRui Paulo wps->error_indication); 116639beb93cSSam Leffler break; 116739beb93cSSam Leffler case WPS_M6: 1168*f05cddf9SRui Paulo if (wps_validate_m6(msg) < 0) 1169*f05cddf9SRui Paulo return WPS_FAILURE; 117039beb93cSSam Leffler ret = wps_process_m6(wps, msg, &attr); 117139beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1172*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M6, wps->config_error, 1173*f05cddf9SRui Paulo wps->error_indication); 117439beb93cSSam Leffler break; 117539beb93cSSam Leffler case WPS_M8: 1176*f05cddf9SRui Paulo if (wps_validate_m8(msg) < 0) 1177*f05cddf9SRui Paulo return WPS_FAILURE; 117839beb93cSSam Leffler ret = wps_process_m8(wps, msg, &attr); 117939beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 1180*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M8, wps->config_error, 1181*f05cddf9SRui Paulo wps->error_indication); 118239beb93cSSam Leffler break; 118339beb93cSSam Leffler default: 118439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", 118539beb93cSSam Leffler *attr.msg_type); 118639beb93cSSam Leffler return WPS_FAILURE; 118739beb93cSSam Leffler } 118839beb93cSSam Leffler 118939beb93cSSam Leffler /* 119039beb93cSSam Leffler * Save a copy of the last message for Authenticator derivation if we 119139beb93cSSam Leffler * are continuing. However, skip M2D since it is not authenticated and 119239beb93cSSam Leffler * neither is the ACK/NACK response frame. This allows the possibly 119339beb93cSSam Leffler * following M2 to be processed correctly by using the previously sent 119439beb93cSSam Leffler * M1 in Authenticator derivation. 119539beb93cSSam Leffler */ 119639beb93cSSam Leffler if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) { 119739beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation 119839beb93cSSam Leffler */ 119939beb93cSSam Leffler wpabuf_free(wps->last_msg); 120039beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg); 120139beb93cSSam Leffler } 120239beb93cSSam Leffler 120339beb93cSSam Leffler return ret; 120439beb93cSSam Leffler } 120539beb93cSSam Leffler 120639beb93cSSam Leffler 120739beb93cSSam Leffler static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, 120839beb93cSSam Leffler const struct wpabuf *msg) 120939beb93cSSam Leffler { 121039beb93cSSam Leffler struct wps_parse_attr attr; 121139beb93cSSam Leffler 121239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); 121339beb93cSSam Leffler 121439beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0) 121539beb93cSSam Leffler return WPS_FAILURE; 121639beb93cSSam Leffler 121739beb93cSSam Leffler if (attr.msg_type == NULL) { 121839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 121939beb93cSSam Leffler return WPS_FAILURE; 122039beb93cSSam Leffler } 122139beb93cSSam Leffler 122239beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_ACK) { 122339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 122439beb93cSSam Leffler *attr.msg_type); 122539beb93cSSam Leffler return WPS_FAILURE; 122639beb93cSSam Leffler } 122739beb93cSSam Leffler 122839beb93cSSam Leffler if (attr.registrar_nonce == NULL || 1229*f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 123039beb93cSSam Leffler { 123139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 123239beb93cSSam Leffler return WPS_FAILURE; 123339beb93cSSam Leffler } 123439beb93cSSam Leffler 123539beb93cSSam Leffler if (attr.enrollee_nonce == NULL || 1236*f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 123739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 123839beb93cSSam Leffler return WPS_FAILURE; 123939beb93cSSam Leffler } 124039beb93cSSam Leffler 124139beb93cSSam Leffler if (wps->state == RECV_ACK && wps->wps->ap) { 124239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: External Registrar registration " 124339beb93cSSam Leffler "completed successfully"); 124439beb93cSSam Leffler wps_success_event(wps->wps); 124539beb93cSSam Leffler wps->state = WPS_FINISHED; 124639beb93cSSam Leffler return WPS_DONE; 124739beb93cSSam Leffler } 124839beb93cSSam Leffler 124939beb93cSSam Leffler return WPS_FAILURE; 125039beb93cSSam Leffler } 125139beb93cSSam Leffler 125239beb93cSSam Leffler 125339beb93cSSam Leffler static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, 125439beb93cSSam Leffler const struct wpabuf *msg) 125539beb93cSSam Leffler { 125639beb93cSSam Leffler struct wps_parse_attr attr; 1257*f05cddf9SRui Paulo u16 config_error; 125839beb93cSSam Leffler 125939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); 126039beb93cSSam Leffler 126139beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0) 126239beb93cSSam Leffler return WPS_FAILURE; 126339beb93cSSam Leffler 126439beb93cSSam Leffler if (attr.msg_type == NULL) { 126539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 126639beb93cSSam Leffler return WPS_FAILURE; 126739beb93cSSam Leffler } 126839beb93cSSam Leffler 126939beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_NACK) { 127039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 127139beb93cSSam Leffler *attr.msg_type); 127239beb93cSSam Leffler return WPS_FAILURE; 127339beb93cSSam Leffler } 127439beb93cSSam Leffler 127539beb93cSSam Leffler if (attr.registrar_nonce == NULL || 1276*f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 127739beb93cSSam Leffler { 127839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 127939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce", 128039beb93cSSam Leffler attr.registrar_nonce, WPS_NONCE_LEN); 128139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce", 128239beb93cSSam Leffler wps->nonce_r, WPS_NONCE_LEN); 128339beb93cSSam Leffler return WPS_FAILURE; 128439beb93cSSam Leffler } 128539beb93cSSam Leffler 128639beb93cSSam Leffler if (attr.enrollee_nonce == NULL || 1287*f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 128839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 128939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce", 129039beb93cSSam Leffler attr.enrollee_nonce, WPS_NONCE_LEN); 129139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce", 129239beb93cSSam Leffler wps->nonce_e, WPS_NONCE_LEN); 129339beb93cSSam Leffler return WPS_FAILURE; 129439beb93cSSam Leffler } 129539beb93cSSam Leffler 129639beb93cSSam Leffler if (attr.config_error == NULL) { 129739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " 129839beb93cSSam Leffler "in WSC_NACK"); 129939beb93cSSam Leffler return WPS_FAILURE; 130039beb93cSSam Leffler } 130139beb93cSSam Leffler 1302*f05cddf9SRui Paulo config_error = WPA_GET_BE16(attr.config_error); 130339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with " 1304*f05cddf9SRui Paulo "Configuration Error %d", config_error); 130539beb93cSSam Leffler 130639beb93cSSam Leffler switch (wps->state) { 130739beb93cSSam Leffler case RECV_M4: 1308*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M3, config_error, 1309*f05cddf9SRui Paulo wps->error_indication); 131039beb93cSSam Leffler break; 131139beb93cSSam Leffler case RECV_M6: 1312*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M5, config_error, 1313*f05cddf9SRui Paulo wps->error_indication); 131439beb93cSSam Leffler break; 131539beb93cSSam Leffler case RECV_M8: 1316*f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M7, config_error, 1317*f05cddf9SRui Paulo wps->error_indication); 131839beb93cSSam Leffler break; 131939beb93cSSam Leffler default: 132039beb93cSSam Leffler break; 132139beb93cSSam Leffler } 132239beb93cSSam Leffler 132339beb93cSSam Leffler /* Followed by NACK if Enrollee is Supplicant or EAP-Failure if 132439beb93cSSam Leffler * Enrollee is Authenticator */ 132539beb93cSSam Leffler wps->state = SEND_WSC_NACK; 132639beb93cSSam Leffler 132739beb93cSSam Leffler return WPS_FAILURE; 132839beb93cSSam Leffler } 132939beb93cSSam Leffler 133039beb93cSSam Leffler 133139beb93cSSam Leffler enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps, 133239beb93cSSam Leffler enum wsc_op_code op_code, 133339beb93cSSam Leffler const struct wpabuf *msg) 133439beb93cSSam Leffler { 133539beb93cSSam Leffler 133639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " 133739beb93cSSam Leffler "op_code=%d)", 133839beb93cSSam Leffler (unsigned long) wpabuf_len(msg), op_code); 133939beb93cSSam Leffler 13403157ba21SRui Paulo if (op_code == WSC_UPnP) { 13413157ba21SRui Paulo /* Determine the OpCode based on message type attribute */ 13423157ba21SRui Paulo struct wps_parse_attr attr; 13433157ba21SRui Paulo if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { 13443157ba21SRui Paulo if (*attr.msg_type == WPS_WSC_ACK) 13453157ba21SRui Paulo op_code = WSC_ACK; 13463157ba21SRui Paulo else if (*attr.msg_type == WPS_WSC_NACK) 13473157ba21SRui Paulo op_code = WSC_NACK; 13483157ba21SRui Paulo } 13493157ba21SRui Paulo } 13503157ba21SRui Paulo 135139beb93cSSam Leffler switch (op_code) { 135239beb93cSSam Leffler case WSC_MSG: 135339beb93cSSam Leffler case WSC_UPnP: 135439beb93cSSam Leffler return wps_process_wsc_msg(wps, msg); 135539beb93cSSam Leffler case WSC_ACK: 1356*f05cddf9SRui Paulo if (wps_validate_wsc_ack(msg) < 0) 1357*f05cddf9SRui Paulo return WPS_FAILURE; 135839beb93cSSam Leffler return wps_process_wsc_ack(wps, msg); 135939beb93cSSam Leffler case WSC_NACK: 1360*f05cddf9SRui Paulo if (wps_validate_wsc_nack(msg) < 0) 1361*f05cddf9SRui Paulo return WPS_FAILURE; 136239beb93cSSam Leffler return wps_process_wsc_nack(wps, msg); 136339beb93cSSam Leffler default: 136439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); 136539beb93cSSam Leffler return WPS_FAILURE; 136639beb93cSSam Leffler } 136739beb93cSSam Leffler } 1368