public inbox for iwd@lists.linux.dev
 help / color / mirror / Atom feed
From: James Prestwood <prestwoj@gmail.com>
To: iwd@lists.linux.dev
Cc: James Prestwood <prestwoj@gmail.com>
Subject: [PATCH v4 4/4] dpp: Add StartConfigurator, PKEX agent support
Date: Tue,  7 Nov 2023 09:06:29 -0800	[thread overview]
Message-ID: <20231107170629.1831655-5-prestwoj@gmail.com> (raw)
In-Reply-To: <20231107170629.1831655-1-prestwoj@gmail.com>

Adds a configurator variant to be used along side an agent. When
called the configurator will start and wait for an initial PKEX
exchange message from an enrollee at which point it will request
the code from an agent. This provides more flexibility for
configurators that are capable of configuring multiple enrollees
with different identifiers/codes.

Note that the timing requirements per the DPP spec still apply
so this is not meant to be used with a human configurator but
within an automated agent which does a quick lookup of potential
identifiers/codes and can reply within the 200ms window.
---
 src/dpp.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 226 insertions(+), 2 deletions(-)

diff --git a/src/dpp.c b/src/dpp.c
index 86361ba0..265fa971 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -82,6 +82,13 @@ enum dpp_capability {
 	DPP_CAPABILITY_CONFIGURATOR = 0x02,
 };
 
+struct pkex_agent {
+	char *owner;
+	char *path;
+	unsigned int disconnect_watch;
+	uint32_t pending_id;
+};
+
 struct dpp_sm {
 	struct netdev *netdev;
 	char *uri;
@@ -104,6 +111,8 @@ struct dpp_sm {
 
 	enum dpp_state state;
 
+	struct pkex_agent *agent;
+
 	/*
 	 * List of frequencies to jump between. The presence of this list is
 	 * also used to signify that a configurator is an initiator vs responder
@@ -154,6 +163,7 @@ struct dpp_sm {
 	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;
@@ -317,6 +327,68 @@ static void dpp_free_pending_pkex_data(struct dpp_sm *dpp)
 	}
 
 	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;
+
+	l_free(agent->owner);
+	l_free(agent->path);
+	l_dbus_remove_watch(dbus_get_bus(), agent->disconnect_watch);
+	l_free(agent);
+}
+
+static void dpp_agent_cancel(struct dpp_sm *dpp)
+{
+	struct l_dbus_message *msg;
+
+	const char *reason = "shutdown";
+
+	msg = l_dbus_message_new_method_call(dbus_get_bus(),
+						dpp->agent->owner,
+						dpp->agent->path,
+						IWD_SHARED_CODE_AGENT_INTERFACE,
+						"Cancel");
+	l_dbus_message_set_arguments(msg, "s", reason);
+	l_dbus_message_set_no_reply(msg, true);
+	l_dbus_send(dbus_get_bus(), msg);
+}
+
+static void dpp_agent_release(struct dpp_sm *dpp)
+{
+	struct l_dbus_message *msg;
+
+	msg = l_dbus_message_new_method_call(dbus_get_bus(),
+						dpp->agent->owner,
+						dpp->agent->path,
+						IWD_SHARED_CODE_AGENT_INTERFACE,
+						"Release");
+	l_dbus_message_set_no_reply(msg, true);
+	l_dbus_send(dbus_get_bus(), msg);
+}
+
+static void dpp_destroy_agent(struct dpp_sm *dpp)
+{
+	if (!dpp->agent)
+		return;
+
+	if (dpp->agent->pending_id) {
+		dpp_agent_cancel(dpp);
+		l_dbus_cancel(dbus_get_bus(), dpp->agent->pending_id);
+	}
+
+	dpp_agent_release(dpp);
+
+	l_debug("Released SharedCodeAgent on path %s", dpp->agent->path);
+
+	pkex_agent_free(dpp->agent);
+	dpp->agent = NULL;
 }
 
 static void dpp_free_auth_data(struct dpp_sm *dpp)
@@ -415,6 +487,11 @@ static void dpp_reset(struct dpp_sm *dpp)
 		dpp->retry_timeout = NULL;
 	}
 
+	if (dpp->pkex_scan_id) {
+		scan_cancel(dpp->wdev_id, dpp->pkex_scan_id);
+		dpp->pkex_scan_id = 0;
+	}
+
 	dpp->state = DPP_STATE_NOTHING;
 	dpp->new_freq = 0;
 	dpp->frame_retry = 0;
@@ -431,6 +508,8 @@ static void dpp_reset(struct dpp_sm *dpp)
 	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);
@@ -458,6 +537,11 @@ static void dpp_free(struct dpp_sm *dpp)
 		dpp->boot_private = NULL;
 	}
 
+	if (dpp->agent) {
+		pkex_agent_free(dpp->agent);
+		dpp->agent = NULL;
+	}
+
 	l_free(dpp);
 }
 
@@ -1800,6 +1884,18 @@ static void dpp_offchannel_timeout(int error, void *user_data)
 
 	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);
+		/* Fall through */
 	case DPP_STATE_PRESENCE:
 		break;
 	case DPP_STATE_NOTHING:
@@ -2912,6 +3008,63 @@ bad_code:
 	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)
@@ -3012,6 +3165,29 @@ static void dpp_handle_pkex_exchange_request(struct dpp_sm *dpp,
 
 	memcpy(dpp->peer_addr, from, 6);
 
+	if (!dpp->pkex_key) {
+		if (!id) {
+			l_debug("Configurator started with agent but enrollee "
+				"sent no identifier, ignoring");
+			return;
+		}
+
+		dpp->pkex_id = l_strndup(id, id_len);
+
+		/* 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;
+		}
+
+		/* Save the encrypted key/identifier for the agent callback */
+
+		dpp->peer_encr_key = l_steal_ptr(m);
+
+		return;
+	}
+
 	dpp_process_pkex_exchange_request(dpp, m);
 
 	return;
@@ -3931,8 +4107,34 @@ invalid_args:
 	return dbus_error_invalid_args(message);
 }
 
+static void pkex_agent_disconnect(struct l_dbus *dbus, void *user_data)
+{
+	struct dpp_sm *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,
+					struct l_dbus_message *message)
+{
+	const char *sender = l_dbus_message_get_sender(message);
+
+	dpp->agent = l_new(struct pkex_agent, 1);
+	dpp->agent->owner = l_strdup(sender);
+	dpp->agent->path = l_strdup(path);
+	dpp->agent->disconnect_watch = l_dbus_add_disconnect_watch(dbus_get_bus(),
+							sender,
+							pkex_agent_disconnect,
+							dpp, NULL);
+
+	l_debug("Registered a SharedCodeAgent on path %s", path);
+}
+
 static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
 					const char *key, const char *identifier,
+					const char *agent_path,
 					struct l_dbus_message *message)
 {
 	struct handshake_state *hs = netdev_get_handshake(dpp->netdev);
@@ -3959,6 +4161,9 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
 	if (key)
 		dpp->pkex_key = l_strdup(key);
 
+	if (agent_path)
+		dpp_create_agent(dpp, agent_path, message);
+
 	dpp->role = DPP_CAPABILITY_CONFIGURATOR;
 	dpp->state = DPP_STATE_PKEX_EXCHANGE;
 	dpp->current_freq = bss->frequency;
@@ -3970,7 +4175,10 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
 	dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
 	dpp_pkex_property_changed_notify(dpp);
 
-	l_debug("Starting PKEX configurator for single enrollee");
+	if (dpp->pkex_key)
+		l_debug("Starting PKEX configurator for single enrollee");
+	else
+		l_debug("Starting PKEX configurator with agent");
 
 	return l_dbus_message_new_method_return(message);
 }
@@ -3989,7 +4197,21 @@ static struct l_dbus_message *dpp_dbus_pkex_configure_enrollee(
 	if (!dpp_parse_pkex_args(message, &key, &id))
 		return dbus_error_invalid_args(message);
 
-	return dpp_start_pkex_configurator(dpp, key, id, message);
+	return dpp_start_pkex_configurator(dpp, key, id, NULL, message);
+}
+
+static struct l_dbus_message *dpp_dbus_pkex_start_configurator(
+						struct l_dbus *dbus,
+						struct l_dbus_message *message,
+						void *user_data)
+{
+	struct dpp_sm *dpp = user_data;
+	const char *path;
+
+	if (!l_dbus_message_get_arguments(message, "o", &path))
+		return dbus_error_invalid_args(message);
+
+	return dpp_start_pkex_configurator(dpp, NULL, NULL, path, message);
 }
 
 static void dpp_setup_interface(struct l_dbus_interface *interface)
@@ -4030,6 +4252,8 @@ static void dpp_setup_pkex_interface(struct l_dbus_interface *interface)
 			dpp_dbus_pkex_stop, "", "");
 	l_dbus_interface_method(interface, "ConfigureEnrollee", 0,
 			dpp_dbus_pkex_configure_enrollee, "", "a{sv}", "args");
+	l_dbus_interface_method(interface, "StartConfigurator", 0,
+			dpp_dbus_pkex_start_configurator, "", "o", "path");
 
 	l_dbus_interface_property(interface, "Started", 0, "b",
 			dpp_pkex_get_started, NULL);
-- 
2.25.1


      parent reply	other threads:[~2023-11-07 17:06 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-07 17:06 [PATCH v4 0/4] DPP PKEX Changes James Prestwood
2023-11-07 17:06 ` [PATCH v4 1/4] doc: PKEX support for DPP James Prestwood
2023-11-08  2:28   ` Denis Kenzior
2023-11-07 17:06 ` [PATCH v4 2/4] dpp: initial version of PKEX enrollee support James Prestwood
2023-11-08  3:11   ` Denis Kenzior
2023-11-08 12:42     ` James Prestwood
2023-11-08 15:07       ` Denis Kenzior
2023-11-08 15:14         ` James Prestwood
2023-11-07 17:06 ` [PATCH v4 3/4] dpp: initial version of PKEX configurator support James Prestwood
2023-11-07 17:06 ` James Prestwood [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231107170629.1831655-5-prestwoj@gmail.com \
    --to=prestwoj@gmail.com \
    --cc=iwd@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox