]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Curve change for netAccessKey
authorJouni Malinen <quic_jouni@quicinc.com>
Tue, 8 Mar 2022 23:06:01 +0000 (01:06 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 8 Mar 2022 23:07:59 +0000 (01:07 +0200)
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>
src/ap/dpp_hostapd.c
src/common/dpp.c
src/common/dpp.h
src/common/dpp_crypto.c
src/common/dpp_i.h
src/common/dpp_tcp.c
wpa_supplicant/dpp_supplicant.c

index 74d7a59234970a7010431a6797785c0d5d57ad62..d4cbed88ddf6ccb521c297657a97f5b548768cc0 100644 (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 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, "*");
index 879f9a8c03739deaf67a22c68265887cf65cb79f..4118a05f53962d3ca6fe00e03cbb81021560fade 100644 (file)
@@ -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;
index 7f6513ff3507ca47e663d7986f0dbefb1c7dc32b..3aca92f7f818eb6cb2e1aa80ca66e243322ae284 100644 (file)
@@ -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;
index 300416fb12ecced6199822c0fb3a06c3ae947a4e..874dd591098c66c677776a57e43cafc8c2f11c14 100644 (file)
@@ -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,
index 0f31ae56a5261ad604675fe6e89335e9206fabce..10db4e818491aec55ffc5341d185733b01980360 100644 (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_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,
index e88c6de6033bac1c0414c7080b5b4f7ec121754a..81145498432203821165f97c1a720720c216f06c 100644 (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,
                                        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;
index 380354294a8b1d9489304afc71d25662add11324..e373aeea3f6e562d4b0a3b4af6bded4208f7721a 100644 (file)
@@ -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);