From: Jouni Malinen Date: Mon, 24 Jan 2022 22:35:36 +0000 (+0200) Subject: DPP3: PKEX over TCP X-Git-Tag: hostap_2_11~2279 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7be749335f2585658cf98c4f0e7d6cd5ac06865;p=thirdparty%2Fhostap.git DPP3: PKEX over TCP Signed-off-by: Jouni Malinen --- diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index fdfdcf9ae..d956be928 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -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 */ diff --git a/src/common/dpp.h b/src/common/dpp.h index bfea44623..ca33fe35c 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -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, diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c index 38349fa3f..72084d9fb 100644 --- a/src/common/dpp_pkex.c +++ b/src/common/dpp_pkex.c @@ -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; diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c index fb8ef1c5b..1a8a7c7d5 100644 --- a/src/common/dpp_tcp.c +++ b/src/common/dpp_tcp.c @@ -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; diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 61b300f9f..aab94cbf4 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -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 */