DPP3: PKEX over TCP

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2022-01-25 00:35:36 +02:00 committed by Jouni Malinen
parent 008e177597
commit d7be749335
5 changed files with 580 additions and 36 deletions

View 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 */

View 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,

View 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;

View 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;

View 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 */