DPP3: PKEX over TCP
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
008e177597
commit
d7be749335
5 changed files with 580 additions and 36 deletions
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue