]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP3: PKEX over TCP
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 24 Jan 2022 22:35:36 +0000 (00:35 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Jan 2022 22:40:09 +0000 (00:40 +0200)
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/ap/dpp_hostapd.c
src/common/dpp.h
src/common/dpp_pkex.c
src/common/dpp_tcp.c
wpa_supplicant/dpp_supplicant.c

index fdfdcf9ae88cb6a06400ae6aaeba5740922418b3..d956be92809f97d012df61523167cb050f0240d0 100644 (file)
@@ -28,12 +28,16 @@ static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
 static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
 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);
 #ifdef CONFIG_DPP2
 static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
                                                    void *timeout_ctx);
 static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
                                          struct dpp_authentication *auth,
                                          struct dpp_config_obj *conf);
+static int hostapd_dpp_process_conf_obj(void *ctx,
+                                       struct dpp_authentication *auth);
 #endif /* CONFIG_DPP2 */
 
 static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -272,6 +276,75 @@ static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
 }
 
 
+#ifdef CONFIG_DPP2
+static int hostapd_dpp_pkex_done(void *ctx, void *conn,
+                                struct dpp_bootstrap_info *peer_bi)
+{
+       struct hostapd_data *hapd = ctx;
+       const char *cmd = hapd->dpp_pkex_auth_cmd;
+       const char *pos;
+       u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+       struct dpp_bootstrap_info *own_bi = NULL;
+       struct dpp_authentication *auth;
+
+       if (!cmd)
+               cmd = "";
+       wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
+                  cmd);
+
+       pos = os_strstr(cmd, " own=");
+       if (pos) {
+               pos += 5;
+               own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
+                                             atoi(pos));
+               if (!own_bi) {
+                       wpa_printf(MSG_INFO,
+                                  "DPP: Could not find bootstrapping info for the identified local entry");
+                       return -1;
+               }
+
+               if (peer_bi->curve != own_bi->curve) {
+                       wpa_printf(MSG_INFO,
+                                  "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
+                                  peer_bi->curve->name, own_bi->curve->name);
+                       return -1;
+               }
+       }
+
+       pos = os_strstr(cmd, " role=");
+       if (pos) {
+               pos += 6;
+               if (os_strncmp(pos, "configurator", 12) == 0)
+                       allowed_roles = DPP_CAPAB_CONFIGURATOR;
+               else if (os_strncmp(pos, "enrollee", 8) == 0)
+                       allowed_roles = DPP_CAPAB_ENROLLEE;
+               else if (os_strncmp(pos, "either", 6) == 0)
+                       allowed_roles = DPP_CAPAB_CONFIGURATOR |
+                               DPP_CAPAB_ENROLLEE;
+               else
+                       return -1;
+       }
+
+       auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
+                            peer_bi, own_bi, allowed_roles, 0,
+                            hapd->iface->hw_features,
+                            hapd->iface->num_hw_features);
+       if (!auth)
+               return -1;
+
+       hostapd_dpp_set_testing_options(hapd, auth);
+       if (dpp_set_configurator(auth, cmd) < 0) {
+               dpp_auth_deinit(auth);
+               return -1;
+       }
+
+       return dpp_tcp_auth(hapd->iface->interfaces->dpp, conn, auth,
+                           hapd->conf->dpp_name, DPP_NETROLE_AP,
+                           hostapd_dpp_process_conf_obj);
+}
+#endif /* CONFIG_DPP2 */
+
+
 enum hostapd_dpp_pkex_ver {
        PKEX_VER_AUTO,
        PKEX_VER_ONLY_1,
@@ -279,7 +352,9 @@ enum hostapd_dpp_pkex_ver {
 };
 
 static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
-                                enum hostapd_dpp_pkex_ver ver)
+                                enum hostapd_dpp_pkex_ver ver,
+                                const struct hostapd_ip_addr *ipaddr,
+                                int tcp_port)
 {
        struct dpp_pkex *pkex;
        struct wpabuf *msg;
@@ -288,15 +363,26 @@ static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
 
        wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
        dpp_pkex_free(hapd->dpp_pkex);
-       hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi,
-                                      hapd->own_addr,
-                                      hapd->dpp_pkex_identifier,
-                                      hapd->dpp_pkex_code, v2);
-       pkex = hapd->dpp_pkex;
+       hapd->dpp_pkex = NULL;
+       pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
+                            hapd->dpp_pkex_identifier,
+                            hapd->dpp_pkex_code, v2);
        if (!pkex)
                return -1;
        pkex->forced_ver = ver != PKEX_VER_AUTO;
 
+       if (ipaddr) {
+#ifdef CONFIG_DPP2
+               return dpp_tcp_pkex_init(hapd->iface->interfaces->dpp, pkex,
+                                        ipaddr, tcp_port,
+                                        hapd->msg_ctx, hapd,
+                                        hostapd_dpp_pkex_done);
+#else /* CONFIG_DPP2 */
+               return -1;
+#endif /* CONFIG_DPP2 */
+       }
+
+       hapd->dpp_pkex = pkex;
        msg = hapd->dpp_pkex->exchange_req;
        wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
        pkex->freq = 2437;
@@ -326,7 +412,8 @@ static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
                        if (pkex->v2 && !pkex->forced_ver) {
                                wpa_printf(MSG_DEBUG,
                                           "DPP: Fall back to PKEXv1");
-                               hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1);
+                               hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1,
+                                                     NULL, 0);
                                return;
                        }
 #endif /* CONFIG_DPP3 */
@@ -1883,7 +1970,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 
 static void
 hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
-                                const u8 *buf, size_t len,
+                                const u8 *hdr, const u8 *buf, size_t len,
                                 unsigned int freq, bool v2)
 {
        struct wpabuf *msg;
@@ -1897,14 +1984,14 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
        if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
                wpa_printf(MSG_DEBUG,
                           "DPP: No PKEX code configured - ignore request");
-               return;
+               goto try_relay;
        }
 
        if (hapd->dpp_pkex) {
                /* TODO: Support parallel operations */
                wpa_printf(MSG_DEBUG,
                           "DPP: Already in PKEX session - ignore new request");
-               return;
+               goto try_relay;
        }
 
        hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
@@ -1916,7 +2003,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
        if (!hapd->dpp_pkex) {
                wpa_printf(MSG_DEBUG,
                           "DPP: Failed to process the request - ignore it");
-               return;
+               goto try_relay;
        }
 
        msg = hapd->dpp_pkex->exchange_resp;
@@ -1933,6 +2020,17 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
                dpp_pkex_free(hapd->dpp_pkex);
                hapd->dpp_pkex = NULL;
        }
+
+       return;
+
+try_relay:
+#ifdef CONFIG_DPP2
+       if (v2)
+               dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+                                   src, hdr, buf, len, freq, NULL, NULL, hapd);
+#else /* CONFIG_DPP2 */
+       wpa_printf(MSG_DEBUG, "DPP: No relay functionality included - skip");
+#endif /* CONFIG_DPP2 */
 }
 
 
@@ -2132,12 +2230,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
                /* This is for PKEXv2, but for now, process only with
                 * CONFIG_DPP3 to avoid issues with a capability that has not
                 * been tested with other implementations. */
-               hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+               hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq,
                                                 true);
                break;
 #endif /* CONFIG_DPP3 */
        case DPP_PA_PKEX_V1_EXCHANGE_REQ:
-               hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+               hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq,
                                                 false);
                break;
        case DPP_PA_PKEX_EXCHANGE_RESP:
@@ -2303,6 +2401,29 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
 {
        struct dpp_bootstrap_info *own_bi;
        const char *pos, *end;
+       int tcp_port = DPP_TCP_PORT;
+       struct hostapd_ip_addr *ipaddr = NULL;
+#ifdef CONFIG_DPP2
+       struct hostapd_ip_addr ipaddr_buf;
+       char *addr;
+
+       pos = os_strstr(cmd, " tcp_port=");
+       if (pos) {
+               pos += 10;
+               tcp_port = atoi(pos);
+       }
+
+       addr = get_param(cmd, " tcp_addr=");
+       if (addr) {
+               int res;
+
+               res = hostapd_parse_ip_addr(addr, &ipaddr_buf);
+               os_free(addr);
+               if (res)
+                       return -1;
+               ipaddr = &ipaddr_buf;
+       }
+#endif /* CONFIG_DPP2 */
 
        pos = os_strstr(cmd, " own=");
        if (!pos)
@@ -2366,8 +2487,14 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
                                return -1;
                }
 
-               if (hostapd_dpp_pkex_init(hapd, ver) < 0)
+               if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0)
                        return -1;
+       } else {
+#ifdef CONFIG_DPP2
+               dpp_controller_pkex_add(hapd->iface->interfaces->dpp, own_bi,
+                                       hapd->dpp_pkex_code,
+                                       hapd->dpp_pkex_identifier);
+#endif /* CONFIG_DPP2 */
        }
 
        /* TODO: Support multiple PKEX info entries */
index bfea446233d3cb94035b1112d59e25b0f0889e6b..ca33fe35cd36e0b4ff8fe8a0e0a3d5da33d071f4 100644 (file)
@@ -550,6 +550,9 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
                     const u8 *attr_start, size_t attr_len);
 int dpp_notify_new_qr_code(struct dpp_authentication *auth,
                           struct dpp_bootstrap_info *peer_bi);
+void dpp_controller_pkex_add(struct dpp_global *dpp,
+                            struct dpp_bootstrap_info *bi,
+                            const char *code, const char *identifier);
 struct dpp_configuration * dpp_configuration_alloc(const char *type);
 int dpp_akm_psk(enum dpp_akm akm);
 int dpp_akm_sae(enum dpp_akm akm);
@@ -688,12 +691,22 @@ struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
                                                    unsigned int id);
 void dpp_controller_new_qr_code(struct dpp_global *dpp,
                                struct dpp_bootstrap_info *bi);
+int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex,
+                     const struct hostapd_ip_addr *addr, int port,
+                     void *msg_ctx, void *cb_ctx,
+                     int (*pkex_done)(void *ctx, void *conn,
+                                      struct dpp_bootstrap_info *bi));
 int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
                 const struct hostapd_ip_addr *addr, int port,
                 const char *name, enum dpp_netrole netrole, void *msg_ctx,
                 void *cb_ctx,
                 int (*process_conf_obj)(void *ctx,
                                         struct dpp_authentication *auth));
+int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
+                struct dpp_authentication *auth, const char *name,
+                enum dpp_netrole netrole,
+                int (*process_conf_obj)(void *ctx,
+                                        struct dpp_authentication *auth));
 
 struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
 void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
index 38349fa3f540eb16c749143ebf04586109ee31b5..72084d9fbc6dae5becad86b76bd375f76214fed2 100644 (file)
@@ -469,8 +469,10 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        pkex->t = bi->pkex_t;
        pkex->msg_ctx = msg_ctx;
        pkex->own_bi = bi;
-       os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
-       os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+       if (own_mac)
+               os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+       if (peer_mac)
+               os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
        if (identifier) {
                pkex->identifier = os_strdup(identifier);
                if (!pkex->identifier)
@@ -742,7 +744,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        }
 #endif /* CONFIG_DPP2 */
 
-       os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+       if (peer_mac)
+               os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
 
        attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
                                   &attr_status_len);
@@ -1341,9 +1344,12 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
                return NULL;
        bi->id = dpp_next_id(dpp);
        bi->type = DPP_BOOTSTRAP_PKEX;
-       os_memcpy(bi->mac_addr, peer, ETH_ALEN);
-       bi->num_freq = 1;
-       bi->freq[0] = freq;
+       if (peer)
+               os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+       if (freq) {
+               bi->num_freq = 1;
+               bi->freq[0] = freq;
+       }
        bi->curve = pkex->own_bi->curve;
        bi->pubkey = pkex->peer_bootstrap_key;
        pkex->peer_bootstrap_key = NULL;
index fb8ef1c5bfaf1bbac3eb4eafb7f2be38c12cb6e1..1a8a7c7d5677e863710cde287b0fbac9c1c5da2f 100644 (file)
@@ -24,10 +24,12 @@ struct dpp_connection {
        struct dpp_controller *ctrl;
        struct dpp_relay_controller *relay;
        struct dpp_global *global;
+       struct dpp_pkex *pkex;
        struct dpp_authentication *auth;
        void *msg_ctx;
        void *cb_ctx;
        int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+       int (*pkex_done)(void *ctx, void *conn, struct dpp_bootstrap_info *bi);
        int sock;
        u8 mac_addr[ETH_ALEN];
        unsigned int freq;
@@ -71,6 +73,9 @@ struct dpp_controller {
        struct dl_list conn; /* struct dpp_connection */
        char *configurator_params;
        enum dpp_netrole netrole;
+       struct dpp_bootstrap_info *pkex_bi;
+       char *pkex_code;
+       char *pkex_identifier;
        void *msg_ctx;
        void *cb_ctx;
        int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
@@ -102,6 +107,7 @@ static void dpp_connection_free(struct dpp_connection *conn)
        wpabuf_free(conn->msg);
        wpabuf_free(conn->msg_out);
        dpp_auth_deinit(conn->auth);
+       dpp_pkex_free(conn->pkex);
        os_free(conn->name);
        os_free(conn);
 }
@@ -525,6 +531,8 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
                /* TODO: Could send this to all configured Controllers. For now,
                 * only the first Controller is supported. */
                ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx);
+       } else if (type == DPP_PA_PKEX_EXCHANGE_REQ) {
+               ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx);
        } else {
                if (!r_bootstrap)
                        return -1;
@@ -609,6 +617,8 @@ static void dpp_controller_free(struct dpp_controller *ctrl)
                eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
        }
        os_free(ctrl->configurator_params);
+       os_free(ctrl->pkex_code);
+       os_free(ctrl->pkex_identifier);
        os_free(ctrl);
 }
 
@@ -955,6 +965,143 @@ static int dpp_controller_rx_reconfig_auth_resp(struct dpp_connection *conn,
 }
 
 
+static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn,
+                                              const u8 *hdr, const u8 *buf,
+                                              size_t len)
+{
+       struct dpp_controller *ctrl = conn->ctrl;
+
+       if (!ctrl)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request");
+
+       /* TODO: Support multiple PKEX codes by iterating over all the enabled
+        * values here */
+
+       if (!ctrl->pkex_code || !ctrl->pkex_bi) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: No PKEX code configured - ignore request");
+               return 0;
+       }
+
+       if (conn->pkex || conn->auth) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Already in PKEX/Authentication session - ignore new PKEX request");
+               return 0;
+       }
+
+       conn->pkex = dpp_pkex_rx_exchange_req(conn->ctrl->global, ctrl->pkex_bi,
+                                             NULL, NULL,
+                                             ctrl->pkex_identifier,
+                                             ctrl->pkex_code,
+                                             buf, len, true);
+       if (!conn->pkex) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Failed to process the request");
+               return -1;
+       }
+
+       return dpp_tcp_send_msg(conn, conn->pkex->exchange_resp);
+}
+
+
+static int dpp_controller_rx_pkex_exchange_resp(struct dpp_connection *conn,
+                                               const u8 *hdr, const u8 *buf,
+                                               size_t len)
+{
+       struct dpp_pkex *pkex = conn->pkex;
+       struct wpabuf *msg;
+       int res;
+
+       wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response");
+
+       if (!pkex || !pkex->initiator || pkex->exchange_done) {
+               wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+               return 0;
+       }
+
+       msg = dpp_pkex_rx_exchange_resp(pkex, NULL, buf, len);
+       if (!msg) {
+               wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request");
+       res = dpp_tcp_send_msg(conn, msg);
+       wpabuf_free(msg);
+       return res;
+}
+
+
+static int dpp_controller_rx_pkex_commit_reveal_req(struct dpp_connection *conn,
+                                                   const u8 *hdr,
+                                                   const u8 *buf, size_t len)
+{
+       struct dpp_pkex *pkex = conn->pkex;
+       struct wpabuf *msg;
+       int res;
+       struct dpp_bootstrap_info *bi;
+
+       wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request");
+
+       if (!pkex || pkex->initiator || !pkex->exchange_done) {
+               wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+               return 0;
+       }
+
+       msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
+       if (!msg) {
+               wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response");
+       res = dpp_tcp_send_msg(conn, msg);
+       wpabuf_free(msg);
+       if (res < 0)
+               return res;
+       bi = dpp_pkex_finish(conn->global, pkex, NULL, 0);
+       if (!bi)
+               return -1;
+       conn->pkex = NULL;
+       return 0;
+}
+
+
+static int
+dpp_controller_rx_pkex_commit_reveal_resp(struct dpp_connection *conn,
+                                         const u8 *hdr,
+                                         const u8 *buf, size_t len)
+{
+       struct dpp_pkex *pkex = conn->pkex;
+       int res;
+       struct dpp_bootstrap_info *bi;
+
+       wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response");
+
+       if (!pkex || !pkex->initiator || !pkex->exchange_done) {
+               wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
+               return 0;
+       }
+
+       res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+               return res;
+       }
+
+       bi = dpp_pkex_finish(conn->global, pkex, NULL, 0);
+       if (!bi)
+               return -1;
+       conn->pkex = NULL;
+
+       if (!conn->pkex_done)
+               return -1;
+       return conn->pkex_done(conn->cb_ctx, conn, bi);
+}
+
+
 static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
                                    size_t len)
 {
@@ -1014,6 +1161,22 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
        case DPP_PA_RECONFIG_AUTH_RESP:
                return dpp_controller_rx_reconfig_auth_resp(conn, msg, pos,
                                                            end - pos);
+       case DPP_PA_PKEX_V1_EXCHANGE_REQ:
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Ignore PKEXv1 Exchange Request - not supported over TCP");
+               return -1;
+       case DPP_PA_PKEX_EXCHANGE_REQ:
+               return dpp_controller_rx_pkex_exchange_req(conn, msg, pos,
+                                                          end - pos);
+       case DPP_PA_PKEX_EXCHANGE_RESP:
+               return dpp_controller_rx_pkex_exchange_resp(conn, msg, pos,
+                                                           end - pos);
+       case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
+               return dpp_controller_rx_pkex_commit_reveal_req(conn, msg, pos,
+                                                               end - pos);
+       case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
+               return dpp_controller_rx_pkex_commit_reveal_resp(conn, msg, pos,
+                                                                end - pos);
        default:
                /* TODO: missing messages types */
                wpa_printf(MSG_DEBUG,
@@ -1559,6 +1722,101 @@ fail:
 }
 
 
+int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex,
+                     const struct hostapd_ip_addr *addr, int port,
+                     void *msg_ctx, void *cb_ctx,
+                     int (*pkex_done)(void *ctx, void *conn,
+                                      struct dpp_bootstrap_info *bi))
+{
+       struct dpp_connection *conn;
+       struct sockaddr_storage saddr;
+       socklen_t addrlen;
+       const u8 *hdr, *pos, *end;
+       char txt[100];
+
+       wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
+                  hostapd_ip_txt(addr, txt, sizeof(txt)), port);
+       if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
+                                  addr, port) < 0) {
+               dpp_pkex_free(pkex);
+               return -1;
+       }
+
+       conn = os_zalloc(sizeof(*conn));
+       if (!conn) {
+               dpp_pkex_free(pkex);
+               return -1;
+       }
+
+       conn->msg_ctx = msg_ctx;
+       conn->cb_ctx = cb_ctx;
+       conn->pkex_done = pkex_done;
+       conn->global = dpp;
+       conn->pkex = pkex;
+       conn->sock = socket(AF_INET, SOCK_STREAM, 0);
+       if (conn->sock < 0)
+               goto fail;
+
+       if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+               wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+                          strerror(errno));
+               goto fail;
+       }
+
+       if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
+               if (errno != EINPROGRESS) {
+                       wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
+                                  strerror(errno));
+                       goto fail;
+               }
+
+               /*
+                * Continue connecting in the background; eloop will call us
+                * once the connection is ready (or failed).
+                */
+       }
+
+       if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
+                               dpp_conn_tx_ready, conn, NULL) < 0)
+               goto fail;
+       conn->write_eloop = 1;
+
+       hdr = wpabuf_head(pkex->exchange_req);
+       end = hdr + wpabuf_len(pkex->exchange_req);
+       hdr += 2; /* skip Category and Actiom */
+       pos = hdr + DPP_HDR_LEN;
+       conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
+       if (!conn->msg_out)
+               goto fail;
+       /* Message will be sent in dpp_conn_tx_ready() */
+
+       /* TODO: eloop timeout to clear a connection if it does not complete
+        * properly */
+       dl_list_add(&dpp->tcp_init, &conn->list);
+       return 0;
+fail:
+       dpp_connection_free(conn);
+       return -1;
+}
+
+
+static int dpp_tcp_auth_start(struct dpp_connection *conn,
+                             struct dpp_authentication *auth)
+{
+       const u8 *hdr, *pos, *end;
+
+       hdr = wpabuf_head(auth->req_msg);
+       end = hdr + wpabuf_len(auth->req_msg);
+       hdr += 2; /* skip Category and Actiom */
+       pos = hdr + DPP_HDR_LEN;
+       conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
+       if (!conn->msg_out)
+               return -1;
+       /* Message will be sent in dpp_conn_tx_ready() */
+       return 0;
+}
+
+
 int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
                 const struct hostapd_ip_addr *addr, int port, const char *name,
                 enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
@@ -1568,7 +1826,6 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
        struct dpp_connection *conn;
        struct sockaddr_storage saddr;
        socklen_t addrlen;
-       const u8 *hdr, *pos, *end;
        char txt[100];
 
        wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
@@ -1620,14 +1877,8 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
                goto fail;
        conn->write_eloop = 1;
 
-       hdr = wpabuf_head(auth->req_msg);
-       end = hdr + wpabuf_len(auth->req_msg);
-       hdr += 2; /* skip Category and Actiom */
-       pos = hdr + DPP_HDR_LEN;
-       conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
-       if (!conn->msg_out)
+       if (dpp_tcp_auth_start(conn, auth) < 0)
                goto fail;
-       /* Message will be sent in dpp_conn_tx_ready() */
 
        /* TODO: eloop timeout to clear a connection if it does not complete
         * properly */
@@ -1639,6 +1890,30 @@ fail:
 }
 
 
+int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
+                struct dpp_authentication *auth, const char *name,
+                enum dpp_netrole netrole,
+                int (*process_conf_obj)(void *ctx,
+                                        struct dpp_authentication *auth))
+{
+       struct dpp_connection *conn = _conn;
+
+       /* Continue with Authentication exchange on an existing TCP connection.
+        */
+       conn->process_conf_obj = process_conf_obj;
+       os_free(conn->name);
+       conn->name = os_strdup(name ? name : "Test");
+       conn->netrole = netrole;
+       conn->auth = auth;
+
+       if (dpp_tcp_auth_start(conn, auth) < 0)
+               return -1;
+
+       dpp_conn_tx_ready(conn->sock, conn, NULL);
+       return 0;
+}
+
+
 int dpp_controller_start(struct dpp_global *dpp,
                         struct dpp_controller_config *config)
 {
@@ -1789,6 +2064,23 @@ void dpp_controller_new_qr_code(struct dpp_global *dpp,
 }
 
 
+void dpp_controller_pkex_add(struct dpp_global *dpp,
+                            struct dpp_bootstrap_info *bi,
+                            const char *code, const char *identifier)
+{
+       struct dpp_controller *ctrl = dpp->controller;
+
+       if (!ctrl)
+               return;
+
+       ctrl->pkex_bi = bi;
+       os_free(ctrl->pkex_code);
+       ctrl->pkex_code = code ? os_strdup(code) : NULL;
+       os_free(ctrl->pkex_identifier);
+       ctrl->pkex_identifier = identifier ? os_strdup(identifier) : NULL;
+}
+
+
 void dpp_tcp_init_flush(struct dpp_global *dpp)
 {
        struct dpp_connection *conn, *tmp;
index 61b300f9f263182b040632f8f5e534c81b9a159b..aab94cbf445ff0c149377ae54a4786e6adcb52bc 100644 (file)
@@ -2557,6 +2557,71 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
 }
 
 
+#ifdef CONFIG_DPP2
+static int wpas_dpp_pkex_done(void *ctx, void *conn,
+                             struct dpp_bootstrap_info *peer_bi)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       const char *cmd = wpa_s->dpp_pkex_auth_cmd;
+       const char *pos;
+       u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
+       struct dpp_bootstrap_info *own_bi = NULL;
+       struct dpp_authentication *auth;
+
+       if (!cmd)
+               cmd = "";
+       wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
+                  cmd);
+
+       pos = os_strstr(cmd, " own=");
+       if (pos) {
+               pos += 5;
+               own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+               if (!own_bi) {
+                       wpa_printf(MSG_INFO,
+                                  "DPP: Could not find bootstrapping info for the identified local entry");
+                       return -1;
+               }
+
+               if (peer_bi->curve != own_bi->curve) {
+                       wpa_printf(MSG_INFO,
+                                  "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
+                                  peer_bi->curve->name, own_bi->curve->name);
+                       return -1;
+               }
+       }
+
+       pos = os_strstr(cmd, " role=");
+       if (pos) {
+               pos += 6;
+               if (os_strncmp(pos, "configurator", 12) == 0)
+                       allowed_roles = DPP_CAPAB_CONFIGURATOR;
+               else if (os_strncmp(pos, "enrollee", 8) == 0)
+                       allowed_roles = DPP_CAPAB_ENROLLEE;
+               else if (os_strncmp(pos, "either", 6) == 0)
+                       allowed_roles = DPP_CAPAB_CONFIGURATOR |
+                               DPP_CAPAB_ENROLLEE;
+               else
+                       return -1;
+       }
+
+       auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+                            0, wpa_s->hw.modes, wpa_s->hw.num_modes);
+       if (!auth)
+               return -1;
+
+       wpas_dpp_set_testing_options(wpa_s, auth);
+       if (dpp_set_configurator(auth, cmd) < 0) {
+               dpp_auth_deinit(auth);
+               return -1;
+       }
+
+       return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name,
+                           DPP_NETROLE_STA, wpas_dpp_process_conf_obj);
+}
+#endif /* CONFIG_DPP2 */
+
+
 enum wpas_dpp_pkex_ver {
        PKEX_VER_AUTO,
        PKEX_VER_ONLY_1,
@@ -2564,7 +2629,9 @@ enum wpas_dpp_pkex_ver {
 };
 
 static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
-                             enum wpas_dpp_pkex_ver ver)
+                             enum wpas_dpp_pkex_ver ver,
+                             const struct hostapd_ip_addr *ipaddr,
+                             int tcp_port)
 {
        struct dpp_pkex *pkex;
        struct wpabuf *msg;
@@ -2573,15 +2640,24 @@ static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
 
        wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
        dpp_pkex_free(wpa_s->dpp_pkex);
-       wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi,
-                                       wpa_s->own_addr,
-                                       wpa_s->dpp_pkex_identifier,
-                                       wpa_s->dpp_pkex_code, v2);
-       pkex = wpa_s->dpp_pkex;
+       wpa_s->dpp_pkex = NULL;
+       pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
+                            wpa_s->dpp_pkex_identifier,
+                            wpa_s->dpp_pkex_code, v2);
        if (!pkex)
                return -1;
        pkex->forced_ver = ver != PKEX_VER_AUTO;
 
+       if (ipaddr) {
+#ifdef CONFIG_DPP2
+               return dpp_tcp_pkex_init(wpa_s->dpp, pkex, ipaddr, tcp_port,
+                                        wpa_s, wpa_s, wpas_dpp_pkex_done);
+#else /* CONFIG_DPP2 */
+               return -1;
+#endif /* CONFIG_DPP2 */
+       }
+
+       wpa_s->dpp_pkex = pkex;
        msg = pkex->exchange_req;
        wait_time = wpa_s->max_remain_on_chan;
        if (wait_time > 2000)
@@ -2618,7 +2694,8 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
                        if (pkex->v2 && !pkex->forced_ver) {
                                wpa_printf(MSG_DEBUG,
                                           "DPP: Fall back to PKEXv1");
-                               wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1);
+                               wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1,
+                                                  NULL, 0);
                                return;
                        }
 #endif /* CONFIG_DPP3 */
@@ -3327,6 +3404,29 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
 {
        struct dpp_bootstrap_info *own_bi;
        const char *pos, *end;
+       int tcp_port = DPP_TCP_PORT;
+       struct hostapd_ip_addr *ipaddr = NULL;
+#ifdef CONFIG_DPP2
+       struct hostapd_ip_addr ipaddr_buf;
+       char *addr;
+
+       pos = os_strstr(cmd, " tcp_port=");
+       if (pos) {
+               pos += 10;
+               tcp_port = atoi(pos);
+       }
+
+       addr = get_param(cmd, " tcp_addr=");
+       if (addr) {
+               int res;
+
+               res = hostapd_parse_ip_addr(addr, &ipaddr_buf);
+               os_free(addr);
+               if (res)
+                       return -1;
+               ipaddr = &ipaddr_buf;
+       }
+#endif /* CONFIG_DPP2 */
 
        pos = os_strstr(cmd, " own=");
        if (!pos)
@@ -3390,8 +3490,14 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
                                return -1;
                }
 
-               if (wpas_dpp_pkex_init(wpa_s, ver) < 0)
+               if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0)
                        return -1;
+       } else {
+#ifdef CONFIG_DPP2
+               dpp_controller_pkex_add(wpa_s->dpp, own_bi,
+                                       wpa_s->dpp_pkex_code,
+                                       wpa_s->dpp_pkex_identifier);
+#endif /* CONFIG_DPP2 */
        }
 
        /* TODO: Support multiple PKEX info entries */