[PATCH RESEND] DPP: Check PKEX Encrypted Key attribute length against the curve
Alejandro Pacheco
alepacheco99 at gmail.com
Sat Oct 17 06:15:00 PDT 2026
dpp_pkex_rx_exchange_req() and dpp_pkex_rx_exchange_resp() passed the
Encrypted Key attribute to crypto_ec_point_from_bin() after checking
only that its length was even and nonzero (and, for the request, not
larger than twice the maximum coordinate length).
crypto_ec_point_from_bin() reads 2 * prime_len octets for the x and y
coordinates, so a shorter attribute resulted in reading beyond the
attribute and, when it was the last one, beyond the received frame. An
oversized attribute in the response also caused an incorrect N.x length
to be used when deriving z.
Require the attribute to be exactly 2 * prime_len octets, as is already
done for the Bootstrapping Key attribute in the PKEX Commit-Reveal
messages.
Add module tests for PKEX Exchange Request and Response processing
rejecting an Encrypted Key attribute of the wrong length.
Signed-off-by: Alejandro Pacheco <alepacheco99 at gmail.com>
---
Resent: the first posting of this patch
(<CAB8Pm=yyNyqisZ0ES_7bjC=UGS=X53tei2fnvfx+3CQSoC1hZw at mail.gmail.com>)
reached the list with its diff reformatted (a long line wrapped and the
spaces of empty context lines removed), so it does not apply. The patch
is unchanged. This time the diff is attached as plain text so that it
arrives intact; git am takes this mail as it is.
src/common/common_module_tests.c | 168 +++++++++++++++++++++++++++++++
src/common/dpp_pkex.c | 5 +-
2 files changed, 170 insertions(+), 3 deletions(-)
-------------- next part --------------
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 74a0ea368..8274b5db8 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -17,6 +17,7 @@
#include "gas.h"
#include "wpa_common.h"
#include "sae.h"
+#include "dpp.h"
struct ieee802_11_parse_test_data {
@@ -781,6 +782,172 @@ static int pasn_tests(void)
}
+#ifdef CONFIG_DPP
+
+static struct wpabuf * dpp_pkex_test_key_len(const struct wpabuf *msg,
+ int delta)
+{
+ const u8 *pos = wpabuf_head_u8(msg) + 8;
+ const u8 *end = wpabuf_head_u8(msg) + wpabuf_len(msg);
+ struct wpabuf *buf, *ret;
+
+ buf = wpabuf_alloc(wpabuf_len(msg) + 2);
+ if (!buf)
+ return NULL;
+
+ while (end - pos >= 4) {
+ u16 id = WPA_GET_LE16(pos);
+ u16 alen = WPA_GET_LE16(pos + 2);
+
+ pos += 4;
+ if (alen > end - pos)
+ break;
+ wpabuf_put_le16(buf, id);
+ if (id == DPP_ATTR_ENCRYPTED_KEY) {
+ wpabuf_put_le16(buf, alen + delta);
+ if (delta < 0) {
+ wpabuf_put_data(buf, pos, alen + delta);
+ } else {
+ wpabuf_put_data(buf, pos, alen);
+ wpabuf_put(buf, delta);
+ }
+ } else {
+ wpabuf_put_le16(buf, alen);
+ wpabuf_put_data(buf, pos, alen);
+ }
+ pos += alen;
+ }
+
+ ret = wpabuf_dup(buf);
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+static int dpp_pkex_tests(void)
+{
+ struct dpp_global_config config;
+ struct dpp_global *dpp;
+ struct dpp_bootstrap_info *bi_i, *bi_r;
+ struct dpp_pkex *init = NULL, *resp = NULL;
+ struct wpabuf *buf = NULL, *msg = NULL;
+ const u8 addr_i[ETH_ALEN] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ const u8 addr_r[ETH_ALEN] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x02 };
+ const char *code = "pkex test code";
+ const int delta[] = { -2, 2 };
+ unsigned int i;
+ int ret = -1;
+
+ wpa_printf(MSG_INFO, "DPP PKEX tests");
+
+ os_memset(&config, 0, sizeof(config));
+ dpp = dpp_global_init(&config);
+ if (!dpp)
+ return -1;
+ bi_i = dpp_bootstrap_get_id(dpp, dpp_bootstrap_gen(
+ dpp, "type=pkex curve=prime256v1"));
+ bi_r = dpp_bootstrap_get_id(dpp, dpp_bootstrap_gen(
+ dpp, "type=pkex curve=prime256v1"));
+ if (!bi_i || !bi_r)
+ goto fail;
+
+ for (i = 0; i <= ARRAY_SIZE(delta); i++) {
+ init = dpp_pkex_init(NULL, bi_i, addr_i, NULL, code,
+ os_strlen(code), false);
+ if (!init)
+ goto fail;
+
+ if (i < ARRAY_SIZE(delta)) {
+ buf = dpp_pkex_test_key_len(init->exchange_req,
+ delta[i]);
+ if (!buf)
+ goto fail;
+ resp = dpp_pkex_rx_exchange_req(NULL, bi_r, addr_r,
+ addr_i, NULL, code,
+ os_strlen(code),
+ wpabuf_head(buf),
+ wpabuf_len(buf), false);
+ if (resp) {
+ wpa_printf(MSG_ERROR,
+ "DPP PKEX: Exchange Request with Encrypted Key length %d accepted",
+ (int) (2 * bi_r->curve->prime_len) +
+ delta[i]);
+ goto fail;
+ }
+ wpabuf_free(buf);
+ buf = NULL;
+ }
+
+ resp = dpp_pkex_rx_exchange_req(
+ NULL, bi_r, addr_r, addr_i, NULL, code,
+ os_strlen(code), wpabuf_head_u8(init->exchange_req) + 8,
+ wpabuf_len(init->exchange_req) - 8, false);
+ if (!resp || !resp->exchange_resp) {
+ wpa_printf(MSG_ERROR,
+ "DPP PKEX: Valid Exchange Request rejected");
+ goto fail;
+ }
+
+ if (i < ARRAY_SIZE(delta)) {
+ buf = dpp_pkex_test_key_len(resp->exchange_resp,
+ delta[i]);
+ if (!buf)
+ goto fail;
+ msg = dpp_pkex_rx_exchange_resp(init, addr_r,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ if (msg) {
+ wpa_printf(MSG_ERROR,
+ "DPP PKEX: Exchange Response with Encrypted Key length %d accepted",
+ (int) (2 * bi_i->curve->prime_len) +
+ delta[i]);
+ goto fail;
+ }
+ } else {
+ msg = dpp_pkex_rx_exchange_resp(
+ init, addr_r,
+ wpabuf_head_u8(resp->exchange_resp) + 8,
+ wpabuf_len(resp->exchange_resp) - 8);
+ if (!msg) {
+ wpa_printf(MSG_ERROR,
+ "DPP PKEX: Valid Exchange Response rejected");
+ goto fail;
+ }
+ }
+
+ wpabuf_free(buf);
+ buf = NULL;
+ wpabuf_free(msg);
+ msg = NULL;
+ dpp_pkex_free(init);
+ init = NULL;
+ dpp_pkex_free(resp);
+ resp = NULL;
+ }
+
+ ret = 0;
+fail:
+ wpabuf_free(buf);
+ wpabuf_free(msg);
+ dpp_pkex_free(init);
+ dpp_pkex_free(resp);
+ dpp_global_deinit(dpp);
+ return ret;
+}
+
+#endif /* CONFIG_DPP */
+
+
+static int dpp_tests(void)
+{
+#ifdef CONFIG_DPP
+ if (dpp_pkex_tests() < 0)
+ return -1;
+#endif /* CONFIG_DPP */
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -792,6 +959,7 @@ int common_module_tests(void)
sae_tests() < 0 ||
sae_pk_tests() < 0 ||
pasn_tests() < 0 ||
+ dpp_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
index dca0d8d39..7f6659638 100644
--- a/src/common/dpp_pkex.c
+++ b/src/common/dpp_pkex.c
@@ -432,8 +432,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
/* M in Encrypted Key attribute */
attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
&attr_key_len);
- if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
- attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
+ if (!attr_key || attr_key_len != 2 * curve->prime_len) {
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Missing Encrypted Key attribute");
return NULL;
@@ -789,7 +788,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
/* N in Encrypted Key attribute */
attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
&attr_key_len);
- if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
+ if (!attr_key || attr_key_len != 2 * curve->prime_len) {
dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
return NULL;
}
More information about the Hostap
mailing list