From 22f90b32f14e718a6d6f59942b54aad03ec0c605 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 Mar 2019 17:05:02 +0200 Subject: [PATCH] DPP2: Configuration Result message generation and processing Use this new message from Enrollee to Configurator to indicate result of the config object provisioning if both devices support protocol version 2 or newer. Signed-off-by: Jouni Malinen --- src/ap/dpp_hostapd.c | 129 +++++++++++++++++++- src/common/dpp.c | 145 +++++++++++++++++++++++ src/common/dpp.h | 10 ++ wpa_supplicant/dpp_supplicant.c | 202 ++++++++++++++++++++++++++++---- 4 files changed, 456 insertions(+), 30 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 149f389f7..a84654d2d 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -354,6 +354,16 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, return; } +#ifdef CONFIG_DPP2 + if (auth->connect_on_tx_status) { + wpa_printf(MSG_DEBUG, + "DPP: Complete exchange on configuration result"); + dpp_auth_deinit(hapd->dpp_auth); + hapd->dpp_auth = NULL; + return; + } +#endif /* CONFIG_DPP2 */ + if (hapd->dpp_auth->remove_on_tx_status) { wpa_printf(MSG_DEBUG, "DPP: Terminate authentication exchange due to an earlier error"); @@ -1072,6 +1082,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, struct hostapd_data *hapd = ctx; const u8 *pos; struct dpp_authentication *auth = hapd->dpp_auth; + enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; if (!auth || !auth->auth_success) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); @@ -1107,12 +1118,35 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, } hostapd_dpp_handle_config_obj(hapd, auth); - dpp_auth_deinit(hapd->dpp_auth); - hapd->dpp_auth = NULL; - return; - + status = DPP_STATUS_OK; fail: - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); + if (status != DPP_STATUS_OK) + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); +#ifdef CONFIG_DPP2 + if (auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); + msg = dpp_build_conf_result(auth, status); + if (!msg) + goto fail2; + + wpa_msg(hapd->msg_ctx, MSG_INFO, + DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(addr), auth->curr_freq, + DPP_PA_CONFIGURATION_RESULT); + hostapd_drv_send_action(hapd, auth->curr_freq, 0, + addr, wpabuf_head(msg), + wpabuf_len(msg)); + wpabuf_free(msg); + + /* This exchange will be terminated in the TX status handler */ + auth->connect_on_tx_status = 1; + return; + } +fail2: +#endif /* CONFIG_DPP2 */ dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; } @@ -1281,6 +1315,63 @@ static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src, } +#ifdef CONFIG_DPP2 + +static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth || !auth->waiting_conf_result) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Timeout while waiting for Configuration Result"); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + hapd->dpp_auth = NULL; +} + + +static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len) +{ + struct dpp_authentication *auth = hapd->dpp_auth; + enum dpp_status_error status; + + wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR, + MAC2STR(src)); + + if (!auth || !auth->waiting_conf_result) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Configuration waiting for result - drop"); + return; + } + + if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + return; + } + + status = dpp_conf_result_rx(auth, hdr, buf, len); + + hostapd_drv_send_action_cancel_wait(hapd); + hostapd_dpp_listen_stop(hapd); + if (status == DPP_STATUS_OK) + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + hapd->dpp_auth = NULL; + eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, + NULL); +} + +#endif /* CONFIG_DPP2 */ + + static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd, const u8 *src, unsigned int freq, u8 trans_id, @@ -1744,6 +1835,11 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len, freq); break; +#ifdef CONFIG_DPP2 + case DPP_PA_CONFIGURATION_RESULT: + hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len); + break; +#endif /* CONFIG_DPP2 */ default: wpa_printf(MSG_DEBUG, "DPP: Ignored unsupported frame subtype %d", type); @@ -1790,11 +1886,28 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) { - if (!hapd->dpp_auth) + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth) return; + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", + ok); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); +#ifdef CONFIG_DPP2 + if (ok && auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); + auth->waiting_conf_result = 1; + eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, + hapd, NULL); + eloop_register_timeout(2, 0, + hostapd_dpp_config_result_wait_timeout, + hapd, NULL); + return; + } +#endif /* CONFIG_DPP2 */ hostapd_drv_send_action_cancel_wait(hapd); if (ok) @@ -2070,6 +2183,10 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, + NULL); +#endif /* CONFIG_DPP2 */ dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; hostapd_dpp_pkex_remove(hapd, "*"); diff --git a/src/common/dpp.c b/src/common/dpp.c index 00208128b..c7a200780 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -4441,6 +4441,7 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, wpabuf_head(conf), wpabuf_len(conf)); } status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE; + auth->conf_resp_status = status; /* { E-nonce, configurationObject}ke */ clear_len = 4 + e_nonce_len; @@ -4613,6 +4614,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, goto fail; } wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); + os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); config_attr = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_ATTR_OBJ, @@ -5486,6 +5488,8 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, size_t unwrapped_len = 0; int ret = -1; + auth->conf_resp_status = 255; + if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { dpp_auth_fail(auth, "Invalid attribute in config response"); return -1; @@ -5546,6 +5550,7 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, "Missing or invalid required DPP Status attribute"); goto fail; } + auth->conf_resp_status = status[0]; wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); if (status[0] != DPP_STATUS_OK) { dpp_auth_fail(auth, "Configurator rejected configuration"); @@ -5572,6 +5577,146 @@ fail: } +#ifdef CONFIG_DPP2 +enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth, + const u8 *hdr, + const u8 *attr_start, size_t attr_len) +{ + const u8 *wrapped_data, *status, *e_nonce; + u16 wrapped_data_len, status_len, e_nonce_len; + const u8 *addr[2]; + size_t len[2]; + u8 *unwrapped = NULL; + size_t unwrapped_len = 0; + enum dpp_status_error ret = 256; + + wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, + &wrapped_data_len); + if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { + dpp_auth_fail(auth, + "Missing or invalid required Wrapped Data attribute"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", + wrapped_data, wrapped_data_len); + + attr_len = wrapped_data - 4 - attr_start; + + addr[0] = hdr; + len[0] = DPP_HDR_LEN; + addr[1] = attr_start; + len[1] = attr_len; + wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); + wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); + wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", + wrapped_data, wrapped_data_len); + unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; + unwrapped = os_malloc(unwrapped_len); + if (!unwrapped) + goto fail; + if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, + wrapped_data, wrapped_data_len, + 2, addr, len, unwrapped) < 0) { + dpp_auth_fail(auth, "AES-SIV decryption failed"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", + unwrapped, unwrapped_len); + + if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { + dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); + goto fail; + } + + e_nonce = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_ENROLLEE_NONCE, + &e_nonce_len); + if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { + dpp_auth_fail(auth, + "Missing or invalid Enrollee Nonce attribute"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); + if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { + dpp_auth_fail(auth, "Enrollee Nonce mismatch"); + wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce", + auth->e_nonce, e_nonce_len); + goto fail; + } + + status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS, + &status_len); + if (!status || status_len < 1) { + dpp_auth_fail(auth, + "Missing or invalid required DPP Status attribute"); + goto fail; + } + wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); + ret = status[0]; + +fail: + bin_clear_free(unwrapped, unwrapped_len); + return ret; +} +#endif /* CONFIG_DPP2 */ + + +struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth, + enum dpp_status_error status) +{ + struct wpabuf *msg, *clear; + size_t nonce_len, clear_len, attr_len; + const u8 *addr[2]; + size_t len[2]; + u8 *wrapped; + + nonce_len = auth->curve->nonce_len; + clear_len = 5 + 4 + nonce_len; + attr_len = 4 + clear_len + AES_BLOCK_SIZE; + clear = wpabuf_alloc(clear_len); + msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len); + if (!clear || !msg) + return NULL; + + /* DPP Status */ + dpp_build_attr_status(clear, status); + + /* E-nonce */ + wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); + wpabuf_put_le16(clear, nonce_len); + wpabuf_put_data(clear, auth->e_nonce, nonce_len); + + /* OUI, OUI type, Crypto Suite, DPP frame type */ + addr[0] = wpabuf_head_u8(msg) + 2; + len[0] = 3 + 1 + 1 + 1; + wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); + + /* Attributes before Wrapped Data (none) */ + addr[1] = wpabuf_put(msg, 0); + len[1] = 0; + wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); + + /* Wrapped Data */ + wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); + wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); + wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); + + wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); + if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, + wpabuf_head(clear), wpabuf_len(clear), + 2, addr, len, wrapped) < 0) + goto fail; + + wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg); + wpabuf_free(clear); + return msg; +fail: + wpabuf_free(clear); + wpabuf_free(msg); + return NULL; +} + + void dpp_configurator_free(struct dpp_configurator *conf) { if (!conf) diff --git a/src/common/dpp.h b/src/common/dpp.h index 4b192ac0b..4af913bc1 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -28,6 +28,7 @@ enum dpp_public_action_frame_type { DPP_PA_PKEX_EXCHANGE_RESP = 8, DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9, DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10, + DPP_PA_CONFIGURATION_RESULT = 11, }; enum dpp_attribute_id { @@ -69,6 +70,7 @@ enum dpp_status_error { DPP_STATUS_RESPONSE_PENDING = 6, DPP_STATUS_INVALID_CONNECTOR = 7, DPP_STATUS_NO_MATCH = 8, + DPP_STATUS_CONFIG_REJECTED = 9, }; #define DPP_CAPAB_ENROLLEE BIT(0) @@ -173,6 +175,7 @@ struct dpp_authentication { u8 waiting_pubkey_hash[SHA256_MAC_LEN]; int response_pending; enum dpp_status_error auth_resp_status; + enum dpp_status_error conf_resp_status; u8 peer_mac_addr[ETH_ALEN]; u8 i_nonce[DPP_MAX_NONCE_LEN]; u8 r_nonce[DPP_MAX_NONCE_LEN]; @@ -208,6 +211,8 @@ struct dpp_authentication { u8 allowed_roles; int configurator; int remove_on_tx_status; + int connect_on_tx_status; + int waiting_conf_result; int auth_success; struct wpabuf *conf_req; const struct wpabuf *conf_resp; /* owned by GAS server */ @@ -393,6 +398,11 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, size_t attr_len); int dpp_conf_resp_rx(struct dpp_authentication *auth, const struct wpabuf *resp); +enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth, + const u8 *hdr, + const u8 *attr_start, size_t attr_len); +struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth, + enum dpp_status_error status); struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, size_t len); const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len); diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 74f71701f..8de53ad8b 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -364,6 +364,18 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s) } +static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network"); + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + wpa_s->scan_runs = 0; + wpa_s->normal_scans = 0; + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); +} + + static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, @@ -387,6 +399,17 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, return; } +#ifdef CONFIG_DPP2 + if (auth->connect_on_tx_status) { + wpa_printf(MSG_DEBUG, + "DPP: Try to connect after completed configuration result"); + wpas_dpp_try_to_connect(wpa_s); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + return; + } +#endif /* CONFIG_DPP2 */ + if (wpa_s->dpp_auth->remove_on_tx_status) { wpa_printf(MSG_DEBUG, "DPP: Terminate authentication exchange due to an earlier error"); @@ -1165,6 +1188,27 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, { struct wpa_ssid *ssid; +#ifdef CONFIG_DPP2 + if (auth->akm == DPP_AKM_SAE) { +#ifdef CONFIG_SAE + struct wpa_driver_capa capa; + int res; + + res = wpa_drv_get_capa(wpa_s, &capa); + if (res == 0 && + !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { + wpa_printf(MSG_DEBUG, + "DPP: SAE not supported by the driver"); + return NULL; + } +#else /* CONFIG_SAE */ + wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build"); + return NULL; +#endif /* CONFIG_SAE */ + } +#endif /* CONFIG_DPP2 */ + ssid = wpa_config_add_network(wpa_s->conf); if (!ssid) return NULL; @@ -1236,17 +1280,17 @@ fail: } -static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s, - struct dpp_authentication *auth) +static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) { struct wpa_ssid *ssid; if (wpa_s->conf->dpp_config_processing < 1) - return; + return 0; ssid = wpas_dpp_add_network(wpa_s, auth); if (!ssid) - return; + return -1; wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id); if (wpa_s->conf->dpp_config_processing == 2) @@ -1259,20 +1303,24 @@ static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_CONFIG_WRITE */ if (wpa_s->conf->dpp_config_processing < 2) - return; + return 0; - wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network"); - wpa_s->disconnected = 0; - wpa_s->reassociate = 1; - wpa_s->scan_runs = 0; - wpa_s->normal_scans = 0; - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); +#ifdef CONFIG_DPP2 + if (auth->peer_version >= 2) { + wpa_printf(MSG_DEBUG, + "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result"); + auth->connect_on_tx_status = 1; + return 0; + } +#endif /* CONFIG_DPP2 */ + + wpas_dpp_try_to_connect(wpa_s); + return 0; } -static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, - struct dpp_authentication *auth) +static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, + struct dpp_authentication *auth) { wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED); if (auth->ssid_len) @@ -1324,7 +1372,7 @@ static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, } } - wpas_dpp_process_config(wpa_s, auth); + return wpas_dpp_process_config(wpa_s, auth); } @@ -1336,6 +1384,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, struct wpa_supplicant *wpa_s = ctx; const u8 *pos; struct dpp_authentication *auth = wpa_s->dpp_auth; + int res; + enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; wpa_s->dpp_gas_dialog_token = -1; @@ -1373,13 +1423,40 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, goto fail; } - wpas_dpp_handle_config_obj(wpa_s, auth); - dpp_auth_deinit(wpa_s->dpp_auth); - wpa_s->dpp_auth = NULL; - return; + res = wpas_dpp_handle_config_obj(wpa_s, auth); + if (res < 0) + goto fail; + status = DPP_STATUS_OK; fail: - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + if (status != DPP_STATUS_OK) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); +#ifdef CONFIG_DPP2 + if (auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); + msg = dpp_build_conf_result(auth, status); + if (!msg) + goto fail2; + + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(addr), auth->curr_freq, + DPP_PA_CONFIGURATION_RESULT); + offchannel_send_action(wpa_s, auth->curr_freq, + addr, wpa_s->own_addr, broadcast, + wpabuf_head(msg), + wpabuf_len(msg), + 500, wpas_dpp_tx_status, 0); + wpabuf_free(msg); + + /* This exchange will be terminated in the TX status handler */ + return; + } +fail2: +#endif /* CONFIG_DPP2 */ dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; } @@ -1562,6 +1639,62 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src, } +#ifdef CONFIG_DPP2 + +static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth || !auth->waiting_conf_result) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Timeout while waiting for Configuration Result"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; +} + + +static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + enum dpp_status_error status; + + wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR, + MAC2STR(src)); + + if (!auth || !auth->waiting_conf_result) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Configuration waiting for result - drop"); + return; + } + + if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " + MACSTR ") - drop", MAC2STR(auth->peer_mac_addr)); + return; + } + + status = dpp_conf_result_rx(auth, hdr, buf, len); + + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + if (status == DPP_STATUS_OK) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); + else + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(auth); + wpa_s->dpp_auth = NULL; + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); +} + +#endif /* CONFIG_DPP2 */ + + static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *buf, size_t len) @@ -2105,6 +2238,11 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len, freq); break; +#ifdef CONFIG_DPP2 + case DPP_PA_CONFIGURATION_RESULT: + wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len); + break; +#endif /* CONFIG_DPP2 */ default: wpa_printf(MSG_DEBUG, "DPP: Ignored unsupported frame subtype %d", type); @@ -2174,6 +2312,21 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) ok); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + if (ok && auth->peer_version >= 2 && + auth->conf_resp_status == DPP_STATUS_OK) { + wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); + auth->waiting_conf_result = 1; + auth->conf_resp = NULL; + wpabuf_free(resp); + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, + wpa_s, NULL); + eloop_register_timeout(2, 0, + wpas_dpp_config_result_wait_timeout, + wpa_s, NULL); + return; + } +#endif /* CONFIG_DPP2 */ offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); if (ok) @@ -2286,10 +2439,8 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd) curve = get_param(cmd, " curve="); wpas_dpp_set_testing_options(wpa_s, auth); if (wpas_dpp_set_configurator(wpa_s, auth, cmd) == 0 && - dpp_configurator_own_config(auth, curve, 0) == 0) { - wpas_dpp_handle_config_obj(wpa_s, auth); - ret = 0; - } + dpp_configurator_own_config(auth, curve, 0) == 0) + ret = wpas_dpp_handle_config_obj(wpa_s, auth); dpp_auth_deinit(auth); os_free(curve); @@ -2610,6 +2761,9 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); +#endif /* CONFIG_DPP2 */ offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); dpp_bootstrap_del(wpa_s, 0);