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 <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-03-09 01:06:01 +02:00 committed by Jouni Malinen
parent fd2eb7a41e
commit de64dfe98e
7 changed files with 466 additions and 11 deletions

View file

@ -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 int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth); struct dpp_authentication *auth);
static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd);
#ifdef CONFIG_DPP2 #ifdef CONFIG_DPP2
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx, static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_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, static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result, enum gas_query_ap_result result,
const struct wpabuf *adv_proto, 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; const u8 *pos;
struct dpp_authentication *auth = hapd->dpp_auth; struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
int res;
if (!auth || !auth->auth_success) { if (!auth || !auth->auth_success) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); 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; 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"); wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail; goto fail;
} }
@ -2354,6 +2380,13 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
if (!auth) if (!auth)
return; 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)", wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok); ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); 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) if (hapd->iface->interfaces)
dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd); dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
#endif /* CONFIG_DPP2 */ #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); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; hapd->dpp_auth = NULL;
hostapd_dpp_pkex_remove(hapd, "*"); hostapd_dpp_pkex_remove(hapd, "*");

View file

@ -658,9 +658,12 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
{ {
size_t nonce_len; size_t nonce_len;
size_t json_len, clear_len; size_t json_len, clear_len;
struct wpabuf *clear = NULL, *msg = NULL; struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
u8 *wrapped; u8 *wrapped;
size_t attr_len; 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"); 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 */ /* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len; 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); clear = wpabuf_alloc(clear_len);
attr_len = 4 + clear_len + AES_BLOCK_SIZE; attr_len = 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
@ -716,6 +731,21 @@ skip_e_nonce:
} }
#endif /* CONFIG_TESTING_OPTIONS */ #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 */ /* configAttrib */
wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
wpabuf_put_le16(clear, json_len); wpabuf_put_le16(clear, json_len);
@ -748,13 +778,15 @@ skip_wrapped_data:
wpa_hexdump_buf(MSG_DEBUG, wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Request frame attributes", msg); "DPP: Configuration Request frame attributes", msg);
out:
wpabuf_free(clear); wpabuf_free(clear);
wpabuf_free(pe);
return msg; return msg;
fail: fail:
wpabuf_free(clear);
wpabuf_free(msg); 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; struct wpabuf *buf = NULL;
char *signed_conn = NULL; char *signed_conn = NULL;
size_t tailroom; 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; struct wpabuf *dppcon = NULL;
size_t extra_len = 1000; size_t extra_len = 1000;
int incl_legacy; int incl_legacy;
@ -1443,6 +1476,10 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
goto fail; goto fail;
} }
curve = auth->conf->curve; 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; akm = conf->akm;
if (dpp_akm_ver2(akm) && auth->peer_version < 2) { 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); extra_len += os_strlen(conf->group_id);
/* Connector (JSON dppCon object) */ /* 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) if (!dppcon)
goto fail; goto fail;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
@ -1490,9 +1527,31 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
skip_groups: skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_TESTING_OPTIONS */
if (!auth->peer_protocol_key || if (!auth->peer_protocol_key) {
dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, wpa_printf(MSG_DEBUG,
auth->curve) < 0) { "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"); wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail; goto fail;
} }
@ -1731,7 +1790,7 @@ struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req) 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; size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL; struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped; 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 && else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr) auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
status = DPP_STATUS_CSR_NEEDED; status = DPP_STATUS_CSR_NEEDED;
#ifdef CONFIG_DPP3
else if (auth->waiting_new_key)
status = DPP_STATUS_NEW_KEY_NEEDED;
#endif /* CONFIG_DPP3 */
else else
status = DPP_STATUS_CONFIGURE_FAILURE; status = DPP_STATUS_CONFIGURE_FAILURE;
forced_status: forced_status:
@ -1784,6 +1847,31 @@ forced_status:
if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
auth->conf_sta->csrattrs) auth->conf_sta->csrattrs)
clear_len += 4 + os_strlen(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); clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
@ -1861,6 +1949,27 @@ skip_e_nonce:
wpabuf_put_str(clear, auth->conf_sta->csrattrs); 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 #ifdef CONFIG_TESTING_OPTIONS
skip_config_obj: skip_config_obj:
if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
@ -1911,6 +2020,7 @@ out:
wpabuf_clear_free(conf2); wpabuf_clear_free(conf2);
wpabuf_clear_free(env_data); wpabuf_clear_free(env_data);
wpabuf_clear_free(clear); wpabuf_clear_free(clear);
wpabuf_free(pc);
return msg; return msg;
fail: fail:
@ -1932,6 +2042,10 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
struct json_token *root = NULL, *token; struct json_token *root = NULL, *token;
enum dpp_netrole netrole; enum dpp_netrole netrole;
struct wpabuf *cert_req = NULL; struct wpabuf *cert_req = NULL;
#ifdef CONFIG_DPP3
const u8 *i_proto;
u16 i_proto_len;
#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { 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); wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
os_memcpy(auth->e_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, config_attr = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_ATTR_OBJ, DPP_ATTR_CONFIG_ATTR_OBJ,
&config_attr_len); &config_attr_len);
@ -2983,6 +3151,72 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
goto fail; goto fail;
} }
#endif /* CONFIG_DPP2 */ #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) { if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration"); dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail; 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) int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{ {
char *curve = NULL; char *curve;
char *key = NULL, *ppkey = NULL; char *key = NULL, *ppkey = NULL;
u8 *privkey = NULL, *pp_key = NULL; u8 *privkey = NULL, *pp_key = NULL;
size_t privkey_len = 0, pp_key_len = 0; size_t privkey_len = 0, pp_key_len = 0;
int ret = -1; int ret = -1;
struct dpp_configurator *conf = NULL; 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="); curve = get_param(cmd, " curve=");
key = get_param(cmd, " key="); key = get_param(cmd, " key=");
@ -4236,6 +4483,7 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
if (!conf) if (!conf)
goto fail; goto fail;
conf->net_access_key_curve = net_access_key_curve;
conf->id = dpp_next_configurator_id(dpp); conf->id = dpp_next_configurator_id(dpp);
dl_list_add(&dpp->configurator, &conf->list); dl_list_add(&dpp->configurator, &conf->list);
ret = conf->id; ret = conf->id;

View file

@ -110,6 +110,7 @@ enum dpp_status_error {
DPP_STATUS_CONFIGURE_PENDING = 11, DPP_STATUS_CONFIGURE_PENDING = 11,
DPP_STATUS_CSR_NEEDED = 12, DPP_STATUS_CSR_NEEDED = 12,
DPP_STATUS_CSR_BAD = 13, DPP_STATUS_CSR_BAD = 13,
DPP_STATUS_NEW_KEY_NEEDED = 14,
}; };
/* DPP Reconfig Flags object - connectorKey values */ /* DPP Reconfig Flags object - connectorKey values */
@ -258,6 +259,7 @@ struct dpp_authentication {
void *msg_ctx; void *msg_ctx;
u8 peer_version; u8 peer_version;
const struct dpp_curve_params *curve; const struct dpp_curve_params *curve;
const struct dpp_curve_params *new_curve;
struct dpp_bootstrap_info *peer_bi; struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi; struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi; struct dpp_bootstrap_info *tmp_own_bi;
@ -358,6 +360,8 @@ struct dpp_authentication {
char *trusted_eap_server_name; char *trusted_eap_server_name;
struct wpabuf *cacert; struct wpabuf *cacert;
struct wpabuf *certbag; struct wpabuf *certbag;
bool waiting_new_key;
bool new_key_received;
void *config_resp_ctx; void *config_resp_ctx;
void *gas_server_ctx; void *gas_server_ctx;
bool use_config_query; bool use_config_query;
@ -381,6 +385,7 @@ struct dpp_configurator {
u8 kid_hash[SHA256_MAC_LEN]; u8 kid_hash[SHA256_MAC_LEN];
char *kid; char *kid;
const struct dpp_curve_params *curve; const struct dpp_curve_params *curve;
const struct dpp_curve_params *net_access_key_curve;
char *connector; /* own Connector for reconfiguration */ char *connector; /* own Connector for reconfiguration */
struct crypto_ec_key *connector_key; struct crypto_ec_key *connector_key;
struct crypto_ec_key *pp_key; struct crypto_ec_key *pp_key;

View file

@ -2355,6 +2355,100 @@ fail:
#endif /* CONFIG_DPP2 */ #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 #ifdef CONFIG_TESTING_OPTIONS
int dpp_test_gen_invalid_key(struct wpabuf *msg, int dpp_test_gen_invalid_key(struct wpabuf *msg,

View file

@ -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_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
struct crypto_ec_key *a_nonce, struct crypto_ec_key *a_nonce,
struct crypto_ec_key *e_prime_id); 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, char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon); const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg, int dpp_test_gen_invalid_key(struct wpabuf *msg,

View file

@ -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, static void dpp_controller_auth_success(struct dpp_connection *conn,
int initiator); int initiator);
static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx); 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_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
static void dpp_relay_conn_timeout(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_build_csr, conn, NULL);
eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
eloop_cancel_timeout(dpp_relay_conn_timeout, 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);
wpabuf_free(conn->msg_out); wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth); dpp_auth_deinit(conn->auth);
@ -193,6 +199,14 @@ static void dpp_controller_gas_done(struct dpp_connection *conn)
return; 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 && if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) { auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); 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) static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
{ {
struct dpp_authentication *auth = conn->auth; 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); eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
return 0; 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) { if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
return -1; return -1;

View file

@ -1656,6 +1656,21 @@ static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
#endif /* CONFIG_DPP2 */ #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, static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_result result, enum gas_query_result result,
const struct wpabuf *adv_proto, 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; return;
} }
#endif /* CONFIG_DPP2 */ #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) { if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail; goto fail;
@ -3356,6 +3379,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
} }
#endif /* CONFIG_DPP2 */ #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)", wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok); ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); 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); dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
wpa_s->dpp_reconfig_id = NULL; wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */ #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); offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s); wpas_dpp_listen_stop(wpa_s);
wpas_dpp_stop(wpa_s); wpas_dpp_stop(wpa_s);