Doesn't create global config file or its directory (/etc/iwd/)
by Diederik de Haas
Hi,
I recently filed a Debian Bug against iwd and this is a forward for it:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1002575
"I needed the "EnableNetworkConfiguration=true" setting, which IIUC
should be done in /etc/iwd/main.conf, but I noticed that that file
and directory didn't exist. I resolved it by using mkdir and creating
the file with vim (as root) and I'm assuming/hoping things like
permissions are set correctly. But I did wonder whether I was doing it
incorrectly (and I may have, but it's working)."
The Debian maintainer informed me that there isn't such a config file in the
upstream source code and I think it would be helpful if the directory with the
correct permissions and the config file, which could f.e. only contain a
commented reference to the iwd.config man page, would be created OOTB.
Cheers,
Diederik
5 months, 3 weeks
iwd doesn't work with openresolv
by Yuri Kanivetsky
Hi,
If I run it as is, I get:
Dec 27 13:27:21 yuri iwd[716]: cp: cannot create regular file
'/etc/resolv.conf.bak': Read-only file system
Dec 27 13:27:21 yuri iwd[717]: /usr/lib/resolvconf/libc: line 230:
/etc/resolv.conf: Read-only file system
Dec 27 13:27:21 yuri iwd[761]: cp: cannot create regular file
'/etc/resolv.conf.bak': Read-only file system
Dec 27 13:27:21 yuri iwd[762]: /usr/lib/resolvconf/libc: line 230:
/etc/resolv.conf: Read-only file system
I can work around it by:
touch /etc/resolv.conf.bak
and overriding:
[Service]
ReadWritePaths=/etc/resolv.conf.bak
ReadWritePaths=/etc/resolv.conf
Others suggested another way to fix it:
RuntimeDirectory=resolvconf
ReadWritePaths=/etc/resolv.conf
https://bugs.archlinux.org/task/67069
Can src/iwd.service.in be adjusted?
Regards,
Yuri
6 months
[PATCH 1/2] test-runner: catch exception on test file removal
by James Prestwood
Without catching this can result in a fatal error, ending the
test run.
---
tools/test-runner | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/test-runner b/tools/test-runner
index 7fa8b840..b5c4f777 100755
--- a/tools/test-runner
+++ b/tools/test-runner
@@ -1380,7 +1380,10 @@ def post_test(ctx, to_copy):
allowed = ['phonesim.conf', 'certs', 'secrets', 'iwd']
for f in [f for f in os.listdir('/tmp') if f not in allowed]:
dbg("File %s was not cleaned up!" % f)
- os.remove('/tmp/' + f)
+ try:
+ os.remove('/tmp/' + f)
+ except:
+ pass
def print_results(results):
table = PrettyTable(['Test', colored('Passed', 'green'), colored('Failed', 'red'), \
--
2.31.1
6 months, 1 week
[PATCH] auto-t: add missing config files (testOWE-transition)
by James Prestwood
---
autotests/testOWE-transition/ssidOWE-2.conf | 9 +++++++++
autotests/testOWE-transition/ssidOpen-2.conf | 3 +++
2 files changed, 12 insertions(+)
create mode 100644 autotests/testOWE-transition/ssidOWE-2.conf
create mode 100644 autotests/testOWE-transition/ssidOpen-2.conf
diff --git a/autotests/testOWE-transition/ssidOWE-2.conf b/autotests/testOWE-transition/ssidOWE-2.conf
new file mode 100644
index 00000000..a8a9023c
--- /dev/null
+++ b/autotests/testOWE-transition/ssidOWE-2.conf
@@ -0,0 +1,9 @@
+ssid=owe-hidden-2
+bssid=02:00:00:00:f3:00
+channel=1
+ignore_broadcast_ssid=1
+ieee80211w=1
+
+wpa=2
+wpa_key_mgmt=OWE
+rsn_pairwise=CCMP
diff --git a/autotests/testOWE-transition/ssidOpen-2.conf b/autotests/testOWE-transition/ssidOpen-2.conf
new file mode 100644
index 00000000..0a9f7628
--- /dev/null
+++ b/autotests/testOWE-transition/ssidOpen-2.conf
@@ -0,0 +1,3 @@
+channel=1
+ssid=transition-2
+bssid=02:00:00:00:f2:00
--
2.31.1
6 months, 1 week
[PATCH 1/2] dpp: zero nonces/keys on dpp_reset
by James Prestwood
---
src/dpp.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/dpp.c b/src/dpp.c
index 48343445..941c3f07 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -163,6 +163,12 @@ static void dpp_reset(struct dpp_sm *dpp)
dpp->state = DPP_STATE_NOTHING;
+ 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->k2, dpp->key_len);
+
dpp_free_auth_data(dpp);
}
--
2.31.1
6 months, 1 week
[PATCH v2 1/6] dpp: add timeout for auth/config protocols
by James Prestwood
This also allows the card to re-issue ROC if it ends in the middle of
authenticating or configuring as well as add a maximum timeout for
auth/config protocols.
IO errors were also handled as these sometimes can happen with
certain drivers but are not fatal.
---
src/dpp.c | 48 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 38 insertions(+), 10 deletions(-)
v2:
* Moved timeout cleanup into this patch
diff --git a/src/dpp.c b/src/dpp.c
index 69dbeb1e..8288aa6c 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -98,6 +98,9 @@ struct dpp_sm {
struct l_ecc_point *i_proto_public;
uint8_t diag_token;
+
+ /* Timeout of either auth/config protocol */
+ struct l_timeout *timeout;
};
static void dpp_free_auth_data(struct dpp_sm *dpp)
@@ -135,6 +138,11 @@ static void dpp_reset(struct dpp_sm *dpp)
dpp->offchannel_id = 0;
}
+ if (dpp->timeout) {
+ l_timeout_remove(dpp->timeout);
+ dpp->timeout = NULL;
+ }
+
dpp->state = DPP_STATE_NOTHING;
dpp_free_auth_data(dpp);
@@ -239,6 +247,24 @@ static size_t dpp_build_config_header(const uint8_t *src, const uint8_t *dest,
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)
+{
+ if (dpp->timeout)
+ l_timeout_modify(dpp->timeout, 10);
+ else
+ dpp->timeout = l_timeout_create(10, 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.
@@ -733,6 +759,7 @@ static void authenticate_confirm(struct dpp_sm *dpp, const uint8_t *from,
l_debug("Authentication successful");
+ dpp_reset_protocol_timer(dpp);
dpp_configuration_start(dpp, from);
return;
@@ -941,6 +968,7 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from,
memcpy(dpp->auth_addr, from, 6);
dpp->state = DPP_STATE_AUTHENTICATING;
+ dpp_reset_protocol_timer(dpp);
send_authenticate_response(dpp, r_auth);
@@ -1013,6 +1041,12 @@ static void dpp_roc_started(void *user_data)
{
struct dpp_sm *dpp = user_data;
+ /*
+ * If not in presence procedure, just stay on channel.
+ */
+ if (dpp->state != DPP_STATE_PRESENCE)
+ return;
+
dpp_presence_announce(dpp);
}
@@ -1082,6 +1116,8 @@ static void dpp_presence_timeout(int error, void *user_data)
*/
if (error == -ECANCELED)
return;
+ else if (error == -EIO)
+ goto next_roc;
else if (error < 0)
goto protocol_failed;
@@ -1093,16 +1129,7 @@ static void dpp_presence_timeout(int error, void *user_data)
return;
case DPP_STATE_AUTHENTICATING:
case DPP_STATE_CONFIGURING:
- /*
- * TODO: If either the auth or config protocol is running we
- * need to stay on channel until the specified timeouts.
- * Unfortunately the kernel makes this very inconvenient since
- * there is no way to stay on channel indefinitely or any way
- * of knowing what duration the kernel/card actually chooses.
- *
- * For now just treat this as a failure.
- */
- goto protocol_failed;
+ goto next_roc;
}
dpp->freqs_idx++;
@@ -1117,6 +1144,7 @@ static void dpp_presence_timeout(int error, void *user_data)
l_debug("Presence timeout, moving to next frequency %u, duration %u",
dpp->current_freq, dpp->dwell);
+next_roc:
dpp->offchannel_id = offchannel_start(netdev_get_wdev_id(dpp->netdev),
dpp->current_freq, dpp->dwell, dpp_roc_started,
dpp, dpp_presence_timeout);
--
2.31.1
6 months, 2 weeks
[PATCH 1/9] dpp: use frame data directly in unwrap for config response
by James Prestwood
Rather than hard coding ad0, use the actual frame data. There really
isn't a reason this would differ (only status attribute) but just
in case its better to use the frame data directly.
---
src/dpp.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/dpp.c b/src/dpp.c
index 5e125265..69dbeb1e 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -391,7 +391,6 @@ static void dpp_handle_config_response_frame(const struct mmpdu_header *frame,
size_t wrapped_len = 0;
_auto_(l_free) uint8_t *unwrapped = NULL;
struct dpp_configuration *config;
- uint8_t ad0[] = { 0x00, 0x10, 0x01, 0x00, 0x05 };
if (dpp->state != DPP_STATE_CONFIGURING)
return;
@@ -474,7 +473,7 @@ static void dpp_handle_config_response_frame(const struct mmpdu_header *frame,
return;
}
- unwrapped = dpp_unwrap_attr(ad0, sizeof(ad0), NULL, 0, dpp->ke,
+ unwrapped = dpp_unwrap_attr(ptr, wrapped - ptr - 4, NULL, 0, dpp->ke,
dpp->key_len, wrapped, wrapped_len,
&wrapped_len);
if (!unwrapped) {
--
2.31.1
6 months, 2 weeks
[PATCH v6 1/2] dpp: add support for configuration protocol
by James Prestwood
This is a minimal implementation only supporting legacy network
configuration, i.e. only SSID and PSK/passphrase are supported.
Missing features include:
- Fragmentation/comeback delay support
- DPP AKM support
- 8021x/PKEX support
---
src/dpp.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 334 insertions(+)
v6:
* Added length checks to configuration response
diff --git a/src/dpp.c b/src/dpp.c
index dd17cc47..c703de75 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -44,6 +44,8 @@
#include "src/crypto.h"
#include "src/mpdu.h"
#include "ell/useful.h"
+#include "src/common.h"
+#include "src/storage.h"
static uint32_t netdev_watch;
static struct l_genl_family *nl80211;
@@ -53,6 +55,7 @@ enum dpp_state {
DPP_STATE_NOTHING,
DPP_STATE_PRESENCE,
DPP_STATE_AUTHENTICATING,
+ DPP_STATE_CONFIGURING,
};
struct dpp_sm {
@@ -84,6 +87,7 @@ struct dpp_sm {
uint8_t auth_addr[6];
uint8_t r_nonce[32];
uint8_t i_nonce[32];
+ uint8_t e_nonce[32];
uint64_t ke[L_ECC_MAX_DIGITS];
uint64_t k2[L_ECC_MAX_DIGITS];
@@ -92,6 +96,8 @@ struct dpp_sm {
struct l_ecc_point *proto_public;
struct l_ecc_point *i_proto_public;
+
+ uint8_t diag_token;
};
static void dpp_free_auth_data(struct dpp_sm *dpp)
@@ -203,6 +209,327 @@ static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
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[static 37])
+{
+ 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;
+}
+
+/*
+ * 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[3];
+ uint8_t hdr[37];
+ uint8_t attrs[512];
+ size_t json_len = strlen(json);
+ uint8_t *ptr = attrs;
+
+ 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;
+
+ l_getrandom(dpp->e_nonce, dpp->nonce_len);
+
+ /* length */
+ 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(NULL, 0, NULL, 0, ptr, sizeof(attrs),
+ 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);
+
+ iov[1].iov_base = attrs;
+ iov[1].iov_len = ptr - attrs;
+
+ dpp->state = DPP_STATE_CONFIGURING;
+
+ dpp_send_frame(dpp->wdev_id, iov, 2, 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;
+ 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,
+ DPP_ATTR_STATUS, 1, &zero,
+ DPP_ATTR_ENROLLEE_NONCE, dpp->nonce_len, dpp->e_nonce);
+
+ iov[1].iov_base = attrs;
+ iov[1].iov_len = ptr - attrs;
+
+ dpp_send_frame(dpp->wdev_id, iov, 2, dpp->current_freq);
+}
+
+static void dpp_write_config(struct dpp_configuration *config)
+{
+ _auto_(l_free) char *ssid = l_malloc(config->ssid_len + 1);
+ _auto_(l_settings_free) struct l_settings *settings = l_settings_new();
+ _auto_(l_free) char *path;
+
+ memcpy(ssid, config->ssid, config->ssid_len);
+ ssid[config->ssid_len] = '\0';
+
+ path = storage_get_network_file_path(SECURITY_PSK, ssid);
+
+ if (l_settings_load_from_file(settings, path)) {
+ /* Remove any existing Security keys */
+ l_settings_remove_group(settings, "Security");
+ }
+
+ if (config->passphrase)
+ l_settings_set_string(settings, "Security", "Passphrase",
+ config->passphrase);
+ else if (config->psk)
+ l_settings_set_string(settings, "Security", "PreSharedKey",
+ config->psk);
+
+ l_debug("Storing credential for '%s(%s)'", ssid,
+ security_to_str(SECURITY_PSK));
+ storage_network_sync(SECURITY_PSK, ssid, settings);
+}
+
+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;
+ uint8_t ad0[] = { 0x00, 0x10, 0x01, 0x00, 0x05 };
+
+ if (dpp->state != DPP_STATE_CONFIGURING)
+ return;
+
+ /*
+ * Can a configuration request come from someone other than who you
+ * authenticated to?
+ */
+ if (memcmp(dpp->auth_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(ad0, sizeof(ad0), 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;
+ }
+
+ dpp_write_config(config);
+ /*
+ * TODO: Depending on the info included in the configuration object a
+ * limited scan could be issued to get autoconnect to trigger faster.
+ * In addition this network may already be in past scan results and
+ * could be joined immediately.
+ *
+ * For now just wait for autoconnect.
+ */
+
+ dpp_configuration_free(config);
+
+ send_config_result(dpp, dpp->auth_addr);
+}
+
/*
* The Authentication protocol has a consistent use of AD components, and this
* use is defined in 6.3.1.4:
@@ -407,6 +734,8 @@ static void authenticate_confirm(struct dpp_sm *dpp, const uint8_t *from,
l_debug("Authentication successful");
+ dpp_configuration_start(dpp, from);
+
return;
auth_confirm_failed:
@@ -693,6 +1022,7 @@ static void dpp_create(struct netdev *netdev)
struct l_dbus *dbus = dbus_get_bus();
struct dpp_sm *dpp = l_new(struct dpp_sm, 1);
uint8_t dpp_prefix[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x1a, 0x01 };
+ uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
dpp->netdev = netdev;
dpp->state = DPP_STATE_NOTHING;
@@ -715,6 +1045,10 @@ static void dpp_create(struct netdev *netdev)
frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0, dpp_prefix,
sizeof(dpp_prefix), dpp_handle_auth_frame,
dpp, NULL);
+ 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);
}
static void dpp_netdev_watch(struct netdev *netdev,
--
2.31.1
6 months, 2 weeks
[PATCH v5 1/4] dpp-util: add DPP attribute building APIs
by James Prestwood
---
src/dpp-util.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++
src/dpp-util.h | 10 ++++
src/dpp.c | 10 ----
3 files changed, 153 insertions(+), 10 deletions(-)
v5:
* Moved these APIs into dpp-util instead of dpp.c so they can be
unit tested
* Changed so the caller supplies ad0/ad1. This takes the burden off
these utilities to sort out what type of frame, and any quirks of
how AAD is supposed to be used (see comments in authentication
and configuration patches)
diff --git a/src/dpp-util.c b/src/dpp-util.c
index f41127c7..f281f346 100644
--- a/src/dpp-util.c
+++ b/src/dpp-util.c
@@ -238,6 +238,149 @@ bool dpp_attr_iter_next(struct dpp_attr_iter *iter,
return true;
}
+size_t dpp_append_attr(uint8_t *to, enum dpp_attribute_type type,
+ void *attr, size_t attr_len)
+{
+ l_put_le16(type, to);
+ l_put_le16(attr_len, to + 2);
+ memcpy(to + 4, attr, attr_len);
+
+ return attr_len + 4;
+}
+
+/*
+ * The use of ad0/ad1 differs with different protocol frame types, which is why
+ * this is left up to the caller to pass the correct AD bytes. The usage is
+ * defined in:
+ *
+ * 6.3.1.4 Protocol Conventions (for authentication)
+ * 6.4.1 Overview (for configuration)
+ *
+ */
+uint8_t *dpp_unwrap_attr(const void *ad0, size_t ad0_len, const void *ad1,
+ size_t ad1_len, const void *key, size_t key_len,
+ const void *wrapped, size_t wrapped_len,
+ size_t *unwrapped_len)
+{
+ struct iovec ad[2];
+ uint8_t *unwrapped;
+ size_t ad_size = 0;
+
+ if (ad0) {
+ ad[ad_size].iov_base = (void *) ad0;
+ ad[ad_size].iov_len = ad0_len;
+ ad_size++;
+ }
+
+ if (ad1) {
+ ad[ad_size].iov_base = (void *) ad1;
+ ad[ad_size].iov_len = ad1_len;
+ ad_size++;
+ }
+
+ unwrapped = l_malloc(wrapped_len - 16);
+
+ if (!aes_siv_decrypt(key, key_len, wrapped, wrapped_len, ad, 2,
+ unwrapped)) {
+ l_free(unwrapped);
+ return NULL;
+ }
+
+ *unwrapped_len = wrapped_len - 16;
+
+ return unwrapped;
+}
+
+/*
+ * 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'
+ * 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 num_attrs, ...)
+{
+ size_t i;
+ size_t attrs_len = 0;
+ _auto_(l_free) uint8_t *plaintext = NULL;
+ uint8_t *ptr;
+ struct iovec ad[2];
+ size_t ad_size = 0;
+ va_list va;
+
+ va_start(va, num_attrs);
+
+ /* Count up total attributes length */
+ for (i = 0; i < num_attrs; i++) {
+ va_arg(va, enum dpp_attribute_type);
+ attrs_len += va_arg(va, size_t) + 4;
+ va_arg(va, void*);
+ }
+
+ if (to_len < attrs_len + 4 + 16)
+ return false;
+
+ plaintext = l_malloc(attrs_len);
+
+ ptr = plaintext;
+
+ va_end(va);
+
+ va_start(va, num_attrs);
+
+ /* Build up plaintext attributes */
+ for (i = 0; i < num_attrs; i++) {
+ enum dpp_attribute_type type = va_arg(va,
+ enum dpp_attribute_type);
+ size_t l = va_arg(va, size_t);
+ void *p = va_arg(va, void *);
+
+ l_put_le16(type, ptr);
+ ptr += 2;
+ l_put_le16(l, ptr);
+ ptr += 2;
+ memcpy(ptr, p, l);
+ ptr += l;
+ }
+
+ va_end(va);
+
+ ptr = to;
+
+ l_put_le16(DPP_ATTR_WRAPPED_DATA, ptr);
+ ptr += 2;
+ l_put_le16(attrs_len + 16, ptr);
+ ptr += 2;
+
+ if (ad0) {
+ ad[ad_size].iov_base = (void *) ad0;
+ ad[ad_size].iov_len = ad0_len;
+ ad_size++;
+ }
+
+ if (ad1) {
+ ad[ad_size].iov_base = (void *) ad1;
+ ad[ad_size].iov_len = ad1_len;
+ ad_size++;
+ }
+
+ if (!aes_siv_encrypt(key, key_len, plaintext, attrs_len,
+ ad, ad_size, ptr))
+ return 0;
+
+ return attrs_len + 4 + 16;
+}
+
+
/*
* 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 84404128..543cf9f8 100644
--- a/src/dpp-util.h
+++ b/src/dpp-util.h
@@ -122,6 +122,16 @@ void dpp_attr_iter_init(struct dpp_attr_iter *iter, const uint8_t *pdu,
bool dpp_attr_iter_next(struct dpp_attr_iter *iter,
enum dpp_attribute_type *type, size_t *len,
const uint8_t **data);
+uint8_t *dpp_unwrap_attr(const void *ad0, size_t ad0_len, const void *ad1,
+ size_t ad1_len, const void *key, size_t key_len,
+ const void *wrapped, size_t wrapped_len,
+ 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 num_attrs, ...);
char *dpp_generate_uri(const uint8_t *asn1, size_t asn1_len, uint8_t version,
const uint8_t *mac, const uint32_t *freqs,
diff --git a/src/dpp.c b/src/dpp.c
index 0a42e321..d9666ead 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -143,16 +143,6 @@ static void dpp_send_frame(uint64_t wdev_id, struct iovec *iov, size_t iov_len,
l_error("Could not send CMD_FRAME");
}
-static size_t dpp_append_attr(uint8_t *to, enum dpp_attribute_type type,
- void *attr, size_t attr_len)
-{
- l_put_le16(type, to);
- l_put_le16(attr_len, to + 2);
- memcpy(to + 4, attr, attr_len);
-
- return attr_len + 4;
-}
-
static size_t dpp_build_header(const uint8_t *src, const uint8_t *dest,
enum dpp_frame_type type,
uint8_t buf[static 32])
--
2.31.1
6 months, 2 weeks
[PATCH v4 01/10] dpp-util: add dpp_point_to_asn1
by James Prestwood
Converts an l_ecc_point to the DPP ASN.1 structure.
---
src/dpp-util.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/dpp-util.h | 2 ++
2 files changed, 92 insertions(+)
v4:
* Removed unneeded length check
* Removed '512 bit' OID, this isn't actually a key size
diff --git a/src/dpp-util.c b/src/dpp-util.c
index 0b355311..ffdc1f84 100644
--- a/src/dpp-util.c
+++ b/src/dpp-util.c
@@ -361,3 +361,93 @@ bool dpp_derive_ke(const uint8_t *i_nonce, const uint8_t *r_nonce,
/* ke = HKDF-Expand(bk, "DPP Key", length) */
return hkdf_expand(sha, bk, key_len, "DPP Key", ke, key_len);
}
+
+#define ASN1_ID(class, pc, tag) (((class) << 6) | ((pc) << 5) | (tag))
+
+#define ASN1_ID_SEQUENCE ASN1_ID(0, 1, 0x10)
+#define ASN1_ID_BIT_STRING ASN1_ID(0, 0, 0x03)
+#define ASN1_ID_OID ASN1_ID(0, 0, 0x06)
+
+/*
+ * Values derived from OID definitions in https://www.secg.org/sec2-v2.pdf
+ * Appendix A.2.1
+ *
+ * 1.2.840.10045.2.1 (ecPublicKey)
+ */
+static uint8_t ec_oid[] = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 };
+
+/* 1.2.840.10045.3.1.7 (prime256v1) */
+static uint8_t ec_p256_oid[] = { 0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x03, 0x01, 0x07 };
+/* 1.3.132.0.34 (secp384r1) */
+static uint8_t ec_p384_oid[] = { 0x2B, 0x81, 0x04, 0x00, 0x22 };
+
+uint8_t *dpp_point_to_asn1(const struct l_ecc_point *p, size_t *len_out)
+{
+ uint8_t *asn1;
+ uint8_t *ptr;
+ uint8_t *type_oid;
+ size_t type_oid_len;
+ const struct l_ecc_curve *curve = l_ecc_point_get_curve(p);
+ ssize_t key_size = l_ecc_curve_get_scalar_bytes(curve);
+ uint64_t x[L_ECC_MAX_DIGITS];
+ ssize_t ret;
+ size_t len;
+
+ switch (key_size) {
+ case 32:
+ type_oid = ec_p256_oid;
+ type_oid_len = sizeof(ec_p256_oid);
+ break;
+ case 48:
+ type_oid = ec_p384_oid;
+ type_oid_len = sizeof(ec_p384_oid);
+ break;
+ default:
+ return NULL;
+ }
+
+ ret = l_ecc_point_get_x(p, x, sizeof(x));
+ if (ret < 0 || ret != key_size)
+ return NULL;
+
+ len = 2 + sizeof(ec_oid) + 2 + type_oid_len + 2 + key_size + 4;
+
+ if (L_WARN_ON(len > 128))
+ return NULL;
+
+ asn1 = l_malloc(len + 2);
+ ptr = asn1;
+
+ *ptr++ = ASN1_ID_SEQUENCE;
+ /* Length of both OIDs and key, plus tag/len bytes */
+ *ptr++ = len;
+
+ *ptr++ = ASN1_ID_SEQUENCE;
+
+ len = sizeof(ec_oid) + type_oid_len + 4;
+
+ *ptr++ = len;
+
+ *ptr++ = ASN1_ID_OID;
+ *ptr++ = sizeof(ec_oid);
+ memcpy(ptr, ec_oid, sizeof(ec_oid));
+ ptr += sizeof(ec_oid);
+
+ *ptr++ = ASN1_ID_OID;
+ *ptr++ = type_oid_len;
+ memcpy(ptr, type_oid, type_oid_len);
+ ptr += type_oid_len;
+
+ *ptr++ = ASN1_ID_BIT_STRING;
+ *ptr++ = key_size + 2;
+ *ptr++ = 0x00;
+ *ptr++ = 0x03;
+ memcpy(ptr, x, key_size);
+ ptr += key_size;
+
+ if (len_out)
+ *len_out = ptr - asn1;
+
+ return asn1;
+}
diff --git a/src/dpp-util.h b/src/dpp-util.h
index c28bbcdf..e7e73071 100644
--- a/src/dpp-util.h
+++ b/src/dpp-util.h
@@ -137,3 +137,5 @@ struct l_ecc_scalar *dpp_derive_k2(const struct l_ecc_point *i_proto_public,
bool dpp_derive_ke(const uint8_t *i_nonce, const uint8_t *r_nonce,
struct l_ecc_scalar *m, struct l_ecc_scalar *n,
void *ke);
+
+uint8_t *dpp_point_to_asn1(const struct l_ecc_point *p, size_t *len_out);
--
2.31.1
6 months, 2 weeks