iwd.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol
@ 2024-03-13 17:13 James Prestwood
  2024-03-13 17:13 ` [RFC 1/5] dpp: prep for moving AAD within dpp_append_wrapped_data James Prestwood
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Patches 1-4 can be applied any time, they are needed for the refactoring in
further patches but are still a nice improvement on their own.

Patch 5 is the skeleton module for the common DPP code. Don't merge this now
(even if it looks fine), I'd like to at least get the TCP side started before
I lock in the dpp_sm APIs in case there are changes required.

The reason this is being done is to eventually support DPP-over-TCP as well as
add the ability to implement a DPP controller within the IWD source repo which
can use the same state machine as IWD. Doing this requires the TX/RX of DPP
frames be offloaded to the encapsulating protocol (802.11 or TCP). This leaves
the DPP state details within the SM, which can be shared between either
protocol.

James Prestwood (5):
  dpp: prep for moving AAD within dpp_append_wrapped_data
  dpp-util: move AAD logic within dpp_append_wrapped_attributes
  dpp-util: add dpp_append_point
  dpp: use dpp_append_point
  dpp-common: Skeleton for common DPP module

 src/dpp-common.c | 517 +++++++++++++++++++++++++++++++++++++++++++++++
 src/dpp-common.h | 109 ++++++++++
 src/dpp-util.c   | 180 ++++++++++++++++-
 src/dpp-util.h   |   7 +-
 src/dpp.c        | 308 ++++++++++++++--------------
 5 files changed, 948 insertions(+), 173 deletions(-)
 create mode 100644 src/dpp-common.c
 create mode 100644 src/dpp-common.h

--
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC 1/5] dpp: prep for moving AAD within dpp_append_wrapped_data
  2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
@ 2024-03-13 17:13 ` James Prestwood
  2024-03-13 17:13 ` [RFC 2/5] dpp-util: move AAD logic within dpp_append_wrapped_attributes James Prestwood
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The AAD pointers for DPP are specific to the frame type. This is
currently sorted out by the caller within the respective frame
building functions but its quite unreadable. There are some comments
but lots of magic numbers. This should be moved within the
dpp_append_wrapped_data utility but the first step is to make the
frame buffer continuous. This will allow the entire frame to be
passed and dpp_append_wrapped_data can calculate the AAD offsets
itself.
---
 src/dpp.c | 239 +++++++++++++++++++++++++-----------------------------
 1 file changed, 112 insertions(+), 127 deletions(-)

diff --git a/src/dpp.c b/src/dpp.c
index 567fe8d2..5aac22a7 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -648,7 +648,7 @@ static void dpp_frame_retry(struct dpp_sm *dpp)
 
 static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
 				enum dpp_frame_type type,
-				uint8_t buf[static 32])
+				uint8_t *buf)
 {
 	uint8_t *ptr = buf + 24;
 
@@ -672,7 +672,7 @@ static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
 
 static size_t dpp_build_config_header(const uint8_t *src, const uint8_t *dest,
 					uint8_t diag_token,
-					uint8_t buf[static 37])
+					uint8_t *buf)
 {
 	uint8_t *ptr = buf + 24;
 
@@ -753,22 +753,21 @@ 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[3];
-	uint8_t hdr[37];
-	uint8_t attrs[512];
+	struct iovec iov;
+	uint8_t frame[512];
 	size_t json_len = strlen(json);
-	uint8_t *ptr = attrs;
+	uint8_t *ptr = frame;
+	uint8_t *lptr;
 
 	l_getrandom(&dpp->diag_token, 1);
 
-	iov[0].iov_len = dpp_build_config_header(
-					netdev_get_address(dpp->netdev),
-					addr, dpp->diag_token, hdr);
-	iov[0].iov_base = hdr;
+	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;
 
 	/*
@@ -780,42 +779,39 @@ static void dpp_configuration_start(struct dpp_sm *dpp, const uint8_t *addr)
 	 * 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(NULL, 0, NULL, 0, ptr, sizeof(attrs),
+	ptr += dpp_append_wrapped_data(NULL, 0, NULL, 0, ptr, sizeof(frame),
 			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 - attrs - 2, attrs);
+	l_put_le16(ptr - lptr - 2, lptr);
 
-	iov[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
 	dpp->state = DPP_STATE_CONFIGURING;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void send_config_result(struct dpp_sm *dpp, const uint8_t *to)
 {
-	uint8_t hdr[32];
-	struct iovec iov[2];
-	uint8_t attrs[256];
-	uint8_t *ptr = attrs;
+	struct iovec iov;
+	uint8_t frame[256];
+	uint8_t *ptr = frame;
 	uint8_t zero = 0;
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev), to,
-					DPP_FRAME_CONFIGURATION_RESULT, hdr);
-	iov[0].iov_base = hdr;
-
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, attrs, 0, ptr,
-			sizeof(attrs), dpp->ke, dpp->key_len, 2,
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev), to,
+					DPP_FRAME_CONFIGURATION_RESULT, ptr);
+	ptr += dpp_append_wrapped_data(frame + 26, 6, ptr, 0, ptr,
+			sizeof(frame), dpp->ke, dpp->key_len, 2,
 			DPP_ATTR_STATUS, (size_t) 1, &zero,
 			DPP_ATTR_ENROLLEE_NONCE, dpp->nonce_len, dpp->e_nonce);
 
-	iov[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void dpp_write_config(struct dpp_configuration *config,
@@ -1162,18 +1158,20 @@ static void dpp_handle_config_response_frame(const struct mmpdu_header *frame,
 static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
 {
 	_auto_(l_free) char *json = NULL;
-	struct iovec iov[3];
-	uint8_t hdr[41];
-	uint8_t attrs[512];
+	struct iovec iov;
+	uint8_t frame[512];
 	size_t json_len;
-	uint8_t *ptr = hdr + 24;
+	uint8_t *ptr = frame;
+	uint8_t *lptr;
+
+	memset(frame, 0, sizeof(frame));
 
-	memset(hdr, 0, sizeof(hdr));
+	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);
 
-	l_put_le16(0x00d0, hdr);
-	memcpy(hdr + 4, dpp->peer_addr, 6);
-	memcpy(hdr + 10, netdev_get_address(dpp->netdev), 6);
-	memcpy(hdr + 16, broadcast, 6);
+	ptr += 24;
 
 	*ptr++ = 0x04;
 	*ptr++ = 0x0b;
@@ -1192,11 +1190,7 @@ static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
 	*ptr++ = 0x1a;
 	*ptr++ = 1;
 
-	iov[0].iov_base = hdr;
-	iov[0].iov_len = ptr - hdr;
-
-	ptr = attrs;
-
+	lptr = ptr;
 	ptr += 2; /* length */
 
 	ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1);
@@ -1211,26 +1205,26 @@ static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
 		json = dpp_configuration_to_json(dpp->config);
 		json_len = strlen(json);
 
-		ptr += dpp_append_wrapped_data(attrs + 2, ptr - attrs - 2,
-						NULL, 0, ptr, sizeof(attrs),
+		ptr += dpp_append_wrapped_data(lptr + 2, ptr - lptr - 2,
+						NULL, 0, ptr, sizeof(frame),
 						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(attrs + 2, ptr - attrs - 2,
-						NULL, 0, ptr, sizeof(attrs),
+		ptr += dpp_append_wrapped_data(lptr + 2, ptr - lptr - 2,
+						NULL, 0, ptr, sizeof(frame),
 						dpp->ke, dpp->key_len, 2,
 						DPP_ATTR_ENROLLEE_NONCE,
 						dpp->nonce_len, dpp->e_nonce);
 
-	l_put_le16(ptr - attrs - 2, attrs);
+	l_put_le16(ptr - lptr - 2, lptr);
 
-	iov[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static bool dpp_check_config_header(const uint8_t *ptr)
@@ -1498,13 +1492,13 @@ static void dpp_handle_config_result_frame(struct dpp_sm *dpp,
  */
 static void send_authenticate_response(struct dpp_sm *dpp)
 {
-	uint8_t hdr[32];
-	uint8_t attrs[512];
-	uint8_t *ptr = attrs;
+	uint8_t frame[512];
+	uint8_t *ptr = frame;
+	uint8_t *attrs;
 	uint8_t status = DPP_STATUS_OK;
 	uint64_t r_proto_key[L_ECC_MAX_DIGITS * 2];
 	uint8_t version = 2;
-	struct iovec iov[3];
+	struct iovec iov;
 	uint8_t wrapped2_plaintext[dpp->key_len + 4];
 	uint8_t wrapped2[dpp->key_len + 16 + 8];
 	size_t wrapped2_len;
@@ -1512,11 +1506,10 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 	l_ecc_point_get_data(dpp->own_proto_public, r_proto_key,
 				sizeof(r_proto_key));
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev),
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
-				DPP_FRAME_AUTHENTICATION_RESPONSE, hdr);
-	iov[0].iov_base = hdr;
-
+				DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
+	attrs = 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);
@@ -1545,17 +1538,17 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 
 	wrapped2_len += 16;
 
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(attrs), dpp->k2, dpp->key_len, 4,
+	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs,
+			ptr, sizeof(frame), 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[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void authenticate_confirm(struct dpp_sm *dpp, const uint8_t *from,
@@ -1699,34 +1692,33 @@ static void dpp_auth_request_failed(struct dpp_sm *dpp,
 					enum dpp_status status,
 					void *k1)
 {
-	uint8_t hdr[32];
-	uint8_t attrs[128];
-	uint8_t *ptr = attrs;
+	uint8_t frame[128];
+	uint8_t *ptr = frame;
+	uint8_t *attrs;
 	uint8_t version = 2;
 	uint8_t s = status;
-	struct iovec iov[2];
+	struct iovec iov;
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev),
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
-				DPP_FRAME_AUTHENTICATION_RESPONSE, hdr);
-	iov[0].iov_base = hdr;
-
+				DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
+	attrs = 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(hdr + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(attrs) - (ptr - attrs), k1, dpp->key_len, 2,
+	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs,
+			ptr, sizeof(frame) - (ptr - attrs), 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[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static bool dpp_check_roles(struct dpp_sm *dpp, uint8_t peer_capa)
@@ -1771,12 +1763,12 @@ static void dpp_presence_announce(struct dpp_sm *dpp)
 
 static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 {
-	uint8_t hdr[32];
-	uint8_t attrs[256];
-	uint8_t *ptr = attrs;
+	uint8_t frame[256];
+	uint8_t *ptr = frame;
+	uint8_t *attrs;
 	uint64_t i_proto_key[L_ECC_MAX_DIGITS * 2];
 	uint8_t version = 2;
-	struct iovec iov[2];
+	struct iovec iov;
 	struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
 	struct scan_bss *bss = station_get_connected_bss(station);
 
@@ -1789,10 +1781,10 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 	l_ecc_point_get_data(dpp->own_proto_public, i_proto_key,
 				sizeof(i_proto_key));
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev),
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
-				DPP_FRAME_AUTHENTICATION_REQUEST, hdr);
-	iov[0].iov_base = hdr;
+				DPP_FRAME_AUTHENTICATION_REQUEST, ptr);
+	attrs = ptr;
 
 	ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_BOOT_KEY_HASH,
 				dpp->peer_boot_hash, 32);
@@ -1810,16 +1802,16 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_CHANNEL, pair, 2);
 	}
 
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(attrs), dpp->k1, dpp->key_len, 2,
+	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs,
+			ptr, sizeof(frame), 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[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 
 	return true;
 }
@@ -1862,31 +1854,28 @@ static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp)
 
 static void dpp_send_commit_reveal_request(struct dpp_sm *dpp)
 {
-	struct iovec iov[2];
-	uint8_t hdr[41];
-	uint8_t attrs[512];
-	uint8_t *ptr = attrs;
+	struct iovec iov;
+	uint8_t frame[512];
+	uint8_t *ptr = frame;
 	uint8_t zero = 0;
 	uint8_t a_pub[L_ECC_POINT_MAX_BYTES];
 	ssize_t a_len;
 
 	a_len = l_ecc_point_get_data(dpp->boot_public, a_pub, sizeof(a_pub));
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev),
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 					dpp->peer_addr,
 					DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST,
-					hdr);
-	iov[0].iov_base = hdr;
-
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, &zero, 1, ptr,
-			sizeof(attrs), dpp->z, dpp->z_len, 2,
+					ptr);
+	ptr += dpp_append_wrapped_data(frame + 26, 6, &zero, 1, ptr,
+			sizeof(frame), 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[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void dpp_roc_started(void *user_data)
@@ -2272,17 +2261,16 @@ auth_request_failed:
 
 static void dpp_send_authenticate_confirm(struct dpp_sm *dpp)
 {
-	uint8_t hdr[32];
-	struct iovec iov[2];
-	uint8_t attrs[256];
-	uint8_t *ptr = attrs;
+	struct iovec iov;
+	uint8_t frame[256];
+	uint8_t *ptr = frame;
+	uint8_t *attrs;
 	uint8_t zero = 0;
 
-	iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev),
+	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 					dpp->peer_addr,
-					DPP_FRAME_AUTHENTICATION_CONFIRM, hdr);
-	iov[0].iov_base = hdr;
-
+					DPP_FRAME_AUTHENTICATION_CONFIRM, ptr);
+	attrs = 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);
@@ -2290,15 +2278,15 @@ static void dpp_send_authenticate_confirm(struct dpp_sm *dpp)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
 					dpp->own_boot_hash, 32);
 
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, attrs, ptr - attrs, ptr,
-			sizeof(attrs), dpp->ke, dpp->key_len, 1,
+	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs, ptr,
+			sizeof(frame), dpp->ke, dpp->key_len, 1,
 			DPP_ATTR_INITIATOR_AUTH_TAG, dpp->key_len,
 			dpp->auth_tag);
 
-	iov[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void authenticate_response(struct dpp_sm *dpp, const uint8_t *from,
@@ -3311,11 +3299,10 @@ bad_group:
 static void dpp_send_commit_reveal_response(struct dpp_sm *dpp,
 						const uint8_t *v, size_t v_len)
 {
-	uint8_t hdr[32];
-	uint8_t attrs[256];
-	uint8_t *ptr = attrs;
+	uint8_t frame[256];
+	uint8_t *ptr = frame;
 	uint8_t one = 1;
-	struct iovec iov[2];
+	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;
@@ -3323,19 +3310,17 @@ static void dpp_send_commit_reveal_response(struct dpp_sm *dpp,
 	b_len = l_ecc_point_get_data(dpp->boot_public, b_pub, sizeof(b_pub));
 
 
-	iov[0].iov_len = dpp_build_header(own_mac, dpp->peer_addr,
-				DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE, hdr);
-	iov[0].iov_base = hdr;
-
-	ptr += dpp_append_wrapped_data(hdr + 26, 6, &one, 1, ptr,
-			sizeof(attrs), dpp->z, dpp->z_len, 2,
+	ptr += dpp_build_header(own_mac, dpp->peer_addr,
+				DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE, ptr);
+	ptr += dpp_append_wrapped_data(frame + 26, 6, &one, 1, ptr,
+			sizeof(frame), dpp->z, dpp->z_len, 2,
 			DPP_ATTR_BOOTSTRAPPING_KEY, b_len, b_pub,
 			DPP_ATTR_RESPONDER_AUTH_TAG, v_len, v);
 
-	iov[1].iov_base = attrs;
-	iov[1].iov_len = ptr - attrs;
+	iov.iov_base = frame;
+	iov.iov_len = ptr - frame;
 
-	dpp_send_frame(dpp, iov, 2, dpp->current_freq);
+	dpp_send_frame(dpp, &iov, 1, dpp->current_freq);
 }
 
 static void dpp_handle_pkex_commit_reveal_request(struct dpp_sm *dpp,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 2/5] dpp-util: move AAD logic within dpp_append_wrapped_attributes
  2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
  2024-03-13 17:13 ` [RFC 1/5] dpp: prep for moving AAD within dpp_append_wrapped_data James Prestwood
@ 2024-03-13 17:13 ` James Prestwood
  2024-03-13 17:13 ` [RFC 3/5] dpp-util: add dpp_append_point James Prestwood
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Leaving it up to the caller to calcluate the AAD resulted in lots of
magic values, and any comments associated are spread out within
dpp.c. The AAD values can be calculated entirely by the frame
contents so move that within dpp_append_wrapped_data.

The caller now only needs to pass the frame (after the mpdu header),
the length, and the offset to where the wrapped data should start.
The new AAD calculation includes all relavent comments so magic
offsets are documented.

The reason the entire mmpdu_body is not passed to
dpp_append_wrapped_attributes (and one byte further) is to future
proof for DPP encapsulation using TCP. For this, the category byte
is omitted and only the action byte and further is encapsulated.
Having dpp_append_wrapped_attributes start at the action byte
allows it to work regardless of 8021x or TCP encapsulation.
---
 src/dpp-util.c | 167 +++++++++++++++++++++++++++++++++++++++++++++----
 src/dpp-util.h |   5 +-
 src/dpp.c      |  99 +++++++++++++++++------------
 3 files changed, 218 insertions(+), 53 deletions(-)

diff --git a/src/dpp-util.c b/src/dpp-util.c
index cfdedbdd..ada7ed96 100644
--- a/src/dpp-util.c
+++ b/src/dpp-util.c
@@ -39,6 +39,11 @@
 #include "ell/asn1-private.h"
 #include "src/ie.h"
 
+#define DPP_ACTION_VENDOR_SPECIFIC	0x09
+#define DPP_ACTION_GAS_REQUEST		0x0a
+#define DPP_ACTION_GAS_RESPONSE		0x0b
+#define DPP_HDR_LEN			6
+
 /* WFA Easy Connect v3.0 C.1 Role-specific Elements for NIST p256 */
 static const uint8_t dpp_pkex_initiator_p256[64] = {
 	/* X */
@@ -463,22 +468,91 @@ uint8_t *dpp_unwrap_attr(const void *ad0, size_t ad0_len, const void *ad1,
 	return unwrapped;
 }
 
+static bool dpp_aad(const uint8_t *frame, size_t frame_len, uint8_t *to,
+			const uint8_t **ad0, size_t *ad0_len,
+			const uint8_t **ad1, size_t *ad1_len)
+{
+	/* For PKEX frames */
+	static uint8_t zero = 0;
+	static uint8_t one = 1;
+	enum dpp_frame_type type;
+	/* OUI field (inclusive) */
+	const uint8_t *start = frame + 1;
+
+	if (frame_len < 6)
+		return false;
+
+	type = l_get_u8(frame + 6);
+
+	switch (type) {
+
+	case DPP_FRAME_AUTHENTICATION_REQUEST:
+	case DPP_FRAME_AUTHENTICATION_RESPONSE:
+	case DPP_FRAME_AUTHENTICATION_CONFIRM:
+	case DPP_FRAME_CONFIGURATION_RESULT:
+		/*
+		 * Section 6.3.1.4 Protocol Conventions
+		 * 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 34, 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
+		 *
+		 * Note: The configuration result frame uses identical wordage
+		 *       but is in Section 6.4.1
+		 */
+		*ad0 = start;
+		*ad0_len = DPP_HDR_LEN;
+		*ad1 = start + DPP_HDR_LEN;
+		*ad1_len = to - start - DPP_HDR_LEN;
+		return true;
+	case DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST:
+		/*
+		 * The AAD for this operation shall consist of two components:
+		 *     (1) the DPP header, as defined in Table 34, from the OUI
+		 *         field (inclusive) to the DPP Frame Type field
+		 *         (inclusive); and
+		 *     (2) a single octet of the value zero
+		 */
+		*ad0 = start;
+		*ad0_len = DPP_HDR_LEN;
+		*ad1 = &zero;
+		*ad1_len = 1;
+		return true;
+	case DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE:
+		/*
+		 * The AAD for this operation shall consist of two components:
+		 *     (1) the DPP header, as defined in Table 34, from the OUI
+		 *         field (inclusive) to the DPP Frame Type field
+		 *         (inclusive); and
+		 *     (2) a single octet of the value one
+		 */
+		*ad0 = start;
+		*ad0_len = DPP_HDR_LEN;
+		*ad1 = &one;
+		*ad1_len = 1;
+		return true;
+	default:
+		return false;
+	}
+}
+
 /*
- * Encrypt DPP attributes encapsulated in DPP wrapped data.
- *
- * ad0/ad0_len - frame specific AD0 component
- * ad1/ad0_len - frame specific AD1 component
- * to - buffer to encrypt data.
- * to_len - size of 'to'
+ * frame - start of action frame (excluding mpdu header and category)
+ * frame_len - total frame buffer size
+ * to - current position of DPP attributes (where wrapped data will start)
  * key - key used to encrypt
  * key_len - size of 'key'
  * num_attrs - number of attributes listed (type, length, data triplets)
  * ... - List of attributes, Type, Length, and data
  */
-size_t dpp_append_wrapped_data(const void *ad0, size_t ad0_len,
-				const void *ad1, size_t ad1_len,
-				uint8_t *to, size_t to_len,
-				const void *key, size_t key_len,
+size_t dpp_append_wrapped_data(const uint8_t *frame, size_t frame_len,
+				uint8_t *to, const void *key, size_t key_len,
 				size_t num_attrs, ...)
 {
 	size_t i;
@@ -488,6 +562,77 @@ size_t dpp_append_wrapped_data(const void *ad0, size_t ad0_len,
 	struct iovec ad[2];
 	size_t ad_size = 0;
 	va_list va;
+	uint8_t action;
+	const uint8_t *ad0 = NULL;
+	const uint8_t *ad1 = NULL;
+	size_t ad0_len, ad1_len;
+
+	/*
+	 * First determine the frame type. This could be passed in but due to
+	 * The config protocol using GAS request/response frames not all frames
+	 * map to a dpp_frame_type enum. Due to this, minimal parsing is done
+	 * on the frame to determine the type, and in turn the AAD
+	 * offsets/lengths.
+	 */
+	if (frame_len < 1)
+		return 0;
+
+	action = *frame;
+
+	switch (action) {
+	case DPP_ACTION_VENDOR_SPECIFIC:
+		if (!dpp_aad(frame, frame_len, to, &ad0, &ad0_len,
+				&ad1, &ad1_len))
+			return 0;
+
+		break;
+	/*
+	 * Section 6.4.1 Overview
+	 *
+	 * "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
+	 */
+	case DPP_ACTION_GAS_REQUEST:
+		/*
+		 * 8.3.2 DPP Configuration Request frame
+		 * The attributes begin 14 bytes after the action (inclusive)
+		 */
+		if (frame_len < 14)
+			return 0;
+
+		/* Start of query request */
+		ad0 = frame + 14;
+		/* "up to the first octet of the Wrapped Data attribute" */
+		ad0_len = to - frame - 14;
+
+		if (!ad0_len)
+			ad0 = NULL;
+
+		break;
+	case DPP_ACTION_GAS_RESPONSE:
+		/*
+		 * 8.3.3 DPP Configuration Response frame
+		 * The attributes begin 18 bytes after the action (inclusive)
+		 */
+		if (frame_len < 18)
+			return 0;
+
+		/* Start of query response */
+		ad0 = frame + 18;
+		/* "up to the first octet of the Wrapped Data attribute" */
+		ad0_len = to - frame - 18;
+
+		if (!ad0_len)
+			ad0 = NULL;
+
+		break;
+	default:
+		return 0;
+	}
 
 	va_start(va, num_attrs);
 
@@ -500,7 +645,7 @@ size_t dpp_append_wrapped_data(const void *ad0, size_t ad0_len,
 
 	va_end(va);
 
-	if (to_len < attrs_len + 4 + 16)
+	if (frame_len - (to - frame) < attrs_len + 4 + 16)
 		return false;
 
 	plaintext = l_malloc(attrs_len);
diff --git a/src/dpp-util.h b/src/dpp-util.h
index dc8a894b..387750aa 100644
--- a/src/dpp-util.h
+++ b/src/dpp-util.h
@@ -148,9 +148,8 @@ uint8_t *dpp_unwrap_attr(const void *ad0, size_t ad0_len, const void *ad1,
 				size_t *unwrapped_len);
 size_t dpp_append_attr(uint8_t *to, enum dpp_attribute_type type,
 				void *attr, size_t attr_len);
-size_t dpp_append_wrapped_data(const void *ad0, size_t ad0_len, const void *ad1,
-				size_t ad1_len, uint8_t *to, size_t to_len,
-				const void *key, size_t key_len,
+size_t dpp_append_wrapped_data(const uint8_t *frame, size_t frame_len,
+				uint8_t *to, const void *key, size_t key_len,
 				size_t num_attrs, ...);
 
 char *dpp_generate_uri(const uint8_t *asn1, size_t asn1_len, uint8_t version,
diff --git a/src/dpp.c b/src/dpp.c
index 5aac22a7..d710aa98 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -758,6 +758,9 @@ static void dpp_configuration_start(struct dpp_sm *dpp, const uint8_t *addr)
 	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);
 
@@ -779,7 +782,8 @@ static void dpp_configuration_start(struct dpp_sm *dpp, const uint8_t *addr)
 	 * 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(NULL, 0, NULL, 0, ptr, sizeof(frame),
+	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);
@@ -800,11 +804,15 @@ static void send_config_result(struct dpp_sm *dpp, const uint8_t *to)
 	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(frame + 26, 6, ptr, 0, ptr,
-			sizeof(frame), dpp->ke, dpp->key_len, 2,
+	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);
 
@@ -1163,6 +1171,7 @@ static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
 	size_t json_len;
 	uint8_t *ptr = frame;
 	uint8_t *lptr;
+	struct mmpdu_header *hdr = (struct mmpdu_header *)frame;
 
 	memset(frame, 0, sizeof(frame));
 
@@ -1205,19 +1214,19 @@ static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status)
 		json = dpp_configuration_to_json(dpp->config);
 		json_len = strlen(json);
 
-		ptr += dpp_append_wrapped_data(lptr + 2, ptr - lptr - 2,
-						NULL, 0, ptr, sizeof(frame),
-						dpp->ke, dpp->key_len, 2,
-						DPP_ATTR_ENROLLEE_NONCE,
-						dpp->nonce_len, dpp->e_nonce,
-						DPP_ATTR_CONFIGURATION_OBJECT,
-						json_len, 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(lptr + 2, ptr - lptr - 2,
-						NULL, 0, ptr, sizeof(frame),
-						dpp->ke, dpp->key_len, 2,
-						DPP_ATTR_ENROLLEE_NONCE,
-						dpp->nonce_len, dpp->e_nonce);
+		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);
 
@@ -1494,7 +1503,6 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 {
 	uint8_t frame[512];
 	uint8_t *ptr = frame;
-	uint8_t *attrs;
 	uint8_t status = DPP_STATUS_OK;
 	uint64_t r_proto_key[L_ECC_MAX_DIGITS * 2];
 	uint8_t version = 2;
@@ -1502,6 +1510,9 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 	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));
 
 	l_ecc_point_get_data(dpp->own_proto_public, r_proto_key,
 				sizeof(r_proto_key));
@@ -1509,7 +1520,6 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
 				DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
-	attrs = 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);
@@ -1538,8 +1548,9 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 
 	wrapped2_len += 16;
 
-	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(frame), dpp->k2, dpp->key_len, 4,
+	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,
@@ -1694,23 +1705,25 @@ static void dpp_auth_request_failed(struct dpp_sm *dpp,
 {
 	uint8_t frame[128];
 	uint8_t *ptr = frame;
-	uint8_t *attrs;
 	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);
-	attrs = 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(frame + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(frame) - (ptr - attrs), k1, dpp->key_len, 2,
+	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);
@@ -1765,12 +1778,14 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 {
 	uint8_t frame[256];
 	uint8_t *ptr = frame;
-	uint8_t *attrs;
 	uint64_t i_proto_key[L_ECC_MAX_DIGITS * 2];
 	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) {
@@ -1784,8 +1799,6 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
 				DPP_FRAME_AUTHENTICATION_REQUEST, ptr);
-	attrs = 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,
@@ -1802,8 +1815,9 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_CHANNEL, pair, 2);
 	}
 
-	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs,
-			ptr, sizeof(frame), dpp->k1, dpp->key_len, 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);
@@ -1857,9 +1871,11 @@ static void dpp_send_commit_reveal_request(struct dpp_sm *dpp)
 	struct iovec iov;
 	uint8_t frame[512];
 	uint8_t *ptr = frame;
-	uint8_t zero = 0;
 	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));
 
@@ -1867,8 +1883,9 @@ static void dpp_send_commit_reveal_request(struct dpp_sm *dpp)
 					dpp->peer_addr,
 					DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST,
 					ptr);
-	ptr += dpp_append_wrapped_data(frame + 26, 6, &zero, 1, ptr,
-			sizeof(frame), dpp->z, dpp->z_len, 2,
+	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);
 
@@ -2264,13 +2281,14 @@ static void dpp_send_authenticate_confirm(struct dpp_sm *dpp)
 	struct iovec iov;
 	uint8_t frame[256];
 	uint8_t *ptr = frame;
-	uint8_t *attrs;
 	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);
-	attrs = 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);
@@ -2278,8 +2296,9 @@ static void dpp_send_authenticate_confirm(struct dpp_sm *dpp)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
 					dpp->own_boot_hash, 32);
 
-	ptr += dpp_append_wrapped_data(frame + 26, 6, attrs, ptr - attrs, ptr,
-			sizeof(frame), dpp->ke, dpp->key_len, 1,
+	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);
 
@@ -3301,19 +3320,21 @@ static void dpp_send_commit_reveal_response(struct dpp_sm *dpp,
 {
 	uint8_t frame[256];
 	uint8_t *ptr = frame;
-	uint8_t one = 1;
 	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;
 
-	b_len = l_ecc_point_get_data(dpp->boot_public, b_pub, sizeof(b_pub));
+	memset(frame, 0, sizeof(frame));
 
+	b_len = l_ecc_point_get_data(dpp->boot_public, b_pub, sizeof(b_pub));
 
 	ptr += dpp_build_header(own_mac, dpp->peer_addr,
 				DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE, ptr);
-	ptr += dpp_append_wrapped_data(frame + 26, 6, &one, 1, ptr,
-			sizeof(frame), dpp->z, dpp->z_len, 2,
+	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);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 3/5] dpp-util: add dpp_append_point
  2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
  2024-03-13 17:13 ` [RFC 1/5] dpp: prep for moving AAD within dpp_append_wrapped_data James Prestwood
  2024-03-13 17:13 ` [RFC 2/5] dpp-util: move AAD logic within dpp_append_wrapped_attributes James Prestwood
@ 2024-03-13 17:13 ` James Prestwood
  2024-03-13 17:13 ` [RFC 4/5] dpp: use dpp_append_point James Prestwood
  2024-03-13 17:13 ` [RFC 5/5] dpp-common: Skeleton for common DPP module James Prestwood
  4 siblings, 0 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Any time DPP needs to append a point it has to use a temporary
buffer to copy into, then copy that into the message buffer.
Instead of this add a special purpose API to add the type/length
then copy the data directly into the message buffer.
---
 src/dpp-util.c | 13 +++++++++++++
 src/dpp-util.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/src/dpp-util.c b/src/dpp-util.c
index ada7ed96..81f34047 100644
--- a/src/dpp-util.c
+++ b/src/dpp-util.c
@@ -697,6 +697,19 @@ size_t dpp_append_wrapped_data(const uint8_t *frame, size_t frame_len,
 	return attrs_len + 4 + 16;
 }
 
+size_t dpp_append_point(uint8_t *to, enum dpp_attribute_type type,
+				struct l_ecc_point *point)
+{
+	const struct l_ecc_curve *c = l_ecc_point_get_curve(point);
+	size_t len = l_ecc_curve_get_scalar_bytes(c) * 2;
+
+	l_put_le16(type, to);
+	l_put_le16(len, to + 2);
+	l_ecc_point_get_data(point, to + 4, len);
+
+	return len + 4;
+}
+
 /*
  * EasyConnect 2.0 Table 3. Key and Nonce Length Dependency on Prime Length
  */
diff --git a/src/dpp-util.h b/src/dpp-util.h
index 387750aa..1ff9004d 100644
--- a/src/dpp-util.h
+++ b/src/dpp-util.h
@@ -151,6 +151,8 @@ size_t dpp_append_attr(uint8_t *to, enum dpp_attribute_type type,
 size_t dpp_append_wrapped_data(const uint8_t *frame, size_t frame_len,
 				uint8_t *to, const void *key, size_t key_len,
 				size_t num_attrs, ...);
+size_t dpp_append_point(uint8_t *to, enum dpp_attribute_type type,
+				struct l_ecc_point *point);
 
 char *dpp_generate_uri(const uint8_t *asn1, size_t asn1_len, uint8_t version,
 			const uint8_t *mac, const uint32_t *freqs,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 4/5] dpp: use dpp_append_point
  2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
                   ` (2 preceding siblings ...)
  2024-03-13 17:13 ` [RFC 3/5] dpp-util: add dpp_append_point James Prestwood
@ 2024-03-13 17:13 ` James Prestwood
  2024-03-13 17:13 ` [RFC 5/5] dpp-common: Skeleton for common DPP module James Prestwood
  4 siblings, 0 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Use dpp_append_point where possible to avoid temporarily copying data
---
 src/dpp.c | 28 ++++++----------------------
 1 file changed, 6 insertions(+), 22 deletions(-)

diff --git a/src/dpp.c b/src/dpp.c
index d710aa98..47ebd495 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -1504,7 +1504,6 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 	uint8_t frame[512];
 	uint8_t *ptr = frame;
 	uint8_t status = DPP_STATUS_OK;
-	uint64_t r_proto_key[L_ECC_MAX_DIGITS * 2];
 	uint8_t version = 2;
 	struct iovec iov;
 	uint8_t wrapped2_plaintext[dpp->key_len + 4];
@@ -1514,9 +1513,6 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 
 	memset(frame, 0, sizeof(frame));
 
-	l_ecc_point_get_data(dpp->own_proto_public, r_proto_key,
-				sizeof(r_proto_key));
-
 	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
 				DPP_FRAME_AUTHENTICATION_RESPONSE, ptr);
@@ -1526,8 +1522,8 @@ static void send_authenticate_response(struct dpp_sm *dpp)
 	if (dpp->mutual_auth)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
 				dpp->peer_boot_hash, 32);
-	ptr += dpp_append_attr(ptr, DPP_ATTR_RESPONDER_PROTOCOL_KEY,
-				r_proto_key, dpp->key_len * 2);
+	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) */
@@ -1778,7 +1774,6 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 {
 	uint8_t frame[256];
 	uint8_t *ptr = frame;
-	uint64_t i_proto_key[L_ECC_MAX_DIGITS * 2];
 	uint8_t version = 2;
 	struct iovec iov;
 	struct station *station = station_find(netdev_get_ifindex(dpp->netdev));
@@ -1793,9 +1788,6 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 		return false;
 	}
 
-	l_ecc_point_get_data(dpp->own_proto_public, i_proto_key,
-				sizeof(i_proto_key));
-
 	ptr += dpp_build_header(netdev_get_address(dpp->netdev),
 				dpp->peer_addr,
 				DPP_FRAME_AUTHENTICATION_REQUEST, ptr);
@@ -1803,8 +1795,8 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp)
 				dpp->peer_boot_hash, 32);
 	ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_BOOT_KEY_HASH,
 				dpp->own_boot_hash, 32);
-	ptr += dpp_append_attr(ptr, DPP_ATTR_INITIATOR_PROTOCOL_KEY,
-				i_proto_key, dpp->key_len * 2);
+	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 &&
@@ -1835,7 +1827,6 @@ static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp)
 	uint8_t hdr[32];
 	uint8_t attrs[256];
 	uint8_t *ptr = attrs;
-	uint64_t m_data[L_ECC_MAX_DIGITS * 2];
 	uint16_t group;
 	struct iovec iov[2];
 	const uint8_t *own_mac = netdev_get_address(dpp->netdev);
@@ -1855,10 +1846,7 @@ static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp)
 		ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER,
 					dpp->pkex_id, strlen(dpp->pkex_id));
 
-	l_ecc_point_get_data(dpp->pkex_m, m_data, sizeof(m_data));
-
-	ptr += dpp_append_attr(ptr, DPP_ATTR_ENCRYPTED_KEY,
-				m_data, dpp->key_len * 2);
+	ptr += dpp_append_point(ptr, DPP_ATTR_ENCRYPTED_KEY, dpp->pkex_m);
 
 	iov[1].iov_base = attrs;
 	iov[1].iov_len = ptr - attrs;
@@ -3018,7 +3006,6 @@ static void dpp_send_pkex_exchange_response(struct dpp_sm *dpp,
 	uint8_t hdr[32];
 	uint8_t attrs[256];
 	uint8_t *ptr = attrs;
-	uint64_t n_data[L_ECC_MAX_DIGITS * 2];
 	uint16_t group;
 	uint8_t status = DPP_STATUS_OK;
 	struct iovec iov[2];
@@ -3036,10 +3023,7 @@ static void dpp_send_pkex_exchange_response(struct dpp_sm *dpp,
 		ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER,
 					dpp->pkex_id, strlen(dpp->pkex_id));
 
-	l_ecc_point_get_data(n, n_data, sizeof(n_data));
-
-	ptr += dpp_append_attr(ptr, DPP_ATTR_ENCRYPTED_KEY,
-				n_data, dpp->key_len * 2);
+	ptr += dpp_append_point(ptr, DPP_ATTR_ENCRYPTED_KEY, n);
 
 	iov[1].iov_base = attrs;
 	iov[1].iov_len = ptr - attrs;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC 5/5] dpp-common: Skeleton for common DPP module
  2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
                   ` (3 preceding siblings ...)
  2024-03-13 17:13 ` [RFC 4/5] dpp: use dpp_append_point James Prestwood
@ 2024-03-13 17:13 ` James Prestwood
  4 siblings, 0 replies; 6+ messages in thread
From: James Prestwood @ 2024-03-13 17:13 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

In order to expand the features for DPP e.g. TCP or a DPP controller
the state machine needs to be both transport agnostic and buildable
for other apps outside of IWD-core.

To do this the core DPP state machine is being moved into a common
module. The consumers of the common SM will create a dpp_sm object
for each protocol run, and destroy it afterwards. The SM will take
a write callback, event callback, the boostrapping keys, and expose
a read handler:

 - The write callback will be called by the SM whenever there is a
   frame to be sent out. In order to support 802.11 encapsulation
   dpp_sm_set_write_handler can be used to notify the SM that writes
   are allowed or disallowed (by passing NULL). This is done to
   allow the 802.11 encapsulating module to prepare any offchannel
   requests before sending out frames.
 - The event callback is called by the SM whenever there are events
   requiring some handling by the encapsulating protocol, or when
   DPP has succeeded or failed.
 - The read handler can be called by the encapsulating protocol
   in order to RX frames to the SM.

Making the SM common will allow both pure-802.11 DPP and
DPP-over-TCP to utilize the same state machine. In addition a
DPP-controller can now be implemented using the common SM but be
entirely standalone from IWD.
---
 src/dpp-common.c | 517 +++++++++++++++++++++++++++++++++++++++++++++++
 src/dpp-common.h | 109 ++++++++++
 2 files changed, 626 insertions(+)
 create mode 100644 src/dpp-common.c
 create mode 100644 src/dpp-common.h

diff --git a/src/dpp-common.c b/src/dpp-common.c
new file mode 100644
index 00000000..af0645df
--- /dev/null
+++ b/src/dpp-common.c
@@ -0,0 +1,517 @@
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2024  Locus Robotics
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <ell/ell.h>
+
+#include "linux/nl80211.h"
+
+#include "src/missing.h"
+#include "src/dbus.h"
+#include "src/netdev.h"
+#include "src/module.h"
+#include "src/dpp-util.h"
+#include "src/band.h"
+#include "src/frame-xchg.h"
+#include "src/offchannel.h"
+#include "src/wiphy.h"
+#include "src/ie.h"
+#include "src/iwd.h"
+#include "src/util.h"
+#include "src/crypto.h"
+#include "src/mpdu.h"
+#include "ell/useful.h"
+#include "src/common.h"
+#include "src/json.h"
+#include "src/storage.h"
+#include "src/station.h"
+#include "src/scan.h"
+#include "src/network.h"
+#include "src/handshake.h"
+#include "src/nl80211util.h"
+#include "src/knownnetworks.h"
+#include "src/dpp-common.h"
+
+#define DPP_HDR_LEN			6
+#define DPP_ACTION_VENDOR_SPECIFIC	0x09
+#define DPP_ACTION_GAS_REQUEST		0x0a
+#define DPP_ACTION_GAS_RESPONSE		0x0b
+#define DPP_AUTH_PROTO_TIMEOUT		10
+#define DPP_PKEX_PROTO_TIMEOUT		120
+
+struct dpp_sm {
+	char *uri;
+	uint8_t role;
+
+	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];
+	uint8_t own_chirp_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;
+
+	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 auth/config/PKEX protocols */
+	uint64_t proto_timeout;
+	struct l_timeout *timeout;
+
+	struct dpp_configuration *config;
+
+	/* 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;
+	uint8_t pkex_own_mac[6];
+	uint8_t pkex_peer_mac[6];
+	/* Set to either own/peer mac depending on configuration */
+	const uint8_t *mac_initiator;
+	const uint8_t *mac_responder;
+
+	/*
+	 * Since the authenticate frame may request a channel switch we do need
+	 * to expose this detail within the common code.
+	 */
+	uint8_t channel[2];
+
+	uint8_t *frame_pending;
+	size_t frame_len;
+	dpp_write_cb_t write;
+	dpp_event_cb_t event_cb;
+	void *user_data;
+
+	bool skip_presence : 1;
+	bool mutual_auth : 1;
+	bool initiator : 1;
+};
+
+static void dpp_failed(struct dpp_sm *dpp)
+{
+	if (dpp->event_cb)
+		dpp->event_cb(DPP_EVENT_FAILED, NULL, dpp->user_data);
+}
+
+static void dpp_protocol_timeout(struct l_timeout *timeout, void *user_data)
+{
+	struct dpp_sm *dpp = user_data;
+
+	l_debug("DPP timed out");
+
+	dpp_failed(dpp);
+}
+
+static void dpp_reset_protocol_timer(struct dpp_sm *dpp, uint64_t time)
+{
+	if (dpp->timeout)
+		l_timeout_modify(dpp->timeout, time);
+	else
+		dpp->timeout = l_timeout_create(time, dpp_protocol_timeout,
+						dpp, NULL);
+}
+
+struct dpp_sm *dpp_sm_new(dpp_event_cb_t event,
+				const struct l_ecc_point *boot_public,
+				const struct l_ecc_scalar *boot_private,
+				void *user_data)
+{
+	struct dpp_sm *dpp = l_new(struct dpp_sm, 1);
+
+	dpp->state = DPP_STATE_NOTHING;
+	dpp->curve = l_ecc_point_get_curve(boot_public);
+	dpp->key_len = l_ecc_curve_get_scalar_bytes(dpp->curve);
+	dpp->nonce_len = dpp_nonce_len_from_key_len(dpp->key_len);
+	dpp->boot_public = l_ecc_point_clone(boot_public);
+	dpp->boot_private = l_ecc_scalar_clone(boot_private);
+	dpp->own_asn1 = dpp_point_to_asn1(dpp->boot_public, &dpp->own_asn1_len);
+	dpp->event_cb = event;
+	dpp->user_data = user_data;
+
+	dpp_hash(L_CHECKSUM_SHA256, dpp->own_boot_hash, 1, dpp->own_asn1,
+			dpp->own_asn1_len);
+	dpp_hash(L_CHECKSUM_SHA256, dpp->own_chirp_hash, 2, "chirp",
+			strlen("chirp"), dpp->own_asn1, dpp->own_asn1_len);
+
+	return dpp;
+}
+
+void dpp_sm_set_write_handler(struct dpp_sm *dpp, dpp_write_cb_t write)
+{
+	dpp->write = write;
+
+	if (!dpp->write)
+		return;
+
+	/* Handle writing frame */
+}
+
+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_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;
+	}
+
+	if (dpp->peer_encr_key) {
+		l_ecc_point_free(dpp->peer_encr_key);
+		dpp->peer_encr_key = NULL;
+	}
+}
+
+void dpp_sm_free(struct dpp_sm *dpp)
+{
+	if (dpp->boot_public) {
+		l_ecc_point_free(dpp->boot_public);
+		dpp->boot_public = NULL;
+	}
+
+	if (dpp->boot_private) {
+		l_ecc_scalar_free(dpp->boot_private);
+		dpp->boot_private = NULL;
+	}
+
+	if (dpp->timeout) {
+		l_timeout_remove(dpp->timeout);
+		dpp->timeout = NULL;
+	}
+
+	if (dpp->config) {
+		dpp_configuration_free(dpp->config);
+		dpp->config = NULL;
+	}
+
+	if (dpp->peer_asn1) {
+		l_free(dpp->peer_asn1);
+		dpp->peer_asn1 = NULL;
+	}
+
+	if (dpp->own_asn1) {
+		l_free(dpp->own_asn1);
+		dpp->own_asn1 = NULL;
+	}
+
+	if (dpp->frame_pending) {
+		l_free(dpp->frame_pending);
+		dpp->frame_pending = NULL;
+	}
+
+	dpp->state = DPP_STATE_NOTHING;
+	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_free_pending_pkex_data(dpp);
+
+	dpp_free_auth_data(dpp);
+
+	l_free(dpp);
+}
+
+void dpp_sm_set_peer_bootstrap(struct dpp_sm *dpp,
+					struct l_ecc_point *public)
+{
+	dpp->peer_boot_public = public;
+	dpp->peer_asn1 = dpp_point_to_asn1(public, &dpp->peer_asn1_len);
+
+	dpp_hash(L_CHECKSUM_SHA256, dpp->peer_boot_hash, 1, dpp->peer_asn1,
+			dpp->peer_asn1_len);
+}
+
+const uint8_t *dpp_sm_get_own_asn1(struct dpp_sm *dpp, size_t *len)
+{
+	*len = dpp->own_asn1_len;
+
+	return dpp->own_asn1;
+}
+
+void dpp_sm_set_configuration(struct dpp_sm *dpp,
+					struct dpp_configuration *config)
+{
+	dpp->config = config;
+}
+
+const struct dpp_configuration *dpp_sm_get_configuration(struct dpp_sm *dpp)
+{
+	return dpp->config;
+}
+
+void dpp_sm_set_skip_presence(struct dpp_sm *dpp, bool skip)
+{
+	dpp->skip_presence = skip;
+}
+
+void dpp_sm_set_channel(struct dpp_sm *dpp, uint8_t oper_class, uint8_t channel)
+{
+	dpp->channel[0] = oper_class;
+	dpp->channel[1] = channel;
+}
+
+enum dpp_state dpp_sm_get_state(struct dpp_sm *dpp)
+{
+	return dpp->state;
+}
+
+bool dpp_sm_start_initiator(struct dpp_sm *dpp)
+{
+	if (L_WARN_ON(!dpp->peer_boot_public))
+		return false;
+
+	dpp->initiator = true;
+
+	/* Generate the keys for this protocol run */
+	l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private,
+					&dpp->own_proto_public);
+
+	l_getrandom(dpp->i_nonce, dpp->nonce_len);
+
+	dpp->m = dpp_derive_k1(dpp->peer_boot_public,
+				dpp->proto_private, dpp->k1);
+
+	if (dpp->config)
+		dpp->role = DPP_CAPABILITY_CONFIGURATOR;
+	else
+		dpp->role = DPP_CAPABILITY_ENROLLEE;
+
+	dpp->state = DPP_STATE_PRESENCE;
+
+	return true;
+}
+
+bool dpp_sm_start_responder(struct dpp_sm *dpp)
+{
+	l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private,
+					&dpp->own_proto_public);
+	dpp->initiator = false;
+
+	if (dpp->config)
+		dpp->role = DPP_CAPABILITY_CONFIGURATOR;
+	else
+		dpp->role = DPP_CAPABILITY_ENROLLEE;
+
+	dpp->state = DPP_STATE_PRESENCE;
+
+	return true;
+}
+
+void dpp_sm_set_pkex_identifier(struct dpp_sm *dpp, const char *identifier)
+{
+	dpp->pkex_id = l_strdup(identifier);
+}
+
+void dpp_sm_set_pkex_key(struct dpp_sm *dpp, const char *key)
+{
+	dpp->pkex_key = l_strdup(key);
+}
+
+void dpp_sm_set_pkex_own_mac(struct dpp_sm *dpp, const uint8_t *mac)
+{
+	memcpy(dpp->pkex_own_mac, mac, 6);
+}
+
+void dpp_sm_set_pkex_peer_mac(struct dpp_sm *dpp, const uint8_t *mac)
+{
+	memcpy(dpp->pkex_peer_mac, mac, 6);
+
+	if (dpp->initiator) {
+		dpp->mac_responder = dpp->pkex_peer_mac;
+		dpp->mac_initiator = dpp->pkex_own_mac;
+	} else {
+		dpp->mac_initiator = dpp->pkex_peer_mac;
+		dpp->mac_responder = dpp->pkex_own_mac;
+	}
+}
+
+bool dpp_sm_pkex_start_initiator(struct dpp_sm *dpp)
+{
+	_auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL;
+
+	if (!dpp->pkex_key)
+		return false;
+
+	dpp->role = dpp->config ? DPP_CAPABILITY_CONFIGURATOR :
+					DPP_CAPABILITY_ENROLLEE;
+
+	/*
+	 * "DPP R2 devices are expected to use PKEXv1 by default"
+	 *
+	 * TODO: Support setting version (v2 required for TCP encapsulation)
+	 */
+	dpp->pkex_version = 1;
+
+	if (!l_ecdh_generate_key_pair(dpp->curve, &dpp->pkex_private,
+					&dpp->pkex_public))
+		return false;
+
+	/*
+	 * "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,
+				dpp->pkex_own_mac);
+	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->initiator = true;
+
+	dpp->mac_initiator = dpp->pkex_own_mac;
+	/* Won't know until we receive a response */
+	dpp->mac_responder = NULL;
+
+	dpp_reset_protocol_timer(dpp, DPP_AUTH_PROTO_TIMEOUT);
+
+	/* Send exchange request */
+
+	return true;
+
+failed:
+	return false;
+}
+
+bool dpp_sm_pkex_start_responder(struct dpp_sm *dpp)
+{
+	dpp->initiator = false;
+
+	dpp->mac_responder = dpp->pkex_own_mac;
+	/* Won't know until we receive the first frame */
+	dpp->mac_initiator = NULL;
+
+	dpp->role = dpp->config ? DPP_CAPABILITY_CONFIGURATOR :
+					DPP_CAPABILITY_ENROLLEE;
+	dpp->state = DPP_STATE_PKEX_EXCHANGE;
+	dpp->pkex_version = 1;
+
+	dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
+
+	return true;
+}
+
+void dpp_handle_rx(struct dpp_sm *dpp, const uint8_t *data, size_t len)
+{
+	/* Handle frame */
+}
diff --git a/src/dpp-common.h b/src/dpp-common.h
new file mode 100644
index 00000000..19ec45ac
--- /dev/null
+++ b/src/dpp-common.h
@@ -0,0 +1,109 @@
+/*
+ *
+ *  Wireless daemon for Linux
+ *
+ *  Copyright (C) 2024  Locus Robotics
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct dpp_sm;
+struct l_ecc_point;
+struct l_ecc_scalar;
+
+enum dpp_state {
+	DPP_STATE_NOTHING,
+	DPP_STATE_PRESENCE,
+	DPP_STATE_PKEX_EXCHANGE,
+	DPP_STATE_PKEX_COMMIT_REVEAL,
+	DPP_STATE_AUTHENTICATING,
+	DPP_STATE_CONFIGURING,
+};
+
+enum dpp_capability {
+	DPP_CAPABILITY_ENROLLEE = 0x01,
+	DPP_CAPABILITY_CONFIGURATOR = 0x02,
+};
+
+enum dpp_event {
+	/*
+	 * PEER_ACCEPTED indicates an initial DPP frame has been received and
+	 * accepted. This could be either a PKEX or an auth frame when DPP is
+	 * running as either a configurator or enrollee. This should be
+	 * used by the encapsulating protocol to note the peer address (MAC
+	 * or IP) and from then on only accept frames from this peer until DPP
+	 * has completed.
+	 */
+	DPP_EVENT_PEER_ACCEPTED,
+	/*
+	 * The authenticate request frame included a channel attribute. The
+	 * encapsulating protocol must switch to this channel to continue the
+	 * protocol (only applicable to 802.11 encapsulation). Event data is
+	 * two bytes: [oper_class, channel]
+	 */
+	DPP_EVENT_CHANNEL_SWITCH,
+	/*
+	 * A key corresponding to an identifier (set in event_data) is now
+	 * required. The encapsulating protocol must retrieve the key and
+	 * notify using dpp_sm_set_pkex_key().
+	 */
+	DPP_EVENT_PKEX_KEY_REQUESTED,
+	DPP_EVENT_SUCCESS,
+	DPP_EVENT_FAILED,
+};
+
+typedef void (*dpp_event_cb_t)(enum dpp_event event, const void *event_data,
+				void *user_data);
+
+typedef void (*dpp_write_cb_t)(const uint8_t *data, size_t len,
+				void *user_data);
+
+struct dpp_sm *dpp_sm_new(dpp_event_cb_t event,
+				const struct l_ecc_point *boot_public,
+				const struct l_ecc_scalar *boot_private,
+				void *user_data);
+
+void dpp_sm_free(struct dpp_sm *dpp);
+
+void dpp_handle_rx(struct dpp_sm *dpp, const uint8_t *data, size_t len);
+void dpp_sm_set_write_handler(struct dpp_sm *dpp, dpp_write_cb_t write);
+
+void dpp_sm_set_peer_bootstrap(struct dpp_sm *dpp,
+					struct l_ecc_point *public);
+void dpp_sm_set_own_bootstrap(struct dpp_sm *dpp, struct l_ecc_point *public,
+					struct l_ecc_scalar *private);
+const uint8_t *dpp_sm_get_own_asn1(struct dpp_sm *dpp, size_t *len);
+
+void dpp_sm_set_configuration(struct dpp_sm *dpp,
+					struct dpp_configuration *config);
+const struct dpp_configuration *dpp_sm_get_configuration(struct dpp_sm *dpp);
+
+void dpp_sm_set_skip_presence(struct dpp_sm *dpp, bool skip);
+
+void dpp_sm_set_channel(struct dpp_sm *dpp, uint8_t oper_class,
+			uint8_t channel);
+enum dpp_state dpp_sm_get_state(struct dpp_sm *dpp);
+
+bool dpp_sm_start_initiator(struct dpp_sm *dpp);
+bool dpp_sm_start_responder(struct dpp_sm *dpp);
+
+void dpp_sm_set_pkex_identifier(struct dpp_sm *dpp, const char *identifier);
+void dpp_sm_set_pkex_key(struct dpp_sm *dpp, const char *key);
+void dpp_sm_set_pkex_own_mac(struct dpp_sm *dpp, const uint8_t *mac);
+void dpp_sm_set_pkex_peer_mac(struct dpp_sm *dpp, const uint8_t *mac);
+
+bool dpp_sm_pkex_start_initiator(struct dpp_sm *dpp);
+bool dpp_sm_pkex_start_responder(struct dpp_sm *dpp);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-03-13 17:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-13 17:13 [RFC 0/5] Initial prep/skeleton for isolating core DPP protocol James Prestwood
2024-03-13 17:13 ` [RFC 1/5] dpp: prep for moving AAD within dpp_append_wrapped_data James Prestwood
2024-03-13 17:13 ` [RFC 2/5] dpp-util: move AAD logic within dpp_append_wrapped_attributes James Prestwood
2024-03-13 17:13 ` [RFC 3/5] dpp-util: add dpp_append_point James Prestwood
2024-03-13 17:13 ` [RFC 4/5] dpp: use dpp_append_point James Prestwood
2024-03-13 17:13 ` [RFC 5/5] dpp-common: Skeleton for common DPP module James Prestwood

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).