@@ -57,8 +57,6 @@
#define DPP_FRAME_MAX_RETRIES 5
#define DPP_FRAME_RETRY_TIMEOUT 1
-#define DPP_AUTH_PROTO_TIMEOUT 10
-#define DPP_PKEX_PROTO_TIMEOUT 120
static uint32_t netdev_watch;
static struct l_genl_family *nl80211;
@@ -96,7 +94,7 @@ struct pkex_agent {
uint32_t pending_id;
};
-struct dpp_sm {
+struct dpp {
struct netdev *netdev;
char *uri;
uint8_t role;
@@ -106,18 +104,8 @@ struct dpp_sm {
uint64_t wdev_id;
- uint8_t *own_asn1;
- size_t own_asn1_len;
- uint8_t *peer_asn1;
- size_t peer_asn1_len;
- uint8_t own_boot_hash[32];
- uint8_t peer_boot_hash[32];
- const struct l_ecc_curve *curve;
- size_t key_len;
- size_t nonce_len;
struct l_ecc_scalar *boot_private;
struct l_ecc_point *boot_public;
- struct l_ecc_point *peer_boot_public;
enum dpp_state state;
enum dpp_interface interface;
@@ -140,22 +128,6 @@ struct dpp_sm {
uint32_t offchannel_id;
uint8_t peer_addr[6];
- uint8_t r_nonce[32];
- uint8_t i_nonce[32];
- uint8_t e_nonce[32];
-
- struct l_ecc_scalar *m;
- uint64_t ke[L_ECC_MAX_DIGITS];
- uint64_t k1[L_ECC_MAX_DIGITS];
- uint64_t k2[L_ECC_MAX_DIGITS];
- uint64_t auth_tag[L_ECC_MAX_DIGITS];
-
- struct l_ecc_scalar *proto_private;
- struct l_ecc_point *own_proto_public;
-
- struct l_ecc_point *peer_proto_public;
-
- uint8_t diag_token;
/* Timeout of either auth/config protocol */
struct l_timeout *timeout;
@@ -175,24 +147,12 @@ struct dpp_sm {
/* PKEX-specific values */
char *pkex_id;
char *pkex_key;
- uint8_t pkex_version;
- struct l_ecc_point *peer_encr_key;
- struct l_ecc_point *pkex_m;
- /* Ephemeral key Y' or X' for enrollee or configurator */
- struct l_ecc_point *y_or_x;
- /* Ephemeral key pair y/Y or x/X */
- struct l_ecc_point *pkex_public;
- struct l_ecc_scalar *pkex_private;
- uint8_t z[L_ECC_SCALAR_MAX_BYTES];
- size_t z_len;
- uint8_t u[L_ECC_SCALAR_MAX_BYTES];
- size_t u_len;
+
uint32_t pkex_scan_id;
bool mcast_support : 1;
bool roc_started : 1;
bool channel_switch : 1;
- bool mutual_auth : 1;
};
static const char *dpp_role_to_string(enum dpp_capability role)
@@ -212,7 +172,7 @@ static bool dpp_pkex_get_started(struct l_dbus *dbus,
struct l_dbus_message_builder *builder,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
bool started = (dpp->state != DPP_STATE_NOTHING &&
dpp->interface == DPP_INTERFACE_PKEX);
@@ -226,7 +186,7 @@ static bool dpp_pkex_get_role(struct l_dbus *dbus,
struct l_dbus_message_builder *builder,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const char *role;
if (dpp->state == DPP_STATE_NOTHING ||
@@ -246,7 +206,7 @@ static bool dpp_get_started(struct l_dbus *dbus,
struct l_dbus_message_builder *builder,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
bool started = (dpp->state != DPP_STATE_NOTHING &&
dpp->interface == DPP_INTERFACE_DPP);
@@ -260,7 +220,7 @@ static bool dpp_get_role(struct l_dbus *dbus,
struct l_dbus_message_builder *builder,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const char *role;
if (dpp->state == DPP_STATE_NOTHING ||
@@ -280,7 +240,7 @@ static bool dpp_get_uri(struct l_dbus *dbus,
struct l_dbus_message_builder *builder,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
if (dpp->state == DPP_STATE_NOTHING ||
dpp->interface != DPP_INTERFACE_DPP)
@@ -290,7 +250,7 @@ static bool dpp_get_uri(struct l_dbus *dbus,
return true;
}
-static void dpp_property_changed_notify(struct dpp_sm *dpp)
+static void dpp_property_changed_notify(struct dpp *dpp)
{
const char *path = netdev_get_path(dpp->netdev);
@@ -340,26 +300,6 @@ static void *dpp_serialize_iovec(struct iovec *iov, size_t iov_len,
return ret;
}
-static void dpp_free_pending_pkex_data(struct dpp_sm *dpp)
-{
- if (dpp->pkex_id) {
- l_free(dpp->pkex_id);
- dpp->pkex_id = NULL;
- }
-
- if (dpp->pkex_key) {
- l_free(dpp->pkex_key);
- dpp->pkex_key = NULL;
- }
-
- memset(dpp->peer_addr, 0, sizeof(dpp->peer_addr));
-
- if (dpp->peer_encr_key) {
- l_ecc_point_free(dpp->peer_encr_key);
- dpp->peer_encr_key = NULL;
- }
-}
-
static void pkex_agent_free(void *data)
{
struct pkex_agent *agent = data;
@@ -370,7 +310,7 @@ static void pkex_agent_free(void *data)
l_free(agent);
}
-static void dpp_agent_cancel(struct dpp_sm *dpp)
+static void dpp_agent_cancel(struct dpp *dpp)
{
struct l_dbus_message *msg;
@@ -386,7 +326,7 @@ static void dpp_agent_cancel(struct dpp_sm *dpp)
l_dbus_send(dbus_get_bus(), msg);
}
-static void dpp_agent_release(struct dpp_sm *dpp)
+static void dpp_agent_release(struct dpp *dpp)
{
struct l_dbus_message *msg;
@@ -400,7 +340,7 @@ static void dpp_agent_release(struct dpp_sm *dpp)
l_dbus_send(dbus_get_bus(), msg);
}
-static void dpp_destroy_agent(struct dpp_sm *dpp)
+static void dpp_destroy_agent(struct dpp *dpp)
{
if (!dpp->agent)
return;
@@ -418,56 +358,7 @@ static void dpp_destroy_agent(struct dpp_sm *dpp)
dpp->agent = NULL;
}
-static void dpp_free_auth_data(struct dpp_sm *dpp)
-{
- if (dpp->own_proto_public) {
- l_ecc_point_free(dpp->own_proto_public);
- dpp->own_proto_public = NULL;
- }
-
- if (dpp->proto_private) {
- l_ecc_scalar_free(dpp->proto_private);
- dpp->proto_private = NULL;
- }
-
- if (dpp->peer_proto_public) {
- l_ecc_point_free(dpp->peer_proto_public);
- dpp->peer_proto_public = NULL;
- }
-
- if (dpp->peer_boot_public) {
- l_ecc_point_free(dpp->peer_boot_public);
- dpp->peer_boot_public = NULL;
- }
-
- if (dpp->m) {
- l_ecc_scalar_free(dpp->m);
- dpp->m = NULL;
- }
-
- if (dpp->pkex_m) {
- l_ecc_point_free(dpp->pkex_m);
- dpp->pkex_m = NULL;
- }
-
- if (dpp->y_or_x) {
- l_ecc_point_free(dpp->y_or_x);
- dpp->y_or_x = NULL;
- }
-
- if (dpp->pkex_public) {
- l_ecc_point_free(dpp->pkex_public);
- dpp->pkex_public = NULL;
- }
-
- if (dpp->pkex_private) {
- l_ecc_scalar_free(dpp->pkex_private);
- dpp->pkex_private = NULL;
- }
-
-}
-
-static void dpp_reset(struct dpp_sm *dpp)
+static void dpp_reset(struct dpp *dpp)
{
if (dpp->uri) {
l_free(dpp->uri);
@@ -499,11 +390,6 @@ static void dpp_reset(struct dpp_sm *dpp)
dpp->connect_scan_id = 0;
}
- if (dpp->peer_asn1) {
- l_free(dpp->peer_asn1);
- dpp->peer_asn1 = NULL;
- }
-
if (dpp->frame_pending) {
l_free(dpp->frame_pending);
dpp->frame_pending = NULL;
@@ -524,44 +410,23 @@ static void dpp_reset(struct dpp_sm *dpp)
dpp->connect_idle = NULL;
}
- dpp->state = DPP_STATE_NOTHING;
dpp->new_freq = 0;
dpp->frame_retry = 0;
dpp->frame_cookie = 0;
- dpp->pkex_version = 0;
-
- explicit_bzero(dpp->r_nonce, dpp->nonce_len);
- explicit_bzero(dpp->i_nonce, dpp->nonce_len);
- explicit_bzero(dpp->e_nonce, dpp->nonce_len);
- explicit_bzero(dpp->ke, dpp->key_len);
- explicit_bzero(dpp->k1, dpp->key_len);
- explicit_bzero(dpp->k2, dpp->key_len);
- explicit_bzero(dpp->auth_tag, dpp->key_len);
- explicit_bzero(dpp->z, dpp->key_len);
- explicit_bzero(dpp->u, dpp->u_len);
dpp_destroy_agent(dpp);
- dpp_free_pending_pkex_data(dpp);
-
- dpp_free_auth_data(dpp);
-
dpp_property_changed_notify(dpp);
dpp->interface = DPP_INTERFACE_UNBOUND;
}
-static void dpp_free(struct dpp_sm *dpp)
+static void dpp_free(struct dpp *dpp)
{
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
dpp_reset(dpp);
- if (dpp->own_asn1) {
- l_free(dpp->own_asn1);
- dpp->own_asn1 = NULL;
- }
-
if (dpp->boot_public) {
l_ecc_point_free(dpp->boot_public);
dpp->boot_public = NULL;
@@ -586,7 +451,7 @@ static void dpp_free(struct dpp_sm *dpp)
static void dpp_send_frame_cb(struct l_genl_msg *msg, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
int err = l_genl_msg_get_error(msg);
if (err < 0) {
@@ -599,7 +464,7 @@ static void dpp_send_frame_cb(struct l_genl_msg *msg, void *user_data)
l_error("Error parsing frame cookie");
}
-static void dpp_send_frame(struct dpp_sm *dpp,
+static void dpp_send_frame(struct dpp *dpp,
struct iovec *iov, size_t iov_len,
uint32_t freq)
{
@@ -632,7 +497,7 @@ static void dpp_send_frame(struct dpp_sm *dpp,
}
}
-static void dpp_frame_retry(struct dpp_sm *dpp)
+static void dpp_frame_retry(struct dpp *dpp)
{
struct iovec iov;
@@ -645,183 +510,6 @@ static void dpp_frame_retry(struct dpp_sm *dpp)
dpp->frame_pending = NULL;
}
-
-static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
- enum dpp_frame_type type,
- uint8_t *buf)
-{
- uint8_t *ptr = buf + 24;
-
- memset(buf, 0, 32);
-
- l_put_le16(0x00d0, buf);
- memcpy(buf + 4, dest, 6);
- memcpy(buf + 10, src, 6);
- memcpy(buf + 16, broadcast, 6);
-
- *ptr++ = 0x04; /* Category: Public */
- *ptr++ = 0x09; /* Action: Vendor specific usage */
- memcpy(ptr, wifi_alliance_oui, 3);
- ptr += 3;
- *ptr++ = 0x1a; /* WiFi Alliance DPP OI type */
- *ptr++ = 1; /* Cryptosuite */
- *ptr++ = type;
-
- return ptr - buf;
-}
-
-static size_t dpp_build_config_header(const uint8_t *src, const uint8_t *dest,
- uint8_t diag_token,
- uint8_t *buf)
-{
- uint8_t *ptr = buf + 24;
-
- memset(buf, 0, 37);
-
- l_put_le16(0x00d0, buf);
- memcpy(buf + 4, dest, 6);
- memcpy(buf + 10, src, 6);
- memcpy(buf + 16, broadcast, 6);
-
- *ptr++ = 0x04; /* Public */
- *ptr++ = 0x0a; /* Action */
- *ptr++ = diag_token;
-
- *ptr++ = IE_TYPE_ADVERTISEMENT_PROTOCOL;
- *ptr++ = 8; /* len */
- *ptr++ = 0x00;
- *ptr++ = IE_TYPE_VENDOR_SPECIFIC;
- *ptr++ = 5;
- memcpy(ptr, wifi_alliance_oui, 3);
- ptr += 3;
- *ptr++ = 0x1a;
- *ptr++ = 1;
-
- return ptr - buf;
-}
-
-static void dpp_protocol_timeout(struct l_timeout *timeout, void *user_data)
-{
- struct dpp_sm *dpp = user_data;
-
- l_debug("DPP timed out");
-
- dpp_reset(dpp);
-}
-
-static void dpp_reset_protocol_timer(struct dpp_sm *dpp, uint32_t time)
-{
- if (dpp->timeout)
- l_timeout_modify(dpp->timeout, time);
- else
- dpp->timeout = l_timeout_create(time, dpp_protocol_timeout,
- dpp, NULL);
-}
-
-/*
- * The configuration protocols use of AD components is somewhat confusing
- * since the request/response frames are of a different format than the rest.
- * In addition there are situations where the components length is zero yet it
- * is still passed as such to AES-SIV.
- *
- * For the configuration request/response frames:
- *
- * "AAD for use with AES-SIV for protected messages in the DPP Configuration
- * protocol shall consist of all octets in the Query Request and Query Response
- * fields up to the first octet of the Wrapped Data attribute, which is the last
- * attribute in a DPP Configuration frame. When the number of octets of AAD is
- * zero, the number of components of AAD passed to AES-SIV is zero."
- *
- * - For configuration requests the optional query request field is not
- * included, therefore no AAD data is passed. (dpp_configuration_start)
- *
- * - The configuration response does contain a query response field which is
- * 5 bytes. (dpp_handle_config_response_frame)
- *
- * For the configuration result/status, the same rules are used as the
- * authentication protocol. This is reiterated in section 6.4.1.
- *
- * - For the configuration result there is some confusion as to exactly how the
- * second AAD component should be passed (since the spec specifically
- * mentions using two components). There are no attributes prior to the
- * wrapped data component meaning the length would be zero.
- * Hostapd/wpa_supplicant pass a zero length AAD component to AES-SIV which
- * does effect the resulting encryption/decryption so this is also what IWD
- * will do to remain compliant with it.
- */
-static void dpp_configuration_start(struct dpp_sm *dpp, const uint8_t *addr)
-{
- const char *json = "{\"name\":\"IWD\",\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"sta\"}";
- struct iovec iov;
- uint8_t frame[512];
- size_t json_len = strlen(json);
- uint8_t *ptr = frame;
- uint8_t *lptr;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- l_getrandom(&dpp->diag_token, 1);
-
- ptr += dpp_build_config_header(netdev_get_address(dpp->netdev),
- addr, dpp->diag_token, ptr);
-
- l_getrandom(dpp->e_nonce, dpp->nonce_len);
-
- /* length */
- lptr = ptr;
- ptr += 2;
-
- /*
- * "AAD for use with AES-SIV for protected messages in the DPP
- * Configuration protocol shall consist of all octets in the Query
- * Request and Query Response fields up to the first octet of the
- * Wrapped Data attribute"
- *
- * In this case there is no query request/response fields, nor any
- * attributes besides wrapped data meaning zero AD components.
- */
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->ke, dpp->key_len, 2,
- DPP_ATTR_ENROLLEE_NONCE, dpp->nonce_len, dpp->e_nonce,
- DPP_ATTR_CONFIGURATION_REQUEST, json_len, json);
-
- l_put_le16(ptr - lptr - 2, lptr);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp->state = DPP_STATE_CONFIGURING;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static void send_config_result(struct dpp_sm *dpp, const uint8_t *to)
-{
- struct iovec iov;
- uint8_t frame[256];
- uint8_t *ptr = frame;
- uint8_t zero = 0;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev), to,
- DPP_FRAME_CONFIGURATION_RESULT, ptr);
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->ke, dpp->key_len, 2,
- DPP_ATTR_STATUS, (size_t) 1, &zero,
- DPP_ATTR_ENROLLEE_NONCE, dpp->nonce_len, dpp->e_nonce);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
static void dpp_write_config(struct dpp_configuration *config,
struct network *network)
{
@@ -862,2600 +550,250 @@ static void dpp_scan_triggered(int err, void *user_data)
static void dpp_start_connect(struct l_idle *idle, void *user_data)
{
- struct dpp_sm *dpp = user_data;
- struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
- struct scan_bss *bss;
- struct network *network;
- int ret;
-
- network = station_network_find(station, dpp->config->ssid,
- SECURITY_PSK);
-
- dpp_reset(dpp);
-
- if (!network) {
- l_debug("Network was not found!");
- return;
- }
-
- l_debug("connecting to %s from DPP", network_get_ssid(network));
-
- bss = network_bss_select(network, true);
- ret = network_autoconnect(network, bss);
- if (ret < 0)
- l_warn("failed to connect after DPP (%d) %s", ret,
- strerror(-ret));
-}
-
-static bool dpp_scan_results(int err, struct l_queue *bss_list,
- const struct scan_freq_set *freqs,
- void *userdata)
-{
- struct dpp_sm *dpp = userdata;
- struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
-
- if (err < 0)
- goto reset;
-
- if (!bss_list || l_queue_length(bss_list) == 0)
- goto reset;
-
- /*
- * The station watch _should_ detect this and reset, which cancels the
- * scan. But just in case...
- */
- if (L_WARN_ON(station_get_connected_network(station)))
- goto reset;
-
- station_set_scan_results(station, bss_list, freqs, false);
-
- dpp_start_connect(NULL, dpp);
-
- return true;
-
-reset:
- return false;
-}
-
-static void dpp_scan_destroy(void *userdata)
-{
- struct dpp_sm *dpp = userdata;
-
- dpp->connect_scan_id = 0;
- dpp_reset(dpp);
-}
-
-static void dpp_known_network_watch(enum known_networks_event event,
- const struct network_info *info,
- void *user_data)
-{
- struct dpp_sm *dpp = user_data;
-
- /*
- * Check the following
- * - DPP is enrolling
- * - DPP finished (dpp->config is set)
- * - This is for the network DPP just configured
- * - DPP isn't already trying to connect (e.g. if the profile was
- * immediately modified after DPP synced it).
- * - DPP didn't start a scan for the network.
- */
- if (dpp->role != DPP_CAPABILITY_ENROLLEE)
- return;
- if (!dpp->config)
- return;
- if (strcmp(info->ssid, dpp->config->ssid))
- return;
- if (dpp->connect_idle)
- return;
- if (dpp->connect_scan_id)
- return;
-
- switch (event) {
- case KNOWN_NETWORKS_EVENT_ADDED:
- case KNOWN_NETWORKS_EVENT_UPDATED:
- /*
- * network.c takes care of updating the settings for the
- * network. This callback just tells us to begin the connection.
- * We do have use an idle here because there is no strict
- * guarantee of ordering between known network events, e.g. DPP
- * could have been called into prior to network and the network
- * object isn't updated yet.
- */
- dpp->connect_idle = l_idle_create(dpp_start_connect, dpp, NULL);
- break;
- case KNOWN_NETWORKS_EVENT_REMOVED:
- l_warn("profile was removed before DPP could connect");
- break;
- }
-}
-
-static void dpp_handle_config_response_frame(const struct mmpdu_header *frame,
- const void *body, size_t body_len,
- int rssi, void *user_data)
-{
- struct dpp_sm *dpp = user_data;
- const uint8_t *ptr = body;
- uint16_t status;
- uint16_t fragmented; /* Fragmented/Comeback delay field */
- uint8_t adv_protocol_element[] = { 0x6C, 0x08, 0x7F };
- uint8_t adv_protocol_id[] = { 0xDD, 0x05, 0x50, 0x6F,
- 0x9A, 0x1A, 0x01 };
- uint16_t query_len;
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const char *json = NULL;
- size_t json_len = 0;
- int dstatus = -1;
- const uint8_t *wrapped = NULL;
- const uint8_t *e_nonce = NULL;
- size_t wrapped_len = 0;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- struct dpp_configuration *config;
+ struct dpp *dpp = user_data;
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
- struct network *network = NULL;
- struct scan_bss *bss = NULL;
-
- if (dpp->state != DPP_STATE_CONFIGURING)
- return;
-
- /*
- * Can a configuration request come from someone other than who you
- * authenticated to?
- */
- if (memcmp(dpp->peer_addr, frame->address_2, 6))
- return;
-
- if (body_len < 19)
- return;
-
- ptr += 2;
-
- if (*ptr++ != dpp->diag_token)
- return;
-
- status = l_get_le16(ptr);
- ptr += 2;
-
- if (status != 0) {
- l_debug("Bad configuration status %u", status);
- return;
- }
-
- fragmented = l_get_le16(ptr);
- ptr += 2;
-
- /*
- * TODO: handle 0x0001 (fragmented), as well as comeback delay.
- */
- if (fragmented != 0) {
- l_debug("Fragmented messages not currently supported");
- return;
- }
-
- if (memcmp(ptr, adv_protocol_element, sizeof(adv_protocol_element))) {
- l_debug("Invalid Advertisement protocol element");
- return;
- }
-
- ptr += sizeof(adv_protocol_element);
-
- if (memcmp(ptr, adv_protocol_id, sizeof(adv_protocol_id))) {
- l_debug("Invalid Advertisement protocol ID");
- return;
- }
-
- ptr += sizeof(adv_protocol_id);
-
- query_len = l_get_le16(ptr);
- ptr += 2;
-
- if (query_len > body_len - 19)
- return;
-
- dpp_attr_iter_init(&iter, ptr, query_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_STATUS:
- dstatus = l_get_u8(data);
- break;
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- /*
- * TODO: CSR Attribute
- */
- break;
- }
- }
-
- if (dstatus != DPP_STATUS_OK || !wrapped) {
- l_debug("Bad status or missing attributes");
- return;
- }
-
- unwrapped = dpp_unwrap_attr(ptr, wrapped - ptr - 4, NULL, 0, dpp->ke,
- dpp->key_len, wrapped, wrapped_len,
- &wrapped_len);
- if (!unwrapped) {
- l_debug("Failed to unwrap");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_ENROLLEE_NONCE:
- if (len != dpp->nonce_len)
- break;
-
- if (memcmp(data, dpp->e_nonce, dpp->nonce_len))
- break;
-
- e_nonce = data;
- break;
- case DPP_ATTR_CONFIGURATION_OBJECT:
- json = (const char *)data;
- json_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!json || !e_nonce) {
- l_debug("No configuration object in response");
- return;
- }
-
- config = dpp_parse_configuration_object(json, json_len);
- if (!config) {
- l_error("Configuration object did not parse");
- return;
- }
-
- /*
- * We should have a station device, but if not DPP can write the
- * credentials out and be done
- */
- if (station) {
- network = station_network_find(station, config->ssid,
- SECURITY_PSK);
- if (network)
- bss = network_bss_select(network, true);
- }
-
- dpp_write_config(config, network);
-
- send_config_result(dpp, dpp->peer_addr);
-
- offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
-
- if (network && bss) {
- l_debug("delaying connect until settings are synced");
- dpp->config = config;
- return;
- } else if (station) {
- struct scan_parameters params = {0};
-
- params.ssid = (void *) config->ssid;
- params.ssid_len = config->ssid_len;
-
- l_debug("Scanning for %s", config->ssid);
-
- dpp->connect_scan_id = scan_active_full(dpp->wdev_id, ¶ms,
- dpp_scan_triggered,
- dpp_scan_results, dpp,
- dpp_scan_destroy);
- if (dpp->connect_scan_id) {
- dpp->config = config;
- return;
- }
- }
-
- dpp_configuration_free(config);
- dpp_reset(dpp);
-}
-
-static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
-{
- _auto_(l_free) char *json = NULL;
- struct iovec iov;
- uint8_t frame[512];
- size_t json_len;
- uint8_t *ptr = frame;
- uint8_t *lptr;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- l_put_le16(0x00d0, ptr);
- memcpy(ptr + 4, dpp->peer_addr, 6);
- memcpy(ptr + 10, netdev_get_address(dpp->netdev), 6);
- memcpy(ptr + 16, broadcast, 6);
-
- ptr += 24;
-
- *ptr++ = 0x04;
- *ptr++ = 0x0b;
- *ptr++ = dpp->diag_token;
- l_put_le16(0, ptr); /* status */
- ptr += 2;
- l_put_le16(0, ptr); /* fragmented (no) */
- ptr += 2;
- *ptr++ = IE_TYPE_ADVERTISEMENT_PROTOCOL;
- *ptr++ = 0x08;
- *ptr++ = 0x7f;
- *ptr++ = IE_TYPE_VENDOR_SPECIFIC;
- *ptr++ = 5;
- memcpy(ptr, wifi_alliance_oui, sizeof(wifi_alliance_oui));
- ptr += sizeof(wifi_alliance_oui);
- *ptr++ = 0x1a;
- *ptr++ = 1;
-
- lptr = ptr;
- ptr += 2; /* length */
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
-
- /*
- * There are several failure status codes that can be used (defined in
- * 6.4.3.1), each with their own set of attributes that should be
- * included. For now IWD's basic DPP implementation will assume
- * STATUS_CONFIGURE_FAILURE which only includes the E-Nonce.
- */
- if (status == DPP_STATUS_OK) {
- json = dpp_configuration_to_json(dpp->config);
- json_len = strlen(json);
-
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1,
- ptr, dpp->ke, dpp->key_len, 2,
- DPP_ATTR_ENROLLEE_NONCE,
- dpp->nonce_len, dpp->e_nonce,
- DPP_ATTR_CONFIGURATION_OBJECT,
- json_len, json);
- } else
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1,
- ptr, dpp->ke, dpp->key_len, 2,
- DPP_ATTR_ENROLLEE_NONCE,
- dpp->nonce_len, dpp->e_nonce);
-
- l_put_le16(ptr - lptr - 2, lptr);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static bool dpp_check_config_header(const uint8_t *ptr)
-{
- /*
- * Table 58. General Format of DPP Configuration Request frame
- *
- * Unfortunately wpa_supplicant hard codes 0x7f as the Query Response
- * Info so we need to handle both cases.
- */
- return ptr[0] == IE_TYPE_ADVERTISEMENT_PROTOCOL &&
- ptr[1] == 0x08 &&
- (ptr[2] == 0x7f || ptr[2] == 0x00) &&
- ptr[3] == IE_TYPE_VENDOR_SPECIFIC &&
- ptr[4] == 5;
-}
-
-static void dpp_handle_config_request_frame(const struct mmpdu_header *frame,
- const void *body, size_t body_len,
- int rssi, void *user_data)
-{
- struct dpp_sm *dpp = user_data;
- const uint8_t *ptr = body;
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const char *json = NULL;
- size_t json_len = 0;
- struct json_contents *c;
- const uint8_t *wrapped = NULL;
- const uint8_t *e_nonce = NULL;
- size_t wrapped_len = 0;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- struct json_iter jsiter;
- _auto_(l_free) char *tech = NULL;
- _auto_(l_free) char *role = NULL;
-
- if (dpp->state != DPP_STATE_AUTHENTICATING) {
- l_debug("Configuration request in wrong state");
- return;
- }
-
- if (dpp->role != DPP_CAPABILITY_CONFIGURATOR)
- return;
-
- if (memcmp(dpp->peer_addr, frame->address_2, 6)) {
- l_debug("Configuration request not from authenticated peer");
- return;
- }
-
- if (body_len < 15) {
- l_debug("Configuration request data not long enough");
- return;
- }
-
- ptr += 2;
-
- dpp->diag_token = *ptr++;
-
- if (!dpp_check_config_header(ptr))
- return;
-
- ptr += 5;
-
- if (memcmp(ptr, wifi_alliance_oui, sizeof(wifi_alliance_oui)))
- return;
-
- ptr += sizeof(wifi_alliance_oui);
-
- if (*ptr != 0x1a && *(ptr + 1) != 1)
- return;
-
- ptr += 2;
-
- len = l_get_le16(ptr);
- ptr += 2;
-
- if (len > body_len - 15)
- return;
-
- dpp_attr_iter_init(&iter, ptr, len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- /* Wrapped data should be only attribute */
- return;
- }
- }
-
- if (!wrapped) {
- l_debug("Wrapped data missing");
- return;
- }
-
- unwrapped = dpp_unwrap_attr(NULL, 0, NULL, 0, dpp->ke,
- dpp->key_len, wrapped, wrapped_len,
- &wrapped_len);
- if (!unwrapped) {
- l_debug("Failed to unwrap");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_ENROLLEE_NONCE:
- if (len != dpp->nonce_len)
- break;
-
- e_nonce = data;
- break;
- case DPP_ATTR_CONFIGURATION_REQUEST:
- json = (const char *)data;
- json_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!json || !e_nonce) {
- l_debug("No configuration object in response");
- return;
- }
-
- c = json_contents_new(json, json_len);
- if (!c) {
- json_contents_free(c);
- return;
- }
-
- json_iter_init(&jsiter, c);
-
- /*
- * Check mandatory values (Table 7). There isn't much that can be done
- * with these, but the spec requires they be included.
- */
- if (!json_iter_parse(&jsiter,
- JSON_MANDATORY("name", JSON_STRING, NULL),
- JSON_MANDATORY("wi-fi_tech", JSON_STRING, &tech),
- JSON_MANDATORY("netRole", JSON_STRING, &role),
- JSON_UNDEFINED))
- goto configure_failure;
-
- if (strcmp(tech, "infra"))
- goto configure_failure;
-
- if (strcmp(role, "sta"))
- goto configure_failure;
-
- json_contents_free(c);
-
- memcpy(dpp->e_nonce, e_nonce, dpp->nonce_len);
-
- dpp->state = DPP_STATE_CONFIGURING;
-
- dpp_send_config_response(dpp, DPP_STATUS_OK);
-
- return;
-
-configure_failure:
- dpp_send_config_response(dpp, DPP_STATUS_CONFIGURE_FAILURE);
- /*
- * The other peer is still authenticated, and can potentially send
- * additional requests so keep this session alive.
- */
-}
-
-static void dpp_handle_config_result_frame(struct dpp_sm *dpp,
- const uint8_t *from, const void *body,
- size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- int status = -1;
- const void *e_nonce = NULL;
- const void *wrapped = NULL;
- size_t wrapped_len;
- _auto_(l_free) void *unwrapped = NULL;
-
- if (dpp->state != DPP_STATE_CONFIGURING)
- return;
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- /* Wrapped data should be only attribute */
- return;
- }
- }
-
- if (!wrapped)
- return;
-
- unwrapped = dpp_unwrap_attr(body + 2, wrapped - body - 6, wrapped, 0,
- dpp->ke, dpp->key_len, wrapped,
- wrapped_len, &wrapped_len);
- if (!unwrapped) {
- l_debug("Failed to unwrap DPP configuration result");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_STATUS:
- status = l_get_u8(data);
- break;
- case DPP_ATTR_ENROLLEE_NONCE:
- e_nonce = data;
- break;
- default:
- break;
- }
- }
-
- if (status != DPP_STATUS_OK || !e_nonce)
- l_debug("Enrollee signaled a failed configuration");
- else
- l_debug("Configuration success");
-
- dpp_reset(dpp);
-}
-
-/*
- * The Authentication protocol has a consistent use of AD components, and this
- * use is defined in 6.3.1.4:
- *
- * "Invocations of AES-SIV in the DPP Authentication protocol that produce
- * ciphertext that is part of an additional AES-SIV invocation do not use AAD;
- * in other words, the number of AAD components is set to zero. All other
- * invocations of AES-SIV in the DPP Authentication protocol shall pass a vector
- * of AAD having two components of AAD in the following order: (1) the DPP
- * header, as defined in Table 30, from the OUI field (inclusive) to the DPP
- * Frame Type field (inclusive); and (2) all octets in a DPP Public Action frame
- * after the DPP Frame Type field up to and including the last octet of the last
- * attribute before the Wrapped Data attribute"
- *
- * In practice you see this as AD0 being some offset in the frame (offset to the
- * OUI). For outgoing packets this is 26 bytes offset since the header is built
- * manually. For incoming packets the offset is 2 bytes. The length is always
- * 6 bytes for AD0.
- *
- * The AD1 data is always the start of the attributes, and length is the number
- * of bytes from these attributes to wrapped data. e.g.
- *
- * ad1 = attrs
- * ad1_len = ptr - attrs
- */
-static void send_authenticate_response(struct dpp_sm *dpp)
-{
- uint8_t frame[512];
- uint8_t *ptr = frame;
- uint8_t status = DPP_STATUS_OK;
- uint8_t version = 2;
- struct iovec iov;
- uint8_t wrapped2_plaintext[dpp->key_len + 4];
- uint8_t wrapped2[dpp->key_len + 16 + 8];
- size_t wrapped2_len;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev),
- dpp->peer_addr,
- DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH,
- dpp->own_boot_hash, 32);
- if (dpp->mutual_auth)
- ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
- dpp->peer_boot_hash, 32);
- ptr += dpp_append_point(ptr, DPP_ATTR_RESPONDER_PROTOCOL_KEY,
- dpp->own_proto_public);
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, &version, 1);
-
- /* Wrap up secondary data (R-Auth) */
- wrapped2_len = dpp_append_attr(wrapped2_plaintext,
- DPP_ATTR_RESPONDER_AUTH_TAG,
- dpp->auth_tag, dpp->key_len);
- /*
- * "Invocations of AES-SIV in the DPP Authentication protocol that
- * produce ciphertext that is part of an additional AES-SIV invocation
- * do not use AAD; in other words, the number of AAD components is set
- * to zero.""
- */
- if (!aes_siv_encrypt(dpp->ke, dpp->key_len, wrapped2_plaintext,
- dpp->key_len + 4, NULL, 0, wrapped2)) {
- l_error("Failed to encrypt wrapped data");
- return;
- }
-
- wrapped2_len += 16;
-
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->k2, dpp->key_len, 4,
- DPP_ATTR_RESPONDER_NONCE, dpp->nonce_len, dpp->r_nonce,
- DPP_ATTR_INITIATOR_NONCE, dpp->nonce_len, dpp->i_nonce,
- DPP_ATTR_RESPONDER_CAPABILITIES, (size_t) 1, &dpp->role,
- DPP_ATTR_WRAPPED_DATA, wrapped2_len, wrapped2);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static void authenticate_confirm(struct dpp_sm *dpp, const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- int status = -1;
- const uint8_t *r_boot_hash = NULL;
- const void *wrapped = NULL;
- const uint8_t *i_auth = NULL;
- size_t i_auth_len;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- size_t wrapped_len = 0;
- uint64_t i_auth_check[L_ECC_MAX_DIGITS];
- const void *unwrap_key;
- const void *ad0 = body + 2;
- const void *ad1 = body + 8;
- struct l_ecc_point *bi = NULL;
-
- if (dpp->state != DPP_STATE_AUTHENTICATING)
- return;
-
- if (memcmp(from, dpp->peer_addr, 6))
- return;
-
- l_debug("authenticate confirm");
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_STATUS:
- status = l_get_u8(data);
- break;
- case DPP_ATTR_RESPONDER_BOOT_KEY_HASH:
- r_boot_hash = data;
- /*
- * Spec requires this, but does not mention if anything
- * is to be done with it.
- */
- break;
- case DPP_ATTR_INITIATOR_BOOT_KEY_HASH:
- /* No mutual authentication */
- break;
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!r_boot_hash || !wrapped) {
- l_debug("Attributes missing from authenticate confirm");
- return;
- }
-
- /*
- * "The Responder obtains the DPP Authentication Confirm frame and
- * checks the value of the DPP Status field. If the value of the DPP
- * Status field is STATUS_NOT_COMPATIBLE or STATUS_AUTH_FAILURE, the
- * Responder unwraps the wrapped data portion of the frame using k2"
- */
- if (status == DPP_STATUS_OK)
- unwrap_key = dpp->ke;
- else if (status == DPP_STATUS_NOT_COMPATIBLE ||
- status == DPP_STATUS_AUTH_FAILURE)
- unwrap_key = dpp->k2;
- else
- goto auth_confirm_failed;
-
- unwrapped = dpp_unwrap_attr(ad0, 6, ad1, wrapped - 4 - ad1,
- unwrap_key, dpp->key_len, wrapped, wrapped_len,
- &wrapped_len);
- if (!unwrapped)
- goto auth_confirm_failed;
-
- if (status != DPP_STATUS_OK) {
- /*
- * "If unwrapping is successful, the Responder should generate
- * an alert indicating the reason for the protocol failure."
- */
- l_debug("Authentication failed due to status %s",
- status == DPP_STATUS_NOT_COMPATIBLE ?
- "NOT_COMPATIBLE" : "AUTH_FAILURE");
- goto auth_confirm_failed;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_INITIATOR_AUTH_TAG:
- i_auth = data;
- i_auth_len = len;
- break;
- case DPP_ATTR_RESPONDER_NONCE:
- /* Only if error */
- break;
- default:
- break;
- }
- }
-
- if (!i_auth || i_auth_len != dpp->key_len) {
- l_debug("I-Auth missing from wrapped data");
- goto auth_confirm_failed;
- }
-
- if (dpp->mutual_auth)
- bi = dpp->peer_boot_public;
-
- dpp_derive_i_auth(dpp->r_nonce, dpp->i_nonce, dpp->nonce_len,
- dpp->own_proto_public, dpp->peer_proto_public,
- dpp->boot_public, bi, i_auth_check);
-
- if (memcmp(i_auth, i_auth_check, i_auth_len)) {
- l_error("I-Auth did not verify");
- goto auth_confirm_failed;
- }
-
- l_debug("Authentication successful");
-
- dpp_reset_protocol_timer(dpp, DPP_AUTH_PROTO_TIMEOUT);
-
- if (dpp->role == DPP_CAPABILITY_ENROLLEE)
- dpp_configuration_start(dpp, from);
-
- return;
-
-auth_confirm_failed:
- dpp->state = DPP_STATE_PRESENCE;
- dpp_free_auth_data(dpp);
-}
-
-static void dpp_auth_request_failed(struct dpp_sm *dpp,
- enum dpp_status status,
- void *k1)
-{
- uint8_t frame[128];
- uint8_t *ptr = frame;
- uint8_t version = 2;
- uint8_t s = status;
- struct iovec iov;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev),
- dpp->peer_addr,
- DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &s, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH,
- dpp->own_boot_hash, 32);
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, &version, 1);
-
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- k1, dpp->key_len, 2,
- DPP_ATTR_INITIATOR_NONCE, dpp->nonce_len, dpp->i_nonce,
- DPP_ATTR_RESPONDER_CAPABILITIES,
- (size_t) 1, &dpp->role);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static bool dpp_check_roles(struct dpp_sm *dpp, uint8_t peer_capa)
-{
- if (dpp->role == DPP_CAPABILITY_ENROLLEE &&
- !(peer_capa & DPP_CAPABILITY_CONFIGURATOR))
- return false;
- else if (dpp->role == DPP_CAPABILITY_CONFIGURATOR &&
- !(peer_capa & DPP_CAPABILITY_ENROLLEE))
- return false;
-
- return true;
-}
-
-static void dpp_presence_announce(struct dpp_sm *dpp)
-{
- struct netdev *netdev = dpp->netdev;
- uint8_t hdr[32];
- uint8_t attrs[32 + 4];
- uint8_t hash[32];
- uint8_t *ptr = attrs;
- const uint8_t *addr = netdev_get_address(netdev);
- struct iovec iov[2];
-
- iov[0].iov_len = dpp_build_header(addr, broadcast,
- DPP_FRAME_PRESENCE_ANNOUNCEMENT, hdr);
- iov[0].iov_base = hdr;
-
- dpp_hash(L_CHECKSUM_SHA256, hash, 2, "chirp", strlen("chirp"),
- dpp->own_asn1, dpp->own_asn1_len);
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH, hash, 32);
-
- iov[1].iov_base = attrs;
- iov[1].iov_len = ptr - attrs;
-
- l_debug("Sending presence announcement on frequency %u and waiting %u",
- dpp->current_freq, dpp->dwell);
-
- dpp_send_frame(dpp, iov, 2, dpp->current_freq);
-}
-
-static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
-{
- uint8_t frame[256];
- uint8_t *ptr = frame;
- uint8_t version = 2;
- struct iovec iov;
- struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
- struct scan_bss *bss = station_get_connected_bss(station);
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- /* Got disconnected by the time the peer was discovered */
- if (dpp->role == DPP_CAPABILITY_CONFIGURATOR && !bss) {
- dpp_reset(dpp);
- return false;
- }
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev),
- dpp->peer_addr,
- DPP_FRAME_AUTHENTICATION_REQUEST, ptr);
- ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH,
- dpp->peer_boot_hash, 32);
- ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
- dpp->own_boot_hash, 32);
- ptr += dpp_append_point(ptr, DPP_ATTR_INITIATOR_PROTOCOL_KEY,
- dpp->own_proto_public);
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, &version, 1);
-
- if (dpp->role == DPP_CAPABILITY_CONFIGURATOR &&
- dpp->current_freq != bss->frequency) {
- uint8_t pair[2] = { 81,
- band_freq_to_channel(bss->frequency, NULL) };
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_CHANNEL, pair, 2);
- }
-
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->k1, dpp->key_len, 2,
- DPP_ATTR_INITIATOR_NONCE, dpp->nonce_len, dpp->i_nonce,
- DPP_ATTR_INITIATOR_CAPABILITIES,
- (size_t) 1, &dpp->role);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-
- return true;
-}
-
-static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp)
-{
- uint8_t hdr[32];
- uint8_t attrs[256];
- uint8_t *ptr = attrs;
- uint16_t group;
- struct iovec iov[2];
- const uint8_t *own_mac = netdev_get_address(dpp->netdev);
-
- l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group);
-
- iov[0].iov_len = dpp_build_header(own_mac, broadcast,
- DPP_FRAME_PKEX_VERSION1_XCHG_REQUEST, hdr);
- iov[0].iov_base = hdr;
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION,
- &dpp->pkex_version, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_FINITE_CYCLIC_GROUP,
- &group, 2);
-
- if (dpp->pkex_id)
- ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER,
- dpp->pkex_id, strlen(dpp->pkex_id));
-
- ptr += dpp_append_point(ptr, DPP_ATTR_ENCRYPTED_KEY, dpp->pkex_m);
-
- iov[1].iov_base = attrs;
- iov[1].iov_len = ptr - attrs;
-
- dpp_send_frame(dpp, iov, 2, dpp->current_freq);
-}
-
-static void dpp_send_commit_reveal_request(struct dpp_sm *dpp)
-{
- struct iovec iov;
- uint8_t frame[512];
- uint8_t *ptr = frame;
- uint8_t a_pub[L_ECC_POINT_MAX_BYTES];
- ssize_t a_len;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- a_len = l_ecc_point_get_data(dpp->boot_public, a_pub, sizeof(a_pub));
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev),
- dpp->peer_addr,
- DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST,
- ptr);
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->z, dpp->z_len, 2,
- DPP_ATTR_BOOTSTRAPPING_KEY, a_len, a_pub,
- DPP_ATTR_INITIATOR_AUTH_TAG, dpp->u_len, dpp->u);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static void dpp_roc_started(void *user_data)
-{
- struct dpp_sm *dpp = user_data;
-
- /*
- * - If a configurator, nothing to do but wait for a request
- * (unless multicast frame registration is unsupported in which case
- * send an authenticate request now)
- * - If in the presence state continue sending announcements.
- * - If authenticating, and this is a result of a channel switch send
- * the authenticate response now.
- */
-
- dpp->roc_started = true;
-
- /*
- * The retry timer indicates a frame was not acked in which case we
- * should not change any state or send any frames until that expires.
- */
- if (dpp->retry_timeout)
- return;
-
- if (dpp->frame_pending) {
- dpp_frame_retry(dpp);
- return;
- }
-
- switch (dpp->state) {
- case DPP_STATE_PRESENCE:
- if (dpp->role == DPP_CAPABILITY_CONFIGURATOR)
- return;
-
- if (dpp->pending) {
- struct l_dbus_message *reply =
- l_dbus_message_new_method_return(dpp->pending);
-
- l_dbus_message_set_arguments(reply, "s", dpp->uri);
-
- dbus_pending_reply(&dpp->pending, reply);
- }
-
- dpp_presence_announce(dpp);
- break;
- case DPP_STATE_AUTHENTICATING:
- /*
- * No multicast frame registration support, jump right into
- * sending auth frames. This diverges from the 2.0 spec, but in
- * reality the the main path nearly all drivers will hit.
- */
- if (dpp->role == DPP_CAPABILITY_CONFIGURATOR) {
- if (dpp->mcast_support)
- return;
-
- dpp_send_authenticate_request(dpp);
- return;
- }
-
- if (dpp->new_freq) {
- dpp->current_freq = dpp->new_freq;
- dpp->new_freq = 0;
- send_authenticate_response(dpp);
- }
-
- break;
- case DPP_STATE_PKEX_EXCHANGE:
- if (dpp->role == DPP_CAPABILITY_ENROLLEE)
- dpp_send_pkex_exchange_request(dpp);
-
- break;
- case DPP_STATE_PKEX_COMMIT_REVEAL:
- if (dpp->role == DPP_CAPABILITY_ENROLLEE)
- dpp_send_commit_reveal_request(dpp);
-
- break;
- default:
- break;
- }
-}
-
-static void dpp_start_offchannel(struct dpp_sm *dpp, uint32_t freq);
-
-static void dpp_offchannel_timeout(int error, void *user_data)
-{
- struct dpp_sm *dpp = user_data;
-
- dpp->offchannel_id = 0;
- dpp->roc_started = false;
-
- /*
- * If cancelled this is likely due to netdev going down or from Stop().
- * Otherwise there was some other problem which is probably not
- * recoverable.
- */
- if (error == -ECANCELED)
- return;
- else if (error == -EIO)
- goto next_roc;
- else if (error < 0)
- goto protocol_failed;
-
- switch (dpp->state) {
- case DPP_STATE_PKEX_EXCHANGE:
- if (dpp->role != DPP_CAPABILITY_CONFIGURATOR || !dpp->agent)
- break;
-
- /*
- * We have a pending agent request but it did not arrive in
- * time, we cant assume the enrollee will be waiting around
- * for our response so cancel the request and continue waiting
- * for another request
- */
- if (dpp->agent->pending_id) {
- dpp_free_pending_pkex_data(dpp);
- dpp_agent_cancel(dpp);
- }
- /* Fall through */
- case DPP_STATE_PRESENCE:
- break;
- case DPP_STATE_NOTHING:
- /* Protocol already terminated */
- return;
- case DPP_STATE_AUTHENTICATING:
- case DPP_STATE_CONFIGURING:
- case DPP_STATE_PKEX_COMMIT_REVEAL:
- goto next_roc;
- }
-
- dpp->freqs_idx++;
-
- if (dpp->freqs_idx >= dpp->freqs_len) {
- l_debug("Max retries offchannel");
- dpp->freqs_idx = 0;
- }
-
- dpp->current_freq = dpp->freqs[dpp->freqs_idx];
-
- l_debug("Offchannel timeout, moving to next frequency %u, duration %u",
- dpp->current_freq, dpp->dwell);
-
-next_roc:
- dpp_start_offchannel(dpp, dpp->current_freq);
-
- return;
-
-protocol_failed:
- dpp_reset(dpp);
-}
-
-static void dpp_start_offchannel(struct dpp_sm *dpp, uint32_t freq)
-{
- /*
- * This needs to be handled carefully for a few reasons:
- *
- * First, the next offchannel operation needs to be started prior to
- * canceling an existing one. This is so the offchannel work can
- * continue uninterrupted without any other work items starting in
- * between canceling and starting the next (e.g. if a scan request is
- * sitting in the queue).
- *
- * Second, dpp_offchannel_timeout resets dpp->offchannel_id to zero
- * which is why the new ID is saved and only set to dpp->offchannel_id
- * once the previous offchannel work is cancelled (i.e. destroy() has
- * been called).
- */
- uint32_t id = offchannel_start(netdev_get_wdev_id(dpp->netdev),
- WIPHY_WORK_PRIORITY_OFFCHANNEL,
- freq, dpp->dwell, dpp_roc_started,
- dpp, dpp_offchannel_timeout);
-
- if (dpp->offchannel_id)
- offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
-
- dpp->offchannel_id = id;
-}
-
-static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const uint8_t *r_boot = NULL;
- const uint8_t *i_boot = NULL;
- const uint8_t *i_proto = NULL;
- const void *wrapped = NULL;
- const uint8_t *i_nonce = NULL;
- uint8_t i_capa = 0;
- size_t r_boot_len = 0, i_proto_len = 0, wrapped_len = 0;
- size_t i_nonce_len = 0;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- _auto_(l_ecc_scalar_free) struct l_ecc_scalar *m = NULL;
- _auto_(l_ecc_scalar_free) struct l_ecc_scalar *n = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL;
- struct l_ecc_point *bi = NULL;
- uint64_t k1[L_ECC_MAX_DIGITS];
- const void *ad0 = body + 2;
- const void *ad1 = body + 8;
- uint32_t freq;
-
- if (util_is_broadcast_address(from))
- return;
-
- if (dpp->state != DPP_STATE_PRESENCE &&
- dpp->state != DPP_STATE_AUTHENTICATING)
- return;
-
- l_debug("authenticate request");
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_INITIATOR_BOOT_KEY_HASH:
- i_boot = data;
- /*
- * This attribute is required by the spec, but only
- * used for mutual authentication.
- */
- break;
- case DPP_ATTR_RESPONDER_BOOT_KEY_HASH:
- r_boot = data;
- r_boot_len = len;
- break;
- case DPP_ATTR_INITIATOR_PROTOCOL_KEY:
- i_proto = data;
- i_proto_len = len;
- break;
- case DPP_ATTR_WRAPPED_DATA:
- /* I-Nonce/I-Capabilities part of wrapped data */
- wrapped = data;
- wrapped_len = len;
- break;
-
- /* Optional attributes */
- case DPP_ATTR_PROTOCOL_VERSION:
- if (l_get_u8(data) != 2) {
- l_debug("Protocol version did not match");
- return;
- }
-
- break;
-
- case DPP_ATTR_CHANNEL:
- if (len != 2)
- return;
-
- freq = oci_to_frequency(l_get_u8(data),
- l_get_u8(data + 1));
-
- if (freq == dpp->current_freq)
- break;
-
- /*
- * Configurators are already connected to a network, so
- * to preserve wireless performance the enrollee will
- * be required to be on this channel, not a channel it
- * requests.
- */
- if (dpp->role == DPP_CAPABILITY_CONFIGURATOR)
- return;
-
- /*
- * Otherwise, as an enrollee, we can jump to whatever
- * channel the configurator requests
- */
- dpp->new_freq = freq;
-
- l_debug("Configurator requested a new frequency %u",
- dpp->new_freq);
-
- dpp_start_offchannel(dpp, dpp->new_freq);
-
- break;
- default:
- break;
- }
- }
-
- if (!r_boot || !i_boot || !i_proto || !wrapped)
- goto auth_request_failed;
-
- if (r_boot_len != 32 || memcmp(dpp->own_boot_hash,
- r_boot, r_boot_len)) {
- l_debug("Responder boot key hash failed to verify");
- goto auth_request_failed;
- }
-
- dpp->peer_proto_public = l_ecc_point_from_data(dpp->curve,
- L_ECC_POINT_TYPE_FULL,
- i_proto, i_proto_len);
- if (!dpp->peer_proto_public) {
- l_debug("Initiators protocol key invalid");
- goto auth_request_failed;
- }
-
- m = dpp_derive_k1(dpp->peer_proto_public, dpp->boot_private, k1);
- if (!m)
- goto auth_request_failed;
-
- unwrapped = dpp_unwrap_attr(ad0, 6, ad1, wrapped - 4 - ad1,
- k1, dpp->key_len, wrapped, wrapped_len, &wrapped_len);
- if (!unwrapped)
- goto auth_request_failed;
-
- dpp_attr_iter_init(&iter, unwrapped, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_INITIATOR_NONCE:
- i_nonce = data;
- i_nonce_len = len;
- break;
- case DPP_ATTR_INITIATOR_CAPABILITIES:
- /*
- * "If the Responder is not capable of supporting the
- * role indicated by the Initiator, it shall respond
- * with a DPP Authentication Response frame indicating
- * failure by adding the DPP Status field set to
- * STATUS_NOT_COMPATIBLE"
- */
- i_capa = l_get_u8(data);
-
- if (!dpp_check_roles(dpp, i_capa)) {
- l_debug("Peer does not support required role");
- dpp_auth_request_failed(dpp,
- DPP_STATUS_NOT_COMPATIBLE, k1);
- goto auth_request_failed;
- }
-
- break;
- default:
- break;
- }
- }
-
- if (i_nonce_len != dpp->nonce_len) {
- l_debug("I-Nonce has unexpected length %zu", i_nonce_len);
- goto auth_request_failed;
- }
-
- memcpy(dpp->i_nonce, i_nonce, i_nonce_len);
-
- if (dpp->mutual_auth) {
- l = dpp_derive_lr(dpp->boot_private, dpp->proto_private,
- dpp->peer_boot_public);
- bi = dpp->peer_boot_public;
- }
-
- /* Derive keys k2, ke, and R-Auth for authentication response */
-
- n = dpp_derive_k2(dpp->peer_proto_public, dpp->proto_private, dpp->k2);
- if (!n)
- goto auth_request_failed;
-
- l_getrandom(dpp->r_nonce, dpp->nonce_len);
-
- if (!dpp_derive_ke(dpp->i_nonce, dpp->r_nonce, m, n, l, dpp->ke))
- goto auth_request_failed;
-
- if (!dpp_derive_r_auth(dpp->i_nonce, dpp->r_nonce, dpp->nonce_len,
- dpp->peer_proto_public, dpp->own_proto_public,
- bi, dpp->boot_public, dpp->auth_tag))
- goto auth_request_failed;
-
- memcpy(dpp->peer_addr, from, 6);
-
- dpp->state = DPP_STATE_AUTHENTICATING;
- dpp_reset_protocol_timer(dpp, DPP_AUTH_PROTO_TIMEOUT);
-
- /* Don't send if the frequency is changing */
- if (!dpp->new_freq)
- send_authenticate_response(dpp);
-
- return;
-
-auth_request_failed:
- dpp->state = DPP_STATE_PRESENCE;
- dpp_free_auth_data(dpp);
-}
-
-static void dpp_send_authenticate_confirm(struct dpp_sm *dpp)
-{
- struct iovec iov;
- uint8_t frame[256];
- uint8_t *ptr = frame;
- uint8_t zero = 0;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
-
- memset(frame, 0, sizeof(frame));
-
- ptr += dpp_build_header(netdev_get_address(dpp->netdev),
- dpp->peer_addr,
- DPP_FRAME_AUTHENTICATION_CONFIRM, ptr);
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &zero, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH,
- dpp->peer_boot_hash, 32);
- if (dpp->mutual_auth)
- ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
- dpp->own_boot_hash, 32);
-
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->ke, dpp->key_len, 1,
- DPP_ATTR_INITIATOR_AUTH_TAG, dpp->key_len,
- dpp->auth_tag);
-
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
-
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
-
-static void authenticate_response(struct dpp_sm *dpp, const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- int status = -1;
- const void *r_boot_hash = NULL;
- const void *r_proto = NULL;
- size_t r_proto_len = 0;
- const void *wrapped = NULL;
- size_t wrapped_len;
- _auto_(l_free) uint8_t *unwrapped1 = NULL;
- _auto_(l_free) uint8_t *unwrapped2 = NULL;
- const void *r_nonce = NULL;
- const void *i_nonce = NULL;
- const void *r_auth = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *r_proto_key = NULL;
- _auto_(l_ecc_scalar_free) struct l_ecc_scalar *n = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL;
- struct l_ecc_point *bi = NULL;
- const void *ad0 = body + 2;
- const void *ad1 = body + 8;
- uint64_t r_auth_derived[L_ECC_MAX_DIGITS];
-
- l_debug("Authenticate response");
-
- if (dpp->state != DPP_STATE_AUTHENTICATING)
- return;
-
- if (!dpp->freqs)
- return;
-
- if (memcmp(from, dpp->peer_addr, 6))
- return;
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_STATUS:
- if (len != 1)
- return;
-
- status = l_get_u8(data);
- break;
- case DPP_ATTR_RESPONDER_BOOT_KEY_HASH:
- r_boot_hash = data;
- break;
- case DPP_ATTR_RESPONDER_PROTOCOL_KEY:
- r_proto = data;
- r_proto_len = len;
- break;
- case DPP_ATTR_PROTOCOL_VERSION:
- if (len != 1 || l_get_u8(data) != 2)
- return;
- break;
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- break;
- }
- }
-
- if (status != DPP_STATUS_OK || !r_boot_hash || !r_proto || !wrapped) {
- l_debug("Auth response bad status or missing attributes");
- return;
- }
-
- r_proto_key = l_ecc_point_from_data(dpp->curve, L_ECC_POINT_TYPE_FULL,
- r_proto, r_proto_len);
- if (!r_proto_key) {
- l_debug("Peers protocol key was invalid");
- return;
- }
-
- n = dpp_derive_k2(r_proto_key, dpp->proto_private, dpp->k2);
-
- unwrapped1 = dpp_unwrap_attr(ad0, 6, ad1, wrapped - 4 - ad1, dpp->k2,
- dpp->key_len, wrapped, wrapped_len,
- &wrapped_len);
- if (!unwrapped1) {
- l_debug("Failed to unwrap primary data");
- return;
- }
-
- wrapped = NULL;
-
- dpp_attr_iter_init(&iter, unwrapped1, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_RESPONDER_NONCE:
- if (len != dpp->nonce_len)
- return;
-
- r_nonce = data;
- break;
- case DPP_ATTR_INITIATOR_NONCE:
- if (len != dpp->nonce_len)
- return;
-
- i_nonce = data;
- break;
- case DPP_ATTR_RESPONDER_CAPABILITIES:
- break;
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!r_nonce || !i_nonce || !wrapped) {
- l_debug("Wrapped data missing attributes");
- return;
- }
-
- if (dpp->mutual_auth) {
- l = dpp_derive_li(dpp->peer_boot_public, r_proto_key,
- dpp->boot_private);
- bi = dpp->boot_public;
- }
-
- if (!dpp_derive_ke(i_nonce, r_nonce, dpp->m, n, l, dpp->ke)) {
- l_debug("Failed to derive ke");
- return;
- }
-
- unwrapped2 = dpp_unwrap_attr(NULL, 0, NULL, 0, dpp->ke, dpp->key_len,
- wrapped, wrapped_len, &wrapped_len);
- if (!unwrapped2) {
- l_debug("Failed to unwrap secondary data");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped2, wrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_RESPONDER_AUTH_TAG:
- if (len != dpp->key_len)
- return;
-
- r_auth = data;
- break;
- default:
- break;
- }
- }
-
- if (!r_auth) {
- l_debug("R-Auth was not in secondary wrapped data");
- return;
- }
-
- if (!dpp_derive_r_auth(i_nonce, r_nonce, dpp->nonce_len,
- dpp->own_proto_public, r_proto_key, bi,
- dpp->peer_boot_public, r_auth_derived)) {
- l_debug("Failed to derive r_auth");
- return;
- }
-
- if (memcmp(r_auth, r_auth_derived, dpp->key_len)) {
- l_debug("R-Auth did not verify");
- return;
- }
-
- if (!dpp_derive_i_auth(r_nonce, i_nonce, dpp->nonce_len,
- r_proto_key, dpp->own_proto_public,
- dpp->peer_boot_public, bi, dpp->auth_tag)) {
- l_debug("Could not derive I-Auth");
- return;
- }
-
- dpp->channel_switch = false;
- dpp->current_freq = dpp->new_freq;
-
- dpp_send_authenticate_confirm(dpp);
-
- if (dpp->role == DPP_CAPABILITY_ENROLLEE)
- dpp_configuration_start(dpp, from);
-
-}
-
-static void dpp_handle_presence_announcement(struct dpp_sm *dpp,
- const uint8_t *from,
- const uint8_t *body,
- size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const void *r_boot = NULL;
- size_t r_boot_len = 0;
- uint8_t hash[32];
-
- l_debug("Presence announcement "MAC, MAC_STR(from));
-
- /* Must be a configurator, in an initiator role, in PRESENCE state */
- if (dpp->state != DPP_STATE_PRESENCE)
- return;
-
- if (dpp->role != DPP_CAPABILITY_CONFIGURATOR)
- return;
-
- if (!dpp->freqs)
- return;
-
- /*
- * The URI may not have contained a MAC address, if this announcement
- * verifies set peer_addr then.
- */
- if (!l_memeqzero(dpp->peer_addr, 6) &&
- memcmp(from, dpp->peer_addr, 6)) {
- l_debug("Unexpected source "MAC" expected "MAC, MAC_STR(from),
- MAC_STR(dpp->peer_addr));
- return;
- }
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_RESPONDER_BOOT_KEY_HASH:
- r_boot = data;
- r_boot_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!r_boot || r_boot_len != 32) {
- l_debug("No responder boot hash");
- return;
- }
-
- /* Hash what we have for the peer and check its our enrollee */
- dpp_hash(L_CHECKSUM_SHA256, hash, 2, "chirp", strlen("chirp"),
- dpp->peer_asn1, dpp->peer_asn1_len);
-
- if (memcmp(hash, r_boot, sizeof(hash))) {
- l_debug("Peers boot hash did not match");
- return;
- }
-
- /*
- * This is the peer we expected, save away the address and derive the
- * initial keys.
- */
- memcpy(dpp->peer_addr, from, 6);
-
- dpp->state = DPP_STATE_AUTHENTICATING;
-
- if (!dpp_send_authenticate_request(dpp))
- return;
-
- /*
- * Requested the peer to move to another channel for the remainder of
- * the protocol. IWD's current logic prohibits a configurator from
- * running while not connected, so we can assume here that the new
- * frequency is the same of the connected BSS. Wait until an ACK is
- * received for the auth request then cancel the offchannel request.
- */
- if (dpp->current_freq != dpp->new_freq)
- dpp->channel_switch = true;
-}
-
-static void dpp_pkex_bad_group(struct dpp_sm *dpp, uint16_t group)
-{
- uint16_t own_group = l_ecc_curve_get_ike_group(dpp->curve);
-
- /*
- * TODO: The spec allows group negotiation, but it is not yet
- * implemented.
- */
- if (!group)
- return;
- /*
- * Section 5.6.2
- * "If the Responder's offered group offers less security
- * than the Initiator's offered group, then the Initiator should
- * ignore this message"
- */
- if (group < own_group) {
- l_debug("Offered group %u is less secure, ignoring",
- group);
- return;
- }
- /*
- * Section 5.6.2
- * "If the Responder's offered group offers equivalent or better
- * security than the Initiator's offered group, then the
- * Initiator may choose to abort its original request and try
- * another exchange using the group offered by the Responder"
- */
- if (group >= own_group) {
- l_debug("Offered group %u is the same or more secure, "
- " but group negotiation is not supported", group);
- return;
- }
-}
-
-static void dpp_pkex_bad_code(struct dpp_sm *dpp)
-{
- _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL;
-
- qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id,
- netdev_get_address(dpp->netdev));
- if (!qr || l_ecc_point_is_infinity(qr)) {
- l_debug("Qr computed to zero, new code should be provisioned");
- return;
- }
-
- l_debug("Qr computed successfully but responder indicated otherwise");
-}
-
-static void dpp_handle_pkex_exchange_response(struct dpp_sm *dpp,
- const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const uint8_t *status = NULL;
- uint8_t version = 0;
- const void *identifier = NULL;
- size_t identifier_len = 0;
- const void *key = NULL;
- size_t key_len = 0;
- uint16_t group = 0;
- _auto_(l_ecc_point_free) struct l_ecc_point *n = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *j = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *k = NULL;
- const uint8_t *own_addr = netdev_get_address(dpp->netdev);
-
- l_debug("PKEX response "MAC, MAC_STR(from));
-
- if (dpp->state != DPP_STATE_PKEX_EXCHANGE)
- return;
-
- if (dpp->role != DPP_CAPABILITY_ENROLLEE)
- return;
-
- memcpy(dpp->peer_addr, from, 6);
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_STATUS:
- if (len != 1)
- return;
-
- status = data;
- break;
- case DPP_ATTR_PROTOCOL_VERSION:
- if (len != 1)
- return;
-
- version = l_get_u8(data);
- break;
- case DPP_ATTR_CODE_IDENTIFIER:
- identifier = data;
- identifier_len = len;
- break;
- case DPP_ATTR_ENCRYPTED_KEY:
- if (len != dpp->key_len * 2)
- return;
-
- key = data;
- key_len = len;
- break;
- case DPP_ATTR_FINITE_CYCLIC_GROUP:
- if (len != 2)
- return;
-
- group = l_get_le16(data);
- break;
- default:
- break;
- }
- }
-
- if (!status) {
- l_debug("No status attribute, ignoring");
- return;
- }
-
- if (!key) {
- l_debug("No encrypted key, ignoring");
- return;
- }
-
- if (*status != DPP_STATUS_OK)
- goto handle_status;
-
- if (dpp->pkex_id) {
- if (!identifier || identifier_len != strlen(dpp->pkex_id) ||
- memcmp(dpp->pkex_id, identifier,
- identifier_len)) {
- l_debug("mismatch identifier, ignoring");
- return;
- }
- }
-
- if (version && version != dpp->pkex_version) {
- l_debug("PKEX version does not match, igoring");
- return;
- }
-
- n = l_ecc_point_from_data(dpp->curve, L_ECC_POINT_TYPE_FULL,
- key, key_len);
- if (!n) {
- l_debug("failed to parse peers encrypted key");
- goto failed;
- }
-
- qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id,
- dpp->peer_addr);
- if (!qr)
- goto failed;
-
- dpp->y_or_x = l_ecc_point_new(dpp->curve);
-
- /* Y' = N - Qr */
- l_ecc_point_inverse(qr);
- l_ecc_point_add(dpp->y_or_x, n, qr);
-
- /*
- * "The resulting ephemeral key, denoted Y’, is then checked whether it
- * is the point-at-infinity. If it is not valid, the protocol ends
- * unsuccessfully"
- */
- if (l_ecc_point_is_infinity(dpp->y_or_x)) {
- l_debug("Y' computed to infinity, failing");
- goto failed;
- }
-
- k = l_ecc_point_new(dpp->curve);
-
- /* K = Y' * x */
- l_ecc_point_multiply(k, dpp->pkex_private, dpp->y_or_x);
-
- dpp_derive_z(own_addr, dpp->peer_addr, n, dpp->pkex_m, k,
- dpp->pkex_key, dpp->pkex_id,
- dpp->z, &dpp->z_len);
-
- /* J = a * Y' */
- j = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_multiply(j, dpp->boot_private, dpp->y_or_x);
-
- if (!dpp_derive_u(j, own_addr, dpp->boot_public, dpp->y_or_x,
- dpp->pkex_public, dpp->u, &dpp->u_len)) {
- l_debug("failed to compute u");
- goto failed;
- }
-
- /*
- * Now that a response was successfully received, start another
- * offchannel with more time for the remainder of the protocol. After
- * PKEX, authentication will begin which handles the protocol timeout.
- * If the remainder of PKEX (commit-reveal exchange) cannot complete in
- * this time it will fail.
- */
- dpp->dwell = (dpp->max_roc < 2000) ? dpp->max_roc : 2000;
- dpp->state = DPP_STATE_PKEX_COMMIT_REVEAL;
-
- dpp_property_changed_notify(dpp);
-
- dpp_start_offchannel(dpp, dpp->current_freq);
-
- return;
-
-handle_status:
- switch (*status) {
- case DPP_STATUS_BAD_GROUP:
- dpp_pkex_bad_group(dpp, group);
- break;
- case DPP_STATUS_BAD_CODE:
- dpp_pkex_bad_code(dpp);
- break;
- default:
- l_debug("Unhandled status %u", *status);
- break;
- }
-
-failed:
- dpp_reset(dpp);
-}
-
-static bool dpp_pkex_start_authentication(struct dpp_sm *dpp)
-{
- dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2,
- netdev_get_address(dpp->netdev),
- &dpp->current_freq, 1, NULL, NULL);
-
- l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private,
- &dpp->own_proto_public);
-
- l_getrandom(dpp->i_nonce, dpp->nonce_len);
-
- dpp->peer_asn1 = dpp_point_to_asn1(dpp->peer_boot_public,
- &dpp->peer_asn1_len);
-
- dpp->m = dpp_derive_k1(dpp->peer_boot_public, dpp->proto_private,
- dpp->k1);
-
- dpp_hash(L_CHECKSUM_SHA256, dpp->peer_boot_hash, 1, dpp->peer_asn1,
- dpp->peer_asn1_len);
-
- dpp->state = DPP_STATE_AUTHENTICATING;
- dpp->mutual_auth = true;
-
- dpp_property_changed_notify(dpp);
-
- if (dpp->role == DPP_CAPABILITY_ENROLLEE) {
- dpp->new_freq = dpp->current_freq;
-
- return dpp_send_authenticate_request(dpp);
- }
-
- return true;
-}
-
-static void dpp_handle_pkex_commit_reveal_response(struct dpp_sm *dpp,
- const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const uint8_t *wrapped = NULL;
- size_t wrapped_len = 0;
- uint8_t one = 1;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- size_t unwrapped_len = 0;
- const uint8_t *boot_key = NULL;
- size_t boot_key_len = 0;
- const uint8_t *r_auth = NULL;
- uint8_t v[L_ECC_SCALAR_MAX_BYTES];
- size_t v_len;
- _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL;
-
- l_debug("PKEX commit reveal "MAC, MAC_STR(from));
-
- if (dpp->state != DPP_STATE_PKEX_COMMIT_REVEAL)
- return;
-
- if (dpp->role != DPP_CAPABILITY_ENROLLEE)
- return;
-
- /*
- * The URI may not have contained a MAC address, if this announcement
- * verifies set peer_addr then.
- */
- if (memcmp(from, dpp->peer_addr, 6)) {
- l_debug("Unexpected source "MAC" expected "MAC, MAC_STR(from),
- MAC_STR(dpp->peer_addr));
- return;
- }
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!wrapped) {
- l_debug("No wrapped data");
- return;
- }
-
- unwrapped = dpp_unwrap_attr(body + 2, 6, &one, 1, dpp->z, dpp->z_len,
- wrapped, wrapped_len, &unwrapped_len);
- if (!unwrapped) {
- l_debug("Failed to unwrap Reveal-Commit message");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, unwrapped_len);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_BOOTSTRAPPING_KEY:
- if (len != dpp->key_len * 2)
- return;
-
- boot_key = data;
- boot_key_len = len;
- break;
- case DPP_ATTR_RESPONDER_AUTH_TAG:
- if (len != 32)
- return;
-
- r_auth = data;
- break;
- default:
- break;
- }
- }
-
- dpp->peer_boot_public = l_ecc_point_from_data(dpp->curve,
- L_ECC_POINT_TYPE_FULL,
- boot_key, boot_key_len);
- if (!dpp->peer_boot_public) {
- l_debug("Peer public bootstrapping key was invalid");
- goto failed;
- }
-
- /* L = b * X' */
- l = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_multiply(l, dpp->pkex_private, dpp->peer_boot_public);
-
- if (!dpp_derive_v(l, dpp->peer_addr, dpp->peer_boot_public,
- dpp->pkex_public, dpp->y_or_x, v, &v_len)) {
- l_debug("Failed to derive v");
- goto failed;
- }
-
- if (memcmp(v, r_auth, v_len)) {
- l_debug("Bootstrapping data did not verify");
- goto failed;
- }
-
- if (dpp_pkex_start_authentication(dpp))
- return;
-
-failed:
- dpp_reset(dpp);
-}
-
-static void dpp_send_bad_group(struct dpp_sm *dpp, const uint8_t *addr)
-{
- uint8_t hdr[32];
- uint8_t attrs[256];
- uint8_t *ptr = attrs;
- uint16_t group;
- uint8_t status = DPP_STATUS_BAD_GROUP;
- struct iovec iov[2];
- const uint8_t *own_mac = netdev_get_address(dpp->netdev);
-
- l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group);
-
- iov[0].iov_len = dpp_build_header(own_mac, addr,
- DPP_FRAME_PKEX_XCHG_RESPONSE, hdr);
- iov[0].iov_base = hdr;
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION,
- &dpp->pkex_version, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_FINITE_CYCLIC_GROUP, &group, 2);
-
- iov[1].iov_base = attrs;
- iov[1].iov_len = ptr - attrs;
-
- dpp_send_frame(dpp, iov, 2, dpp->current_freq);
-}
-
-static void dpp_send_bad_code(struct dpp_sm *dpp, const uint8_t *addr)
-{
- uint8_t hdr[32];
- uint8_t attrs[256];
- uint8_t *ptr = attrs;
- uint8_t status = DPP_STATUS_BAD_CODE;
- struct iovec iov[2];
- const uint8_t *own_mac = netdev_get_address(dpp->netdev);
-
- iov[0].iov_len = dpp_build_header(own_mac, addr,
- DPP_FRAME_PKEX_XCHG_RESPONSE, hdr);
- iov[0].iov_base = hdr;
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
- ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION,
- &dpp->pkex_version, 1);
- if (dpp->pkex_id)
- ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER,
- dpp->pkex_id, strlen(dpp->pkex_id));
-
- iov[1].iov_base = attrs;
- iov[1].iov_len = ptr - attrs;
-
- dpp_send_frame(dpp, iov, 2, dpp->current_freq);
-}
-
-static void dpp_send_pkex_exchange_response(struct dpp_sm *dpp,
- struct l_ecc_point *n)
-{
- uint8_t hdr[32];
- uint8_t attrs[256];
- uint8_t *ptr = attrs;
- uint16_t group;
- uint8_t status = DPP_STATUS_OK;
- struct iovec iov[2];
- const uint8_t *own_mac = netdev_get_address(dpp->netdev);
-
- l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group);
-
- iov[0].iov_len = dpp_build_header(own_mac, dpp->peer_addr,
- DPP_FRAME_PKEX_XCHG_RESPONSE, hdr);
- iov[0].iov_base = hdr;
-
- ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
-
- if (dpp->pkex_id)
- ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER,
- dpp->pkex_id, strlen(dpp->pkex_id));
-
- ptr += dpp_append_point(ptr, DPP_ATTR_ENCRYPTED_KEY, n);
-
- iov[1].iov_base = attrs;
- iov[1].iov_len = ptr - attrs;
-
- dpp->state = DPP_STATE_PKEX_COMMIT_REVEAL;
-
- dpp_property_changed_notify(dpp);
-
- dpp_send_frame(dpp, iov, 2, dpp->current_freq);
-}
-
-static void dpp_process_pkex_exchange_request(struct dpp_sm *dpp,
- struct l_ecc_point *m)
-{
- _auto_(l_ecc_point_free) struct l_ecc_point *n = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *k = NULL;
- const uint8_t *own_addr = netdev_get_address(dpp->netdev);
-
- /* Qi = H(MAC-Initiator | [identifier | ] code) * Pi */
- qi = dpp_derive_qi(dpp->curve, dpp->pkex_key, dpp->pkex_id,
- dpp->peer_addr);
- if (!qi) {
- l_debug("could not derive Qi");
- return;
- }
-
- /* X' = M - Qi */
- dpp->y_or_x = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_inverse(qi);
- l_ecc_point_add(dpp->y_or_x, m, qi);
-
- /*
- * "The resulting ephemeral key, denoted X’, is checked whether it is
- * the point-at-infinity. If it is not valid, the protocol silently
- * fails"
- */
- if (l_ecc_point_is_infinity(dpp->y_or_x)) {
- l_debug("X' is at infinity, ignore message");
- dpp_reset(dpp);
- return;
- }
-
- qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id, own_addr);
- if (!qr || l_ecc_point_is_infinity(qr)) {
- l_debug("Qr did not derive");
- l_ecc_point_free(dpp->y_or_x);
- dpp->y_or_x = NULL;
- goto bad_code;
- }
-
- /*
- * "The Responder then generates a random ephemeral keypair, y/Y,
- * encrypts Y with Qr to obtain the result, denoted N."
- */
- l_ecdh_generate_key_pair(dpp->curve, &dpp->pkex_private,
- &dpp->pkex_public);
-
- /* N = Y + Qr */
- n = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_add(n, dpp->pkex_public, qr);
-
- /* K = y * X' */
-
- k = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_multiply(k, dpp->pkex_private, dpp->y_or_x);
-
- /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
- dpp_derive_z(dpp->peer_addr, own_addr, n, m, k, dpp->pkex_key,
- dpp->pkex_id, dpp->z, &dpp->z_len);
-
- dpp_send_pkex_exchange_response(dpp, n);
-
- return;
-
-bad_code:
- dpp_send_bad_code(dpp, dpp->peer_addr);
- return;
-}
-
-static void dpp_pkex_agent_reply(struct l_dbus_message *message,
- void *user_data)
-{
- struct dpp_sm *dpp = user_data;
- const char *error, *text;
- const char *code;
-
- dpp->agent->pending_id = 0;
-
- l_debug("SharedCodeAgent %s path %s replied", dpp->agent->owner,
- dpp->agent->path);
-
- if (l_dbus_message_get_error(message, &error, &text)) {
- l_error("RequestSharedCode(%s) returned %s(\"%s\")",
- dpp->pkex_id, error, text);
- goto reset;
- }
-
- if (!l_dbus_message_get_arguments(message, "s", &code)) {
- l_debug("Invalid arguments, check SharedCodeAgent!");
- goto reset;
- }
-
- dpp->pkex_key = l_strdup(code);
- dpp_process_pkex_exchange_request(dpp, dpp->peer_encr_key);
-
- return;
-
-reset:
- dpp_free_pending_pkex_data(dpp);
-}
-
-static bool dpp_pkex_agent_request(struct dpp_sm *dpp)
-{
- struct l_dbus_message *msg;
-
- if (!dpp->agent)
- return false;
-
- if (L_WARN_ON(dpp->agent->pending_id))
- return false;
-
- msg = l_dbus_message_new_method_call(dbus_get_bus(),
- dpp->agent->owner,
- dpp->agent->path,
- IWD_SHARED_CODE_AGENT_INTERFACE,
- "RequestSharedCode");
- l_dbus_message_set_arguments(msg, "s", dpp->pkex_id);
-
-
- dpp->agent->pending_id = l_dbus_send_with_reply(dbus_get_bus(),
- msg,
- dpp_pkex_agent_reply,
- dpp, NULL);
- return dpp->agent->pending_id != 0;
-}
-
-static void dpp_handle_pkex_exchange_request(struct dpp_sm *dpp,
- const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- uint8_t version = 0;
- uint16_t group = 0;
- const void *id = NULL;
- size_t id_len = 0;
- const void *key = NULL;
- size_t key_len = 0;
- _auto_(l_ecc_point_free) struct l_ecc_point *m = NULL;
-
- l_debug("PKEX exchange request "MAC, MAC_STR(from));
-
- if (dpp->state != DPP_STATE_PKEX_EXCHANGE)
- return;
-
- if (dpp->role != DPP_CAPABILITY_CONFIGURATOR)
- return;
-
- if (!l_memeqzero(dpp->peer_addr, 6)) {
- l_debug("Already configuring enrollee, ignoring");
- return;
- }
-
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
-
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_PROTOCOL_VERSION:
- if (len != 1)
- return;
-
- version = l_get_u8(data);
- break;
- case DPP_ATTR_FINITE_CYCLIC_GROUP:
- if (len != 2)
- return;
-
- group = l_get_le16(data);
- break;
- case DPP_ATTR_CODE_IDENTIFIER:
- id = data;
- id_len = len;
- break;
- case DPP_ATTR_ENCRYPTED_KEY:
- key = data;
- key_len = len;
- break;
- default:
- break;
- }
- }
-
- if (!key || !group) {
- l_debug("initiator did not provide group or key, ignoring");
- return;
- }
+ struct scan_bss *bss;
+ struct network *network;
+ int ret;
- if (group != l_ecc_curve_get_ike_group(dpp->curve)) {
- l_debug("initiator is not using the same group");
- goto bad_group;
- }
+ network = station_network_find(station, dpp->config->ssid,
+ SECURITY_PSK);
- /*
- * If the group isn't the same the key length won't match, so check
- * this here after we've determined the groups are equal
- */
- if (key_len != dpp->key_len * 2) {
- l_debug("Unexpected encrypted key length");
- return;
- }
+ dpp_reset(dpp);
- if (version && version != dpp->pkex_version) {
- l_debug("initiator is not using the same version, ignoring");
+ if (!network) {
+ l_debug("Network was not found!");
return;
}
- if (dpp->pkex_id) {
- if (!id || id_len != strlen(dpp->pkex_id) ||
- memcmp(dpp->pkex_id, id, id_len)) {
- l_debug("mismatch identifier, ignoring");
- return;
- }
- }
+ l_debug("connecting to %s from DPP", network_get_ssid(network));
- m = l_ecc_point_from_data(dpp->curve, L_ECC_POINT_TYPE_FULL,
- key, key_len);
- if (!m) {
- l_debug("could not parse key from initiator, ignoring");
- return;
- }
+ bss = network_bss_select(network, true);
+ ret = network_autoconnect(network, bss);
+ if (ret < 0)
+ l_warn("failed to connect after DPP (%d) %s", ret,
+ strerror(-ret));
+}
- memcpy(dpp->peer_addr, from, 6);
+static bool dpp_scan_results(int err, struct l_queue *bss_list,
+ const struct scan_freq_set *freqs,
+ void *userdata)
+{
+ struct dpp *dpp = userdata;
+ struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
- if (!dpp->pkex_key) {
- /*
- * "If an optional code identifier is used, it shall be a UTF-8
- * string not greater than eighty (80) octets"
- */
- if (!id || id_len > 80 || !l_utf8_validate(id, id_len, NULL)) {
- l_debug("Configurator started with agent but enrollee "
- "sent invalid or no identifier, ignoring");
- return;
- }
+ if (err < 0)
+ goto reset;
- dpp->pkex_id = l_strndup(id, id_len);
+ if (!bss_list || l_queue_length(bss_list) == 0)
+ goto reset;
- /* Need to obtain code from agent */
- if (!dpp_pkex_agent_request(dpp)) {
- l_debug("Failed to request code from agent!");
- dpp_free_pending_pkex_data(dpp);
- return;
- }
+ /*
+ * The station watch _should_ detect this and reset, which cancels the
+ * scan. But just in case...
+ */
+ if (L_WARN_ON(station_get_connected_network(station)))
+ goto reset;
- /* Save the encrypted key/identifier for the agent callback */
+ station_set_scan_results(station, bss_list, freqs, false);
- dpp->peer_encr_key = l_steal_ptr(m);
+ dpp_start_connect(NULL, dpp);
- return;
- }
+ return true;
- dpp_process_pkex_exchange_request(dpp, m);
+reset:
+ return false;
+}
- return;
+static void dpp_scan_destroy(void *userdata)
+{
+ struct dpp *dpp = userdata;
-bad_group:
- dpp_send_bad_group(dpp, from);
+ dpp->connect_scan_id = 0;
+ dpp_reset(dpp);
}
-static void dpp_send_commit_reveal_response(struct dpp_sm *dpp,
- const uint8_t *v, size_t v_len)
+static void dpp_known_network_watch(enum known_networks_event event,
+ const struct network_info *info,
+ void *user_data)
{
- uint8_t frame[256];
- uint8_t *ptr = frame;
- struct iovec iov;
- const uint8_t *own_mac = netdev_get_address(dpp->netdev);
- uint8_t b_pub[L_ECC_POINT_MAX_BYTES];
- size_t b_len;
- struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
+ struct dpp *dpp = user_data;
- memset(frame, 0, sizeof(frame));
+ /*
+ * Check the following
+ * - DPP is enrolling
+ * - DPP finished (dpp->config is set)
+ * - This is for the network DPP just configured
+ * - DPP isn't already trying to connect (e.g. if the profile was
+ * immediately modified after DPP synced it).
+ * - DPP didn't start a scan for the network.
+ */
+ if (dpp->role != DPP_CAPABILITY_ENROLLEE)
+ return;
+ if (!dpp->config)
+ return;
+ if (strcmp(info->ssid, dpp->config->ssid))
+ return;
+ if (dpp->connect_idle)
+ return;
+ if (dpp->connect_scan_id)
+ return;
- b_len = l_ecc_point_get_data(dpp->boot_public, b_pub, sizeof(b_pub));
+ switch (event) {
+ case KNOWN_NETWORKS_EVENT_ADDED:
+ case KNOWN_NETWORKS_EVENT_UPDATED:
+ /*
+ * network.c takes care of updating the settings for the
+ * network. This callback just tells us to begin the connection.
+ * We do have use an idle here because there is no strict
+ * guarantee of ordering between known network events, e.g. DPP
+ * could have been called into prior to network and the network
+ * object isn't updated yet.
+ */
+ dpp->connect_idle = l_idle_create(dpp_start_connect, dpp, NULL);
+ break;
+ case KNOWN_NETWORKS_EVENT_REMOVED:
+ l_warn("profile was removed before DPP could connect");
+ break;
+ }
+}
- ptr += dpp_build_header(own_mac, dpp->peer_addr,
- DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE, ptr);
- ptr += dpp_append_wrapped_data(mmpdu_body(hdr) + 1,
- sizeof(frame) - mmpdu_header_len(hdr) - 1, ptr,
- dpp->z, dpp->z_len, 2,
- DPP_ATTR_BOOTSTRAPPING_KEY, b_len, b_pub,
- DPP_ATTR_RESPONDER_AUTH_TAG, v_len, v);
+static void dpp_handle_config_frame(const struct mmpdu_header *frame,
+ const void *body, size_t body_len,
+ int rssi, void *user_data)
+{
+ struct dpp *dpp = user_data;
+ struct dpp_configuration *config = NULL;
+ struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
+ struct network *network = NULL;
+ struct scan_bss *bss = NULL;
- iov.iov_base = frame;
- iov.iov_len = ptr - frame;
+ dpp_write_config(config, network);
- dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
-}
+ offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
-static void dpp_handle_pkex_commit_reveal_request(struct dpp_sm *dpp,
- const uint8_t *from,
- const uint8_t *body, size_t body_len)
-{
- struct dpp_attr_iter iter;
- enum dpp_attribute_type type;
- size_t len;
- const uint8_t *data;
- const void *wrapped = NULL;
- size_t wrapped_len = 0;
- _auto_(l_free) uint8_t *unwrapped = NULL;
- size_t unwrapped_len;
- uint8_t zero = 0;
- const void *key = 0;
- size_t key_len = 0;
- const void *i_auth = NULL;
- size_t i_auth_len = 0;
- _auto_(l_ecc_point_free) struct l_ecc_point *j = NULL;
- _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL;
- uint8_t u[L_ECC_SCALAR_MAX_BYTES];
- size_t u_len = 0;
- uint8_t v[L_ECC_SCALAR_MAX_BYTES];
- size_t v_len = 0;
- const uint8_t *own_addr = netdev_get_address(dpp->netdev);
-
- l_debug("PKEX commit-reveal request "MAC, MAC_STR(from));
-
- if (dpp->state != DPP_STATE_PKEX_COMMIT_REVEAL)
+ if (network && bss) {
+ l_debug("delaying connect until settings are synced");
+ dpp->config = config;
return;
+ } else if (station) {
+ struct scan_parameters params = {0};
- if (dpp->role != DPP_CAPABILITY_CONFIGURATOR)
- return;
+ params.ssid = (void *) config->ssid;
+ params.ssid_len = config->ssid_len;
- dpp_attr_iter_init(&iter, body + 8, body_len - 8);
+ l_debug("Scanning for %s", config->ssid);
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_WRAPPED_DATA:
- wrapped = data;
- wrapped_len = len;
- break;
- default:
- break;
+ dpp->connect_scan_id = scan_active_full(dpp->wdev_id, ¶ms,
+ dpp_scan_triggered,
+ dpp_scan_results, dpp,
+ dpp_scan_destroy);
+ if (dpp->connect_scan_id) {
+ dpp->config = config;
+ return;
}
}
- if (!wrapped) {
- l_debug("No wrapped data");
- return;
- }
-
- unwrapped = dpp_unwrap_attr(body + 2, 6, &zero, 1, dpp->z, dpp->z_len,
- wrapped, wrapped_len, &unwrapped_len);
- if (!unwrapped) {
- l_debug("Failed to unwrap attributes");
- return;
- }
-
- dpp_attr_iter_init(&iter, unwrapped, unwrapped_len);
+}
- while (dpp_attr_iter_next(&iter, &type, &len, &data)) {
- switch (type) {
- case DPP_ATTR_BOOTSTRAPPING_KEY:
- if (len != dpp->key_len * 2)
- return;
+static void dpp_roc_started(void *user_data)
+{
+ struct dpp *dpp = user_data;
- key = data;
- key_len = len;
- break;
- case DPP_ATTR_INITIATOR_AUTH_TAG:
- if (len != 32)
- return;
+ /*
+ * - If a configurator, nothing to do but wait for a request
+ * (unless multicast frame registration is unsupported in which case
+ * send an authenticate request now)
+ * - If in the presence state continue sending announcements.
+ * - If authenticating, and this is a result of a channel switch send
+ * the authenticate response now.
+ */
- i_auth = data;
- i_auth_len = len;
- break;
- default:
- break;
- }
- }
+ dpp->roc_started = true;
- if (!key || !i_auth) {
- l_debug("missing attributes");
+ /*
+ * The retry timer indicates a frame was not acked in which case we
+ * should not change any state or send any frames until that expires.
+ */
+ if (dpp->retry_timeout)
return;
- }
- dpp->peer_boot_public = l_ecc_point_from_data(dpp->curve,
- L_ECC_POINT_TYPE_FULL, key, key_len);
- if (!dpp->peer_boot_public) {
- l_debug("peers boostrapping key did not validate");
- goto failed;
+ if (dpp->frame_pending) {
+ dpp_frame_retry(dpp);
+ return;
}
+}
- /* J' = y * A' */
- j = l_ecc_point_new(dpp->curve);
-
- l_ecc_point_multiply(j, dpp->pkex_private, dpp->peer_boot_public);
+static void dpp_start_offchannel(struct dpp *dpp, uint32_t freq);
- dpp_derive_u(j, dpp->peer_addr, dpp->peer_boot_public, dpp->pkex_public,
- dpp->y_or_x, u, &u_len);
+static void dpp_offchannel_timeout(int error, void *user_data)
+{
+ struct dpp *dpp = user_data;
- if (memcmp(u, i_auth, i_auth_len)) {
- l_debug("Initiator auth tag did not verify");
- goto failed;
- }
+ dpp->offchannel_id = 0;
+ dpp->roc_started = false;
- /* L' = x * B' */
- l = l_ecc_point_new(dpp->curve);
+ /*
+ * If cancelled this is likely due to netdev going down or from Stop().
+ * Otherwise there was some other problem which is probably not
+ * recoverable.
+ */
+ if (error == -ECANCELED)
+ return;
+ else if (error == -EIO)
+ goto next_roc;
+ else if (error < 0)
+ goto protocol_failed;
- l_ecc_point_multiply(l, dpp->boot_private, dpp->y_or_x);
+ dpp->freqs_idx++;
- if (!dpp_derive_v(l, own_addr, dpp->boot_public, dpp->y_or_x,
- dpp->pkex_public, v, &v_len)) {
- l_debug("Failed to derive v");
- goto failed;
+ if (dpp->freqs_idx >= dpp->freqs_len) {
+ l_debug("Max retries offchannel");
+ dpp->freqs_idx = 0;
}
- dpp_send_commit_reveal_response(dpp, v, v_len);
+ dpp->current_freq = dpp->freqs[dpp->freqs_idx];
+
+ l_debug("Offchannel timeout, moving to next frequency %u, duration %u",
+ dpp->current_freq, dpp->dwell);
- dpp_pkex_start_authentication(dpp);
+next_roc:
+ dpp_start_offchannel(dpp, dpp->current_freq);
return;
-failed:
+protocol_failed:
dpp_reset(dpp);
}
-static void dpp_handle_frame(struct dpp_sm *dpp,
+static void dpp_start_offchannel(struct dpp *dpp, uint32_t freq)
+{
+ /*
+ * This needs to be handled carefully for a few reasons:
+ *
+ * First, the next offchannel operation needs to be started prior to
+ * canceling an existing one. This is so the offchannel work can
+ * continue uninterrupted without any other work items starting in
+ * between canceling and starting the next (e.g. if a scan request is
+ * sitting in the queue).
+ *
+ * Second, dpp_offchannel_timeout resets dpp->offchannel_id to zero
+ * which is why the new ID is saved and only set to dpp->offchannel_id
+ * once the previous offchannel work is cancelled (i.e. destroy() has
+ * been called).
+ */
+ uint32_t id = offchannel_start(netdev_get_wdev_id(dpp->netdev),
+ WIPHY_WORK_PRIORITY_OFFCHANNEL,
+ freq, dpp->dwell, dpp_roc_started,
+ dpp, dpp_offchannel_timeout);
+
+ if (dpp->offchannel_id)
+ offchannel_cancel(dpp->wdev_id, dpp->offchannel_id);
+
+ dpp->offchannel_id = id;
+}
+
+static void dpp_handle_frame(struct dpp *dpp,
const struct mmpdu_header *frame,
const void *body, size_t body_len)
{
@@ -3472,39 +810,6 @@ static void dpp_handle_frame(struct dpp_sm *dpp,
ptr = body + 7;
switch (*ptr) {
- case DPP_FRAME_AUTHENTICATION_REQUEST:
- authenticate_request(dpp, frame->address_2, body, body_len);
- break;
- case DPP_FRAME_AUTHENTICATION_RESPONSE:
- authenticate_response(dpp, frame->address_2, body, body_len);
- break;
- case DPP_FRAME_AUTHENTICATION_CONFIRM:
- authenticate_confirm(dpp, frame->address_2, body, body_len);
- break;
- case DPP_FRAME_CONFIGURATION_RESULT:
- dpp_handle_config_result_frame(dpp, frame->address_2,
- body, body_len);
- break;
- case DPP_FRAME_PRESENCE_ANNOUNCEMENT:
- dpp_handle_presence_announcement(dpp, frame->address_2,
- body, body_len);
- break;
- case DPP_FRAME_PKEX_XCHG_RESPONSE:
- dpp_handle_pkex_exchange_response(dpp, frame->address_2, body,
- body_len);
- break;
- case DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE:
- dpp_handle_pkex_commit_reveal_response(dpp, frame->address_2,
- body, body_len);
- break;
- case DPP_FRAME_PKEX_VERSION1_XCHG_REQUEST:
- dpp_handle_pkex_exchange_request(dpp, frame->address_2, body,
- body_len);
- break;
- case DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST:
- dpp_handle_pkex_commit_reveal_request(dpp, frame->address_2,
- body, body_len);
- break;
default:
l_debug("Unhandled DPP frame %u", *ptr);
break;
@@ -3513,7 +818,7 @@ static void dpp_handle_frame(struct dpp_sm *dpp,
static bool match_wdev(const void *a, const void *b)
{
- const struct dpp_sm *dpp = a;
+ const struct dpp *dpp = a;
const uint64_t *wdev_id = b;
return *wdev_id == dpp->wdev_id;
@@ -3521,7 +826,7 @@ static bool match_wdev(const void *a, const void *b)
static void dpp_frame_timeout(struct l_timeout *timeout, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
l_timeout_remove(timeout);
dpp->retry_timeout = NULL;
@@ -3540,7 +845,7 @@ static void dpp_frame_timeout(struct l_timeout *timeout, void *user_data)
static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data)
{
- struct dpp_sm *dpp;
+ struct dpp *dpp;
uint64_t wdev_id = 0;
uint64_t cookie = 0;
bool ack = false;
@@ -3620,7 +925,7 @@ retransmit:
static void dpp_unicast_notify(struct l_genl_msg *msg, void *user_data)
{
- struct dpp_sm *dpp;
+ struct dpp *dpp;
const uint64_t *wdev_id = NULL;
struct l_genl_attr attr;
uint16_t type, len, frame_len;
@@ -3692,7 +997,7 @@ static void dpp_frame_watch_cb(struct l_genl_msg *msg, void *user_data)
* require multicast support. This is only supported by ath9k, so adding
* general support to frame-xchg isn't desireable.
*/
-static void dpp_frame_watch(struct dpp_sm *dpp, uint16_t frame_type,
+static void dpp_frame_watch(struct dpp *dpp, uint16_t frame_type,
const uint8_t *prefix, size_t prefix_len)
{
struct l_genl_msg *msg;
@@ -3728,7 +1033,7 @@ static void dpp_frame_watch(struct dpp_sm *dpp, uint16_t frame_type,
*/
static void dpp_station_state_watch(enum station_state state, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
if (dpp->state == DPP_STATE_NOTHING)
return;
@@ -3779,7 +1084,7 @@ static void dpp_station_state_watch(enum station_state state, void *user_data)
static void dpp_create(struct netdev *netdev)
{
struct l_dbus *dbus = dbus_get_bus();
- struct dpp_sm *dpp = l_new(struct dpp_sm, 1);
+ struct dpp *dpp = l_new(struct dpp, 1);
uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
uint64_t wdev_id = netdev_get_wdev_id(netdev);
@@ -3789,32 +1094,22 @@ static void dpp_create(struct netdev *netdev)
dpp->state = DPP_STATE_NOTHING;
dpp->interface = DPP_INTERFACE_UNBOUND;
dpp->wdev_id = wdev_id;
- dpp->curve = l_ecc_curve_from_ike_group(19);
- dpp->key_len = l_ecc_curve_get_scalar_bytes(dpp->curve);
- dpp->nonce_len = dpp_nonce_len_from_key_len(dpp->key_len);
+
dpp->max_roc = wiphy_get_max_roc_duration(wiphy_find_by_wdev(wdev_id));
dpp->mcast_support = wiphy_has_ext_feature(
wiphy_find_by_wdev(dpp->wdev_id),
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
- l_ecdh_generate_key_pair(dpp->curve, &dpp->boot_private,
- &dpp->boot_public);
-
- dpp->own_asn1 = dpp_point_to_asn1(dpp->boot_public, &dpp->own_asn1_len);
-
- dpp_hash(L_CHECKSUM_SHA256, dpp->own_boot_hash, 1,
- dpp->own_asn1, dpp->own_asn1_len);
-
l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_DPP_INTERFACE, dpp);
l_dbus_object_add_interface(dbus, netdev_get_path(netdev),
IWD_DPP_PKEX_INTERFACE, dpp);
/*
- * Since both interfaces share the dpp_sm set this to 2. Currently both
+ * Since both interfaces share the dpp set this to 2. Currently both
* interfaces are added/removed in unison so we _could_ simply omit the
* destroy callback on one of them. But for consistency and future
* proofing use a reference count and the final interface being removed
- * will destroy the dpp_sm.
+ * will destroy the dpp.
*/
dpp->refcount = 2;
@@ -3823,11 +1118,11 @@ static void dpp_create(struct netdev *netdev)
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
dpp_conf_response_prefix,
sizeof(dpp_conf_response_prefix),
- dpp_handle_config_response_frame, dpp, NULL);
+ dpp_handle_config_frame, dpp, NULL);
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
dpp_conf_request_prefix,
sizeof(dpp_conf_request_prefix),
- dpp_handle_config_request_frame, dpp, NULL);
+ dpp_handle_config_frame, dpp, NULL);
dpp->station_watch = station_add_state_watch(station,
dpp_station_state_watch, dpp, NULL);
@@ -3864,7 +1159,7 @@ static void dpp_netdev_watch(struct netdev *netdev,
/*
* EasyConnect 2.0 - 6.2.2
*/
-static uint32_t *dpp_add_default_channels(struct dpp_sm *dpp, size_t *len_out)
+static uint32_t *dpp_add_default_channels(struct dpp *dpp, size_t *len_out)
{
struct wiphy *wiphy = wiphy_find_by_wdev(
netdev_get_wdev_id(dpp->netdev));
@@ -3901,7 +1196,7 @@ static uint32_t *dpp_add_default_channels(struct dpp_sm *dpp, size_t *len_out)
* procedure is not being fully implemented. In reality doing this would result
* in quite terrible DPP performance anyways.
*/
-static void dpp_start_presence(struct dpp_sm *dpp, uint32_t *limit_freqs,
+static void dpp_start_presence(struct dpp *dpp, uint32_t *limit_freqs,
size_t limit_len)
{
if (limit_freqs) {
@@ -3921,7 +1216,7 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
uint32_t freq = band_channel_to_freq(6, BAND_FREQ_2_4_GHZ);
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
@@ -3939,17 +1234,10 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
} else if (!station)
l_debug("No station device, continuing anyways...");
- dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2,
- netdev_get_address(dpp->netdev), &freq,
- 1, NULL, NULL);
-
dpp->state = DPP_STATE_PRESENCE;
dpp->role = DPP_CAPABILITY_ENROLLEE;
dpp->interface = DPP_INTERFACE_DPP;
- l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private,
- &dpp->own_proto_public);
-
l_debug("DPP Start Enrollee: %s", dpp->uri);
dpp->pending = l_dbus_message_ref(message);
@@ -3971,7 +1259,7 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
* will go offchannel to frequencies advertised by the enrollees URI or,
* if no channels are provided, use a default channel list.
*/
-static bool dpp_configurator_start_presence(struct dpp_sm *dpp, const char *uri)
+static bool dpp_configurator_start_presence(struct dpp *dpp, const char *uri)
{
_auto_(l_free) uint32_t *freqs = NULL;
size_t freqs_len = 0;
@@ -4002,20 +1290,8 @@ static bool dpp_configurator_start_presence(struct dpp_sm *dpp, const char *uri)
if (info->freqs)
freqs = scan_freq_set_to_fixed_array(info->freqs, &freqs_len);
- dpp->peer_boot_public = l_ecc_point_clone(info->boot_public);
- dpp->peer_asn1 = dpp_point_to_asn1(info->boot_public,
- &dpp->peer_asn1_len);
-
dpp_free_uri_info(info);
- if (!dpp->peer_asn1) {
- l_debug("Peer boot key did not convert to asn1");
- return false;
- }
-
- dpp_hash(L_CHECKSUM_SHA256, dpp->peer_boot_hash, 1, dpp->peer_asn1,
- dpp->peer_asn1_len);
-
dpp_start_presence(dpp, freqs, freqs_len);
return true;
@@ -4027,7 +1303,7 @@ static struct l_dbus_message *dpp_start_configurator_common(
void *user_data,
bool responder)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
struct l_dbus_message *reply;
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
struct scan_bss *bss;
@@ -4059,9 +1335,6 @@ static struct l_dbus_message *dpp_start_configurator_common(
dpp->interface != DPP_INTERFACE_UNBOUND)
return dbus_error_busy(message);
- l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private,
- &dpp->own_proto_public);
-
dpp->state = DPP_STATE_PRESENCE;
if (!responder) {
@@ -4071,12 +1344,6 @@ static struct l_dbus_message *dpp_start_configurator_common(
if (!dpp_configurator_start_presence(dpp, uri))
return dbus_error_invalid_args(message);
- /* Since we have the peer's URI generate the keys now */
- l_getrandom(dpp->i_nonce, dpp->nonce_len);
-
- dpp->m = dpp_derive_k1(dpp->peer_boot_public,
- dpp->proto_private, dpp->k1);
-
if (!dpp->mcast_support)
dpp->state = DPP_STATE_AUTHENTICATING;
@@ -4084,9 +1351,6 @@ static struct l_dbus_message *dpp_start_configurator_common(
} else
dpp->current_freq = bss->frequency;
- dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2,
- netdev_get_address(dpp->netdev),
- &bss->frequency, 1, NULL, NULL);
dpp->role = DPP_CAPABILITY_CONFIGURATOR;
dpp->interface = DPP_INTERFACE_DPP;
dpp->config = dpp_configuration_new(settings,
@@ -4122,7 +1386,7 @@ static struct l_dbus_message *dpp_dbus_stop(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
l_debug("");
@@ -4136,7 +1400,7 @@ static struct l_dbus_message *dpp_dbus_stop(struct l_dbus *dbus,
static void dpp_pkex_scan_trigger(int err, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
if (err < 0)
dpp_reset(dpp);
@@ -4152,7 +1416,7 @@ static void dpp_pkex_scan_trigger(int err, void *user_data)
* operation only in the 5.150 - 5.250 GHz band and Channel
* 149 (5.745 GHz) otherwise
*/
-static uint32_t *dpp_default_freqs(struct dpp_sm *dpp, size_t *out_len)
+static uint32_t *dpp_default_freqs(struct dpp *dpp, size_t *out_len)
{
struct wiphy *wiphy = wiphy_find_by_wdev(dpp->wdev_id);
uint32_t default_channels[3] = { 2437, 5220, 5745 };
@@ -4184,7 +1448,7 @@ static bool dpp_pkex_scan_notify(int err, struct l_queue *bss_list,
const struct scan_freq_set *freqs,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const struct l_queue_entry *e;
_auto_(scan_freq_set_free) struct scan_freq_set *freq_set = NULL;
@@ -4216,8 +1480,6 @@ static bool dpp_pkex_scan_notify(int err, struct l_queue *bss_list,
start:
dpp->current_freq = dpp->freqs[0];
- dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
-
l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset");
dpp_start_offchannel(dpp, dpp->current_freq);
@@ -4231,12 +1493,12 @@ failed:
static void dpp_pkex_scan_destroy(void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
dpp->pkex_scan_id = 0;
}
-static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp, const char *key,
+static bool dpp_start_pkex_enrollee(struct dpp *dpp, const char *key,
const char *identifier)
{
_auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL;
@@ -4256,28 +1518,6 @@ static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp, const char *key,
* but for now use max_roc or 200ms, whichever is less.
*/
dpp->dwell = (dpp->max_roc < 200) ? dpp->max_roc : 200;
- /* "DPP R2 devices are expected to use PKEXv1 by default" */
- dpp->pkex_version = 1;
-
- if (!l_ecdh_generate_key_pair(dpp->curve, &dpp->pkex_private,
- &dpp->pkex_public))
- goto failed;
-
- /*
- * "If Qi is the point-at-infinity, the code shall be deleted and the
- * user should be notified to provision a new code"
- */
- qi = dpp_derive_qi(dpp->curve, dpp->pkex_key, dpp->pkex_id,
- netdev_get_address(dpp->netdev));
- if (!qi || l_ecc_point_is_infinity(qi)) {
- l_debug("Cannot derive Qi, provision a new code");
- goto failed;
- }
-
- dpp->pkex_m = l_ecc_point_new(dpp->curve);
-
- if (!l_ecc_point_add(dpp->pkex_m, dpp->pkex_public, qi))
- goto failed;
dpp_property_changed_notify(dpp);
@@ -4349,7 +1589,7 @@ static struct l_dbus_message *dpp_dbus_pkex_start_enrollee(struct l_dbus *dbus,
struct l_dbus_message *message,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const char *key;
const char *id;
struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
@@ -4377,14 +1617,14 @@ invalid_args:
static void pkex_agent_disconnect(struct l_dbus *dbus, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
l_debug("SharedCodeAgent %s disconnected", dpp->agent->path);
dpp_reset(dpp);
}
-static void dpp_create_agent(struct dpp_sm *dpp, const char *path,
+static void dpp_create_agent(struct dpp *dpp, const char *path,
struct l_dbus_message *message)
{
const char *sender = l_dbus_message_get_sender(message);
@@ -4401,7 +1641,7 @@ static void dpp_create_agent(struct dpp_sm *dpp, const char *path,
l_debug("Registered a SharedCodeAgent on path %s", path);
}
-static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
+static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp *dpp,
const char *key, const char *identifier,
const char *agent_path,
struct l_dbus_message *message)
@@ -4444,12 +1684,10 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
dpp->state = DPP_STATE_PKEX_EXCHANGE;
dpp->interface = DPP_INTERFACE_PKEX;
dpp->current_freq = bss->frequency;
- dpp->pkex_version = 1;
dpp->config = dpp_configuration_new(network_get_settings(network),
network_get_ssid(network),
hs->akm_suite);
- dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
dpp_property_changed_notify(dpp);
if (dpp->pkex_key)
@@ -4465,7 +1703,7 @@ static struct l_dbus_message *dpp_dbus_pkex_configure_enrollee(
struct l_dbus_message *message,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const char *key;
const char *id;
@@ -4482,7 +1720,7 @@ static struct l_dbus_message *dpp_dbus_pkex_start_configurator(
struct l_dbus_message *message,
void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
const char *path;
if (!l_dbus_message_get_arguments(message, "o", &path))
@@ -4512,7 +1750,7 @@ static void dpp_setup_interface(struct l_dbus_interface *interface)
static struct l_dbus_message *dpp_dbus_pkex_stop(struct l_dbus *dbus,
struct l_dbus_message *message, void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
l_debug("");
@@ -4543,7 +1781,7 @@ static void dpp_setup_pkex_interface(struct l_dbus_interface *interface)
static void dpp_destroy_interface(void *user_data)
{
- struct dpp_sm *dpp = user_data;
+ struct dpp *dpp = user_data;
if (--dpp->refcount)
return;