From de64dfe98e2fd9c1a75490bf44aa1c2e6f271f1a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 9 Mar 2022 01:06:01 +0200 Subject: [PATCH] DPP: Curve change for netAccessKey Allow the Configurator to be configured to use a specific curve for the netAccessKey so that it can request the Enrollee to generate a new key during the configuration exchange to allow a compatible Connector to be generated when the network uses a different curve than the protocol keys used during the authentication exchange. Signed-off-by: Jouni Malinen --- src/ap/dpp_hostapd.c | 38 ++++- src/common/dpp.c | 268 ++++++++++++++++++++++++++++++-- src/common/dpp.h | 5 + src/common/dpp_crypto.c | 94 +++++++++++ src/common/dpp_i.h | 1 + src/common/dpp_tcp.c | 37 +++++ wpa_supplicant/dpp_supplicant.c | 34 ++++ 7 files changed, 466 insertions(+), 11 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 74d7a5923..d4cbed88d 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -31,6 +31,7 @@ static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx); static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd); static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, struct dpp_authentication *auth); +static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd); #ifdef CONFIG_DPP2 static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx); @@ -1154,6 +1155,21 @@ static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd, } +#ifdef CONFIG_DPP3 +static void hostapd_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + hostapd_dpp_start_gas_client(hapd); +} +#endif /* CONFIG_DPP3 */ + + static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_ap_result result, const struct wpabuf *adv_proto, @@ -1163,6 +1179,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const u8 *pos; struct dpp_authentication *auth = hapd->dpp_auth; enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; + int res; if (!auth || !auth->auth_success) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); @@ -1193,7 +1210,16 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, goto fail; } - if (dpp_conf_resp_rx(auth, resp) < 0) { + res = dpp_conf_resp_rx(auth, resp); +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, hostapd_dpp_build_new_key, hapd, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ + if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; } @@ -2354,6 +2380,13 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) if (!auth) return; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); @@ -2651,6 +2684,9 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) if (hapd->iface->interfaces) dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd); #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL); +#endif /* CONFIG_DPP3 */ 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 879f9a8c0..4118a05f5 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -658,9 +658,12 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, { size_t nonce_len; size_t json_len, clear_len; - struct wpabuf *clear = NULL, *msg = NULL; + struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL; u8 *wrapped; size_t attr_len; +#ifdef CONFIG_DPP3 + u8 auth_i[DPP_MAX_HASH_LEN]; +#endif /* CONFIG_DPP3 */ wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); @@ -675,6 +678,18 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, /* { E-nonce, configAttrib }ke */ clear_len = 4 + nonce_len + 4 + json_len; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + if (!pe) + goto fail; + clear_len += 4 + wpabuf_len(pe); + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + clear_len += 4 + auth->new_curve->hash_len; + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -716,6 +731,21 @@ skip_e_nonce: } #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_DPP3 + if (pe) { + wpa_printf(MSG_DEBUG, "DPP: Pe"); + wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pe)); + wpabuf_put_buf(clear, pe); + } + if (auth->waiting_new_key && auth->new_curve) { + wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag"); + wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); + wpabuf_put_le16(clear, auth->new_curve->hash_len); + wpabuf_put_data(clear, auth_i, auth->new_curve->hash_len); + } +#endif /* CONFIG_DPP3 */ + /* configAttrib */ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); wpabuf_put_le16(clear, json_len); @@ -748,13 +778,15 @@ skip_wrapped_data: wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Request frame attributes", msg); +out: wpabuf_free(clear); + wpabuf_free(pe); return msg; fail: - wpabuf_free(clear); wpabuf_free(msg); - return NULL; + msg = NULL; + goto out; } @@ -1430,7 +1462,8 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, struct wpabuf *buf = NULL; char *signed_conn = NULL; size_t tailroom; - const struct dpp_curve_params *curve; + const struct dpp_curve_params *curve; /* C-sign-key curve */ + const struct dpp_curve_params *nak_curve; /* netAccessKey curve */ struct wpabuf *dppcon = NULL; size_t extra_len = 1000; int incl_legacy; @@ -1443,6 +1476,10 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, goto fail; } curve = auth->conf->curve; + if (auth->new_curve && auth->new_key_received) + nak_curve = auth->new_curve; + else + nak_curve = auth->curve; akm = conf->akm; if (dpp_akm_ver2(akm) && auth->peer_version < 2) { @@ -1460,7 +1497,7 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, extra_len += os_strlen(conf->group_id); /* Connector (JSON dppCon object) */ - dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); + dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3); if (!dppcon) goto fail; #ifdef CONFIG_TESTING_OPTIONS @@ -1490,9 +1527,31 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, #ifdef CONFIG_TESTING_OPTIONS skip_groups: #endif /* CONFIG_TESTING_OPTIONS */ - if (!auth->peer_protocol_key || - dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, - auth->curve) < 0) { + if (!auth->peer_protocol_key) { + wpa_printf(MSG_DEBUG, + "DPP: No peer protocol key available to build netAccessKey JWK"); + goto fail; + } +#ifdef CONFIG_DPP3 + if (auth->conf->net_access_key_curve && + auth->curve != auth->conf->net_access_key_curve && + !auth->new_key_received) { + wpa_printf(MSG_DEBUG, + "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s", + auth->curve->name, + auth->conf->net_access_key_curve->name, + auth->waiting_new_key ? + "the required key not received" : + "request a new key"); + if (auth->waiting_new_key) + auth->waiting_new_key = false; /* failed */ + else + auth->waiting_new_key = true; + goto fail; + } +#endif /* CONFIG_DPP3 */ + if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, + nak_curve) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); goto fail; } @@ -1731,7 +1790,7 @@ struct wpabuf * dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req) { - struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL; + struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL; size_t clear_len, attr_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; @@ -1765,6 +1824,10 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta && auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr) status = DPP_STATUS_CSR_NEEDED; +#ifdef CONFIG_DPP3 + else if (auth->waiting_new_key) + status = DPP_STATUS_NEW_KEY_NEEDED; +#endif /* CONFIG_DPP3 */ else status = DPP_STATUS_CONFIGURE_FAILURE; forced_status: @@ -1784,6 +1847,31 @@ forced_status: if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && auth->conf_sta->csrattrs) clear_len += 4 + os_strlen(auth->conf_sta->csrattrs); +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED) { + struct crypto_ec_key *new_pc; + + clear_len += 6; /* Finite Cyclic Group attribute */ + + wpa_printf(MSG_DEBUG, + "DPP: Generate a new own protocol key for the curve %s", + auth->conf->net_access_key_curve->name); + new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve); + if (!new_pc) { + wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc"); + return NULL; + } + pc = crypto_ec_key_get_pubkey_point(new_pc, 0); + if (!pc) { + crypto_ec_key_deinit(new_pc); + return NULL; + } + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pc; + auth->new_curve = auth->conf->net_access_key_curve; + clear_len += 4 + wpabuf_len(pc); + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -1861,6 +1949,27 @@ skip_e_nonce: wpabuf_put_str(clear, auth->conf_sta->csrattrs); } +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf && + auth->conf->net_access_key_curve) { + u16 ike_group = auth->conf->net_access_key_curve->ike_group; + + /* Finite Cyclic Group attribute */ + wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u", + ike_group); + wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP); + wpabuf_put_le16(clear, 2); + wpabuf_put_le16(clear, ike_group); + + if (pc) { + wpa_printf(MSG_DEBUG, "DPP: Pc"); + wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pc)); + wpabuf_put_buf(clear, pc); + } + } +#endif /* CONFIG_DPP3 */ + #ifdef CONFIG_TESTING_OPTIONS skip_config_obj: if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { @@ -1911,6 +2020,7 @@ out: wpabuf_clear_free(conf2); wpabuf_clear_free(env_data); wpabuf_clear_free(clear); + wpabuf_free(pc); return msg; fail: @@ -1932,6 +2042,10 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, struct json_token *root = NULL, *token; enum dpp_netrole netrole; struct wpabuf *cert_req = NULL; +#ifdef CONFIG_DPP3 + const u8 *i_proto; + u16 i_proto_len; +#endif /* CONFIG_DPP3 */ #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { @@ -1985,6 +2099,60 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); +#ifdef CONFIG_DPP3 + i_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); + if (i_proto && !auth->waiting_new_key) { + dpp_auth_fail(auth, + "Enrollee included a new protocol key even though one was not expected"); + goto fail; + } + if (i_proto) { + struct crypto_ec_key *pe; + u8 auth_i[DPP_MAX_HASH_LEN]; + const u8 *rx_auth_i; + u16 rx_auth_i_len; + + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)", + i_proto, i_proto_len); + + pe = dpp_set_pubkey_point(auth->own_protocol_key, + i_proto, i_proto_len); + if (!pe) { + dpp_auth_fail(auth, + "Invalid Initiator Protocol Key (Pe)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pe)", pe); + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pe; + auth->new_key_received = true; + auth->waiting_new_key = false; + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + + rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len); + if (!rx_auth_i) { + dpp_auth_fail(auth, + "Missing Initiator Authentication Tag"); + goto fail; + } + if (rx_auth_i_len != auth->new_curve->hash_len || + os_memcmp(rx_auth_i, auth_i, + auth->new_curve->hash_len) != 0) { + dpp_auth_fail(auth, + "Mismatch in Initiator Authenticating Tag"); + wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I", + rx_auth_i, rx_auth_i_len); + wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'", + auth_i, auth->new_curve->hash_len); + goto fail; + } + } +#endif /* CONFIG_DPP3 */ + config_attr = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_ATTR_OBJ, &config_attr_len); @@ -2983,6 +3151,72 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, goto fail; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) { + const u8 *fcgroup, *r_proto; + u16 fcgroup_len, r_proto_len; + u16 group; + const struct dpp_curve_params *curve; + struct crypto_ec_key *new_pe; + struct crypto_ec_key *pc; + + fcgroup = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_FINITE_CYCLIC_GROUP, + &fcgroup_len); + if (!fcgroup || fcgroup_len != 2) { + dpp_auth_fail(auth, + "Missing or invalid required Finite Cyclic Group attribute"); + goto fail; + } + group = WPA_GET_LE16(fcgroup); + + wpa_printf(MSG_DEBUG, + "DPP: Configurator requested a new protocol key from group %u", + group); + curve = dpp_get_curve_ike_group(group); + if (!curve) { + dpp_auth_fail(auth, + "Unsupported group for new protocol key"); + goto fail; + } + + new_pe = dpp_gen_keypair(curve); + if (!new_pe) { + dpp_auth_fail(auth, + "Failed to generate a new protocol key"); + goto fail; + } + + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pe; + auth->new_curve = curve; + + r_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_R_PROTOCOL_KEY, + &r_proto_len); + if (!r_proto) { + dpp_auth_fail(auth, + "Missing required Responder Protocol Key attribute (Pc)"); + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)", + r_proto, r_proto_len); + + pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len); + if (!pc) { + dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pc)", pc); + + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pc; + + auth->waiting_new_key = true; + ret = -3; + goto fail; + } +#endif /* CONFIG_DPP3 */ if (status[0] != DPP_STATUS_OK) { dpp_auth_fail(auth, "Configurator rejected configuration"); goto fail; @@ -4204,12 +4438,25 @@ static unsigned int dpp_next_configurator_id(struct dpp_global *dpp) int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) { - char *curve = NULL; + char *curve; char *key = NULL, *ppkey = NULL; u8 *privkey = NULL, *pp_key = NULL; size_t privkey_len = 0, pp_key_len = 0; int ret = -1; struct dpp_configurator *conf = NULL; + const struct dpp_curve_params *net_access_key_curve = NULL; + + curve = get_param(cmd, " net_access_key_curve="); + if (curve) { + net_access_key_curve = dpp_get_curve_name(curve); + if (!net_access_key_curve) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported net_access_key_curve: %s", + curve); + goto fail; + } + os_free(curve); + } curve = get_param(cmd, " curve="); key = get_param(cmd, " key="); @@ -4236,6 +4483,7 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) if (!conf) goto fail; + conf->net_access_key_curve = net_access_key_curve; conf->id = dpp_next_configurator_id(dpp); dl_list_add(&dpp->configurator, &conf->list); ret = conf->id; diff --git a/src/common/dpp.h b/src/common/dpp.h index 7f6513ff3..3aca92f7f 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -110,6 +110,7 @@ enum dpp_status_error { DPP_STATUS_CONFIGURE_PENDING = 11, DPP_STATUS_CSR_NEEDED = 12, DPP_STATUS_CSR_BAD = 13, + DPP_STATUS_NEW_KEY_NEEDED = 14, }; /* DPP Reconfig Flags object - connectorKey values */ @@ -258,6 +259,7 @@ struct dpp_authentication { void *msg_ctx; u8 peer_version; const struct dpp_curve_params *curve; + const struct dpp_curve_params *new_curve; struct dpp_bootstrap_info *peer_bi; struct dpp_bootstrap_info *own_bi; struct dpp_bootstrap_info *tmp_own_bi; @@ -358,6 +360,8 @@ struct dpp_authentication { char *trusted_eap_server_name; struct wpabuf *cacert; struct wpabuf *certbag; + bool waiting_new_key; + bool new_key_received; void *config_resp_ctx; void *gas_server_ctx; bool use_config_query; @@ -381,6 +385,7 @@ struct dpp_configurator { u8 kid_hash[SHA256_MAC_LEN]; char *kid; const struct dpp_curve_params *curve; + const struct dpp_curve_params *net_access_key_curve; char *connector; /* own Connector for reconfiguration */ struct crypto_ec_key *connector_key; struct crypto_ec_key *pp_key; diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c index 300416fb1..874dd5910 100644 --- a/src/common/dpp_crypto.c +++ b/src/common/dpp_crypto.c @@ -2355,6 +2355,100 @@ fail: #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i) +{ + int ret = -1, res; + u8 Sx[DPP_MAX_SHARED_SECRET_LEN]; + size_t Sx_len; + unsigned int hash_len; + const char *info = "New DPP Protocol Key"; + const u8 *addr[4]; + size_t len[4]; + u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN]; + struct wpabuf *pcx = NULL, *pex = NULL; + + if (!auth->new_curve) + return -1; + + hash_len = auth->new_curve->hash_len; + + /* + * Configurator: S = pc * Pe + * Enrollee: S = pe * Pc + * k = HKDF(bk, "New DPP Protocol Key", S.x) + * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key", + * len(new-curve-hash-out)) + * Auth-I = H(k, E-nonce | Pc.x | Pe.x) + * Note: Assume this H(k, ..) is actually H(k | ..) + * + * auth->own_protocol_key, auth->peer_protocol_key, and auth->curve have + * already been updated to use the new keys and curve. + */ + + if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key, + Sx, &Sx_len) < 0) + goto fail; + + wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len); + + /* tmp = HKDF-Extract(bk, S.x) */ + addr[0] = Sx; + len[0] = Sx_len; + res = dpp_hmac_vector(hash_len, auth->bk, auth->new_curve->hash_len, + 1, addr, len, tmp); + if (res < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)", + tmp, hash_len); + /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(new-curve-hash-out)) + */ + res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, + "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")", + k, hash_len); + + /* Auth-I = H(k | E-nonce | Pc.x | Pe.x) */ + addr[0] = k; + len[0] = hash_len; + addr[1] = auth->e_nonce; + len[1] = auth->new_curve->nonce_len; + + if (auth->configurator) { + pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + } else { + pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + } + if (!pcx || !pex) + goto fail; + addr[2] = wpabuf_head(pcx); + len[2] = wpabuf_len(pcx) / 2; + addr[3] = wpabuf_head(pex); + len[3] = wpabuf_len(pex) / 2; + + if (dpp_hash_vector(auth->new_curve, 4, addr, len, auth_i) < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: Auth-I = H(k | E-nonce | Pc.x | Pe.x)", + auth_i, hash_len); + ret = 0; +fail: + forced_memzero(Sx, sizeof(Sx)); + forced_memzero(tmp, sizeof(tmp)); + forced_memzero(k, sizeof(k)); + wpabuf_free(pcx); + wpabuf_free(pex); + return ret; +} +#endif /* CONFIG_DPP3 */ + + #ifdef CONFIG_TESTING_OPTIONS int dpp_test_gen_invalid_key(struct wpabuf *msg, diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index 0f31ae56a..10db4e818 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -136,6 +136,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth, struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey, struct crypto_ec_key *a_nonce, struct crypto_ec_key *e_prime_id); +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i); char * dpp_sign_connector(struct dpp_configurator *conf, const struct wpabuf *dppcon); int dpp_test_gen_invalid_key(struct wpabuf *msg, diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index e88c6de60..811454984 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -89,6 +89,9 @@ static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx); static void dpp_controller_auth_success(struct dpp_connection *conn, int initiator); static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx); +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx); +#endif /* CONFIG_DPP3 */ static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx); static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx); @@ -107,6 +110,9 @@ static void dpp_connection_free(struct dpp_connection *conn) eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL); eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL); +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL); +#endif /* CONFIG_DPP3 */ wpabuf_free(conn->msg); wpabuf_free(conn->msg_out); dpp_auth_deinit(conn->auth); @@ -193,6 +199,14 @@ static void dpp_controller_gas_done(struct dpp_connection *conn) return; } +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + conn->on_tcp_tx_complete_gas_done = 0; + return; + } +#endif /* CONFIG_DPP3 */ + if (auth->peer_version >= 2 && auth->conf_resp_status == DPP_STATUS_OK) { wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); @@ -1440,6 +1454,21 @@ static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx) } +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct dpp_connection *conn = eloop_ctx; + struct dpp_authentication *auth = conn->auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + dpp_controller_start_gas_client(conn); +} +#endif /* CONFIG_DPP3 */ + + static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) { struct dpp_authentication *auth = conn->auth; @@ -1460,6 +1489,14 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL); return 0; } +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn, + NULL); + return 0; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); return -1; diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 380354294..e373aeea3 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1656,6 +1656,21 @@ static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 +static void wpas_dpp_build_new_key(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_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + wpas_dpp_start_gas_client(wpa_s); +} +#endif /* CONFIG_DPP3 */ + + static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, @@ -1709,6 +1724,14 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, return; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, wpas_dpp_build_new_key, wpa_s, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; @@ -3356,6 +3379,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + wpabuf_free(resp); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); @@ -3809,6 +3840,9 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) dpp_free_reconfig_id(wpa_s->dpp_reconfig_id); wpa_s->dpp_reconfig_id = NULL; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(wpas_dpp_build_new_key, wpa_s, NULL); +#endif /* CONFIG_DPP3 */ offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); wpas_dpp_stop(wpa_s);