From 3e48c5d4b412770db89c6de0086bcf21432271cd Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 10 May 2020 23:46:41 +0300 Subject: [PATCH] DPP2: Reconfig Authentication Confirm processing Extend Enrollee functionality to process Reconfig Authentication Confirm message and start GAS client. Signed-off-by: Jouni Malinen --- src/common/dpp.c | 9 ++- src/common/dpp.h | 3 + src/common/dpp_reconfig.c | 124 ++++++++++++++++++++++++++++++++ wpa_supplicant/dpp_supplicant.c | 35 ++++++++- 4 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/common/dpp.c b/src/common/dpp.c index ff63256a4..9aa42f1c7 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -4756,8 +4756,15 @@ static void dpp_copy_netaccesskey(struct dpp_authentication *auth, unsigned char *der = NULL; int der_len; EC_KEY *eckey; + EVP_PKEY *own_key; - eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key); + own_key = auth->own_protocol_key; +#ifdef CONFIG_DPP2 + if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY && + auth->reconfig_old_protocol_key) + own_key = auth->reconfig_old_protocol_key; +#endif /* CONFIG_DPP2 */ + eckey = EVP_PKEY_get1_EC_KEY(own_key); if (!eckey) return; diff --git a/src/common/dpp.h b/src/common/dpp.h index d24e2f888..07c5bef62 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -243,6 +243,7 @@ struct dpp_authentication { u8 waiting_pubkey_hash[SHA256_MAC_LEN]; int response_pending; int reconfig; + enum dpp_connector_key reconfig_connector_key; enum dpp_status_error auth_resp_status; enum dpp_status_error conf_resp_status; u8 peer_mac_addr[ETH_ALEN]; @@ -661,6 +662,8 @@ dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, struct wpabuf * dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len); +int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, + const u8 *attr_start, size_t attr_len); #endif /* CONFIG_DPP */ #endif /* DPP_H */ diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c index 0db0e08b9..355114cbc 100644 --- a/src/common/dpp_reconfig.c +++ b/src/common/dpp_reconfig.c @@ -754,4 +754,128 @@ fail: goto out; } + +int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, + const u8 *attr_start, size_t attr_len) +{ + const u8 *trans_id, *version, *wrapped_data, *i_nonce, *r_nonce, + *reconfig_flags; + u16 trans_id_len, version_len, wrapped_data_len, i_nonce_len, + r_nonce_len, reconfig_flags_len; + const u8 *addr[2]; + size_t len[2]; + u8 *unwrapped = NULL; + size_t unwrapped_len = 0; + struct json_token *root = NULL, *token; + int res = -1; + + if (!auth->reconfig || auth->configurator) + goto fail; + + 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_MSGDUMP, "DPP: Wrapped Data", + wrapped_data, wrapped_data_len); + + addr[0] = hdr; + len[0] = DPP_HDR_LEN; + addr[1] = attr_start; + len[1] = 0; + 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; + } + + trans_id = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_TRANSACTION_ID, &trans_id_len); + if (!trans_id || trans_id_len != 1 || + trans_id[0] != auth->transaction_id) { + dpp_auth_fail(auth, + "Peer did not include valid Transaction ID"); + goto fail; + } + + version = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_PROTOCOL_VERSION, &version_len); + if (!version || version_len < 1 || version[0] != DPP_VERSION) { + dpp_auth_fail(auth, + "Missing or invalid Protocol Version attribute"); + goto fail; + } + + i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, + &i_nonce_len); + if (!i_nonce || i_nonce_len != auth->curve->nonce_len || + os_memcmp(i_nonce, auth->i_nonce, i_nonce_len) != 0) { + dpp_auth_fail(auth, "Missing or invalid I-nonce"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); + + r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE, + &r_nonce_len); + if (!r_nonce || r_nonce_len != auth->curve->nonce_len || + os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) { + dpp_auth_fail(auth, "Missing or invalid R-nonce"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len); + + reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_RECONFIG_FLAGS, + &reconfig_flags_len); + if (!reconfig_flags) { + dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags"); + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, "DPP: Reconfig-Flags", + reconfig_flags, reconfig_flags_len); + root = json_parse((const char *) reconfig_flags, reconfig_flags_len); + if (!root) { + dpp_auth_fail(auth, "Could not parse Reconfig-Flags"); + goto fail; + } + token = json_get_member(root, "connectorKey"); + if (!token || token->type != JSON_NUMBER) { + dpp_auth_fail(auth, "No connectorKey in Reconfig-Flags"); + goto fail; + } + if (token->number != DPP_CONFIG_REUSEKEY && + token->number != DPP_CONFIG_REPLACEKEY) { + dpp_auth_fail(auth, + "Unsupported connectorKey value in Reconfig-Flags"); + goto fail; + } + auth->reconfig_connector_key = token->number; + + auth->reconfig_success = true; + res = 0; +fail: + json_free(root); + bin_clear_free(unwrapped, unwrapped_len); + return res; +} + #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 8fd6ece79..ae93d59fd 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1374,7 +1374,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, wpa_s->dpp_gas_dialog_token = -1; - if (!auth || !auth->auth_success) { + if (!auth || (!auth->auth_success && !auth->reconfig_success) || + os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return; } @@ -2007,6 +2008,35 @@ wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, wpas_dpp_start_gas_server(wpa_s); } + +static void +wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + + wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Confirm from " + MACSTR, MAC2STR(src)); + + if (!auth || !auth->reconfig || auth->configurator) { + wpa_printf(MSG_DEBUG, + "DPP: No DPP Reconfig Authentication in progress - 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; + } + + if (dpp_reconfig_auth_conf_rx(auth, hdr, buf, len) < 0) + return; + + wpas_dpp_start_gas_client(wpa_s); +} + #endif /* CONFIG_DPP2 */ @@ -2578,6 +2608,9 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, case DPP_PA_RECONFIG_AUTH_RESP: wpas_dpp_rx_reconfig_auth_resp(wpa_s, src, hdr, buf, len, freq); break; + case DPP_PA_RECONFIG_AUTH_CONF: + wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq); + break; #endif /* CONFIG_DPP2 */ default: wpa_printf(MSG_DEBUG,