{
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");
/* { 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
}
#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);
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;
}
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;
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) {
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
#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;
}
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;
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:
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
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) {
wpabuf_clear_free(conf2);
wpabuf_clear_free(env_data);
wpabuf_clear_free(clear);
+ wpabuf_free(pc);
return msg;
fail:
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) {
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);
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;
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=");
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;
#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,