new file mode 100644
@@ -0,0 +1,254 @@
+From 9d3f347a2b14652e767d51142600206a32676b62 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <quic_jouni@quicinc.com>
+Date: Mon, 24 Jan 2022 20:57:19 +0200
+Subject: [PATCH] DPP3: Add PKEX initiator retries and fallback from v2 to v1
+ for hostapd
+
+This extends hostapd with the design used in wpa_supplicant for PKEX
+initiator retries and automatic version fallback from v2 to v1 (the
+latter is enabled only with CONFIG_DPP3=y).
+
+Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
+
+CVE: CVE-2022-37660
+
+Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=9d3f347a2b14652e767d51142600206a32676b62]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ src/ap/dpp_hostapd.c | 188 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 171 insertions(+), 17 deletions(-)
+
+diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
+index 13e1fc5..6c30ba3 100644
+--- a/src/ap/dpp_hostapd.c
++++ b/src/ap/dpp_hostapd.c
+@@ -216,6 +216,163 @@ static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
+ }
+
+
++static int hostapd_dpp_allow_ir(struct hostapd_data *hapd, unsigned int freq)
++{
++ int i, j;
++
++ if (!hapd->iface->hw_features)
++ return -1;
++
++ for (i = 0; i < hapd->iface->num_hw_features; i++) {
++ struct hostapd_hw_modes *mode = &hapd->iface->hw_features[i];
++
++ for (j = 0; j < mode->num_channels; j++) {
++ struct hostapd_channel_data *chan = &mode->channels[j];
++
++ if (chan->freq != (int) freq)
++ continue;
++
++ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
++ HOSTAPD_CHAN_NO_IR |
++ HOSTAPD_CHAN_RADAR))
++ continue;
++
++ return 1;
++ }
++ }
++
++ wpa_printf(MSG_DEBUG,
++ "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
++ freq);
++
++ return 0;
++}
++
++
++static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
++ struct dpp_pkex *pkex)
++{
++ if (pkex->freq == 2437)
++ pkex->freq = 5745;
++ else if (pkex->freq == 5745)
++ pkex->freq = 5220;
++ else if (pkex->freq == 5220)
++ pkex->freq = 60480;
++ else
++ return -1; /* no more channels to try */
++
++ if (hostapd_dpp_allow_ir(hapd, pkex->freq) == 1) {
++ wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
++ pkex->freq);
++ return 0;
++ }
++
++ /* Could not use this channel - try the next one */
++ return hostapd_dpp_pkex_next_channel(hapd, pkex);
++}
++
++
++static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, bool v2)
++{
++ struct dpp_pkex *pkex;
++ struct wpabuf *msg;
++ unsigned int wait_time;
++
++ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
++ dpp_pkex_free(hapd->dpp_pkex);
++ hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi,
++ hapd->own_addr,
++ hapd->dpp_pkex_identifier,
++ hapd->dpp_pkex_code, v2);
++ pkex = hapd->dpp_pkex;
++ if (!pkex)
++ return -1;
++
++ msg = hapd->dpp_pkex->exchange_req;
++ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
++ pkex->freq = 2437;
++ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
++ " freq=%u type=%d", MAC2STR(broadcast), pkex->freq,
++ v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
++ DPP_PA_PKEX_V1_EXCHANGE_REQ);
++ hostapd_drv_send_action(hapd, pkex->freq, 0, broadcast,
++ wpabuf_head(msg), wpabuf_len(msg));
++ pkex->exch_req_wait_time = wait_time;
++ pkex->exch_req_tries = 1;
++
++ return 0;
++}
++
++
++static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
++{
++ struct hostapd_data *hapd = eloop_ctx;
++ struct dpp_pkex *pkex = hapd->dpp_pkex;
++
++ if (!pkex || !pkex->exchange_req)
++ return;
++ if (pkex->exch_req_tries >= 5) {
++ if (hostapd_dpp_pkex_next_channel(hapd, pkex) < 0) {
++#ifdef CONFIG_DPP3
++ if (pkex->v2) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: Fall back to PKEXv1");
++ hostapd_dpp_pkex_init(hapd, false);
++ return;
++ }
++#endif /* CONFIG_DPP3 */
++ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
++ "No response from PKEX peer");
++ dpp_pkex_free(pkex);
++ hapd->dpp_pkex = NULL;
++ return;
++ }
++ pkex->exch_req_tries = 0;
++ }
++
++ pkex->exch_req_tries++;
++ wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
++ pkex->exch_req_tries);
++ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
++ " freq=%u type=%d",
++ MAC2STR(broadcast), pkex->freq,
++ pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
++ DPP_PA_PKEX_V1_EXCHANGE_REQ);
++ hostapd_drv_send_action(hapd, pkex->freq, pkex->exch_req_wait_time,
++ broadcast,
++ wpabuf_head(pkex->exchange_req),
++ wpabuf_len(pkex->exchange_req));
++}
++
++
++static void hostapd_dpp_pkex_tx_status(struct hostapd_data *hapd, const u8 *dst,
++ const u8 *data, size_t data_len, int ok)
++{
++ struct dpp_pkex *pkex = hapd->dpp_pkex;
++
++ if (pkex->failed) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: Terminate PKEX exchange due to an earlier error");
++ if (pkex->t > pkex->own_bi->pkex_t)
++ pkex->own_bi->pkex_t = pkex->t;
++ dpp_pkex_free(pkex);
++ hapd->dpp_pkex = NULL;
++ return;
++ }
++
++ if (pkex->exch_req_wait_time && pkex->exchange_req) {
++ /* Wait for PKEX Exchange Response frame and retry request if
++ * no response is seen. */
++ eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd,
++ NULL);
++ eloop_register_timeout(pkex->exch_req_wait_time / 1000,
++ (pkex->exch_req_wait_time % 1000) * 1000,
++ hostapd_dpp_pkex_retry_timeout, hapd,
++ NULL);
++ }
++}
++
++
+ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ const u8 *data, size_t data_len, int ok)
+ {
+@@ -227,6 +384,11 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
+ " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
+
+ if (!hapd->dpp_auth) {
++ if (hapd->dpp_pkex) {
++ hostapd_dpp_pkex_tx_status(hapd, dst, data, data_len,
++ ok);
++ return;
++ }
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore TX status since there is no ongoing authentication exchange");
+ return;
+@@ -1783,6 +1945,9 @@ hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
+ return;
+ }
+
++ eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL);
++ hapd->dpp_pkex->exch_req_wait_time = 0;
++
+ msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
+ if (!msg) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
+@@ -2172,26 +2337,14 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
+ return -1;
+
+ if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
+- struct wpabuf *msg;
++#ifdef CONFIG_DPP3
++ bool v2 = true;
++#else /* CONFIG_DPP3 */
+ bool v2 = os_strstr(cmd, " init=2") != NULL;
++#endif /* CONFIG_DPP3 */
+
+- wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
+- dpp_pkex_free(hapd->dpp_pkex);
+- hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
+- hapd->own_addr,
+- hapd->dpp_pkex_identifier,
+- hapd->dpp_pkex_code, v2);
+- if (!hapd->dpp_pkex)
++ if (hostapd_dpp_pkex_init(hapd, v2) < 0)
+ return -1;
+-
+- msg = hapd->dpp_pkex->exchange_req;
+- /* TODO: Which channel to use? */
+- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+- " freq=%u type=%d", MAC2STR(broadcast), 2437,
+- v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+- DPP_PA_PKEX_V1_EXCHANGE_REQ);
+- hostapd_drv_send_action(hapd, 2437, 0, broadcast,
+- wpabuf_head(msg), wpabuf_len(msg));
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+@@ -2319,6 +2472,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
+ #endif /* CONFIG_TESTING_OPTIONS */
+ if (!hapd->dpp_init_done)
+ return;
++ eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,139 @@
+From 80213629981a21825e4688fde1b590e4c4d4bcea Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <quic_jouni@quicinc.com>
+Date: Mon, 24 Jan 2022 20:21:24 +0200
+Subject: [PATCH] DPP3: Start with PKEXv2 and fall back to v1
+
+Use automatic PKEX version negotiation as the initiator by starting with
+PKEXv2 and if no response is received, trying again with PKEXv1. For
+now, this is enabled only in wpa_supplicant CONFIG_DPP3=y builds.
+
+Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
+
+CVE: CVE-2022-37660
+
+Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=80213629981a21825e4688fde1b590e4c4d4bcea]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ wpa_supplicant/dpp_supplicant.c | 81 +++++++++++++++++++++------------
+ 1 file changed, 52 insertions(+), 29 deletions(-)
+
+diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
+index 584654a..43c85d3 100644
+--- a/wpa_supplicant/dpp_supplicant.c
++++ b/wpa_supplicant/dpp_supplicant.c
+@@ -2557,6 +2557,45 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ }
+
+
++static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s, bool v2)
++{
++ struct dpp_pkex *pkex;
++ struct wpabuf *msg;
++ unsigned int wait_time;
++
++ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
++ dpp_pkex_free(wpa_s->dpp_pkex);
++ wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi,
++ wpa_s->own_addr,
++ wpa_s->dpp_pkex_identifier,
++ wpa_s->dpp_pkex_code, v2);
++ pkex = wpa_s->dpp_pkex;
++ if (!pkex)
++ return -1;
++
++ msg = pkex->exchange_req;
++ wait_time = wpa_s->max_remain_on_chan;
++ if (wait_time > 2000)
++ wait_time = 2000;
++ pkex->freq = 2437;
++ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
++ " freq=%u type=%d",
++ MAC2STR(broadcast), pkex->freq,
++ v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
++ DPP_PA_PKEX_V1_EXCHANGE_REQ);
++ offchannel_send_action(wpa_s, pkex->freq, broadcast,
++ wpa_s->own_addr, broadcast,
++ wpabuf_head(msg), wpabuf_len(msg),
++ wait_time, wpas_dpp_tx_pkex_status, 0);
++ if (wait_time == 0)
++ wait_time = 2000;
++ pkex->exch_req_wait_time = wait_time;
++ pkex->exch_req_tries = 1;
++
++ return 0;
++}
++
++
+ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ {
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+@@ -2566,6 +2605,14 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ return;
+ if (pkex->exch_req_tries >= 5) {
+ if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
++#ifdef CONFIG_DPP3
++ if (pkex->v2) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: Fall back to PKEXv1");
++ wpas_dpp_pkex_init(wpa_s, false);
++ return;
++ }
++#endif /* CONFIG_DPP3 */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No response from PKEX peer");
+ dpp_pkex_free(pkex);
+@@ -3271,7 +3318,6 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+ {
+ struct dpp_bootstrap_info *own_bi;
+ const char *pos, *end;
+- unsigned int wait_time;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+@@ -3315,37 +3361,14 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+ return -1;
+
+ if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
+- struct dpp_pkex *pkex;
+- struct wpabuf *msg;
++#ifdef CONFIG_DPP3
++ bool v2 = true;
++#else /* CONFIG_DPP3 */
+ bool v2 = os_strstr(cmd, " init=2") != NULL;
++#endif /* CONFIG_DPP3 */
+
+- wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
+- dpp_pkex_free(wpa_s->dpp_pkex);
+- wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
+- wpa_s->dpp_pkex_identifier,
+- wpa_s->dpp_pkex_code, v2);
+- pkex = wpa_s->dpp_pkex;
+- if (!pkex)
++ if (wpas_dpp_pkex_init(wpa_s, v2) < 0)
+ return -1;
+-
+- msg = pkex->exchange_req;
+- wait_time = wpa_s->max_remain_on_chan;
+- if (wait_time > 2000)
+- wait_time = 2000;
+- pkex->freq = 2437;
+- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+- " freq=%u type=%d",
+- MAC2STR(broadcast), pkex->freq,
+- v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+- DPP_PA_PKEX_V1_EXCHANGE_REQ);
+- offchannel_send_action(wpa_s, pkex->freq, broadcast,
+- wpa_s->own_addr, broadcast,
+- wpabuf_head(msg), wpabuf_len(msg),
+- wait_time, wpas_dpp_tx_pkex_status, 0);
+- if (wait_time == 0)
+- wait_time = 2000;
+- pkex->exch_req_wait_time = wait_time;
+- pkex->exch_req_tries = 1;
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,196 @@
+From bdcccbc2755dd1a75731496782e02b5435fb9534 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <quic_jouni@quicinc.com>
+Date: Tue, 25 Jan 2022 20:06:49 +0200
+Subject: [PATCH] DPP: Change PKEX version configuration design
+
+Use a separate ver=<1|2> parameter to DPP_PKEX_ADD instead of
+overloading init=1 with version indication. This allows additional
+options for forcing v1-only and v2-only in addition to automatic mode
+(start with v2 and fall back to v1, if needed).
+
+Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
+
+CVE: CVE-2022-37660
+
+Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=bdcccbc2755dd1a75731496782e02b5435fb9534]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ src/ap/dpp_hostapd.c | 37 ++++++++++++++++++++++++++-------
+ src/common/dpp.h | 1 +
+ wpa_supplicant/dpp_supplicant.c | 37 ++++++++++++++++++++++++++-------
+ 3 files changed, 61 insertions(+), 14 deletions(-)
+
+diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
+index 6c30ba3..fdfdcf9 100644
+--- a/src/ap/dpp_hostapd.c
++++ b/src/ap/dpp_hostapd.c
+@@ -272,11 +272,19 @@ static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
+ }
+
+
+-static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, bool v2)
++enum hostapd_dpp_pkex_ver {
++ PKEX_VER_AUTO,
++ PKEX_VER_ONLY_1,
++ PKEX_VER_ONLY_2,
++};
++
++static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
++ enum hostapd_dpp_pkex_ver ver)
+ {
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+ unsigned int wait_time;
++ bool v2 = ver != PKEX_VER_ONLY_1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
+ dpp_pkex_free(hapd->dpp_pkex);
+@@ -287,6 +295,7 @@ static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, bool v2)
+ pkex = hapd->dpp_pkex;
+ if (!pkex)
+ return -1;
++ pkex->forced_ver = ver != PKEX_VER_AUTO;
+
+ msg = hapd->dpp_pkex->exchange_req;
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+@@ -314,10 +323,10 @@ static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ if (pkex->exch_req_tries >= 5) {
+ if (hostapd_dpp_pkex_next_channel(hapd, pkex) < 0) {
+ #ifdef CONFIG_DPP3
+- if (pkex->v2) {
++ if (pkex->v2 && !pkex->forced_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Fall back to PKEXv1");
+- hostapd_dpp_pkex_init(hapd, false);
++ hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1);
+ return;
+ }
+ #endif /* CONFIG_DPP3 */
+@@ -2336,14 +2345,28 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
+ if (!hapd->dpp_pkex_code)
+ return -1;
+
+- if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
++ if (os_strstr(cmd, " init=1")) {
+ #ifdef CONFIG_DPP3
+- bool v2 = true;
++ enum hostapd_dpp_pkex_ver ver = PKEX_VER_AUTO;
+ #else /* CONFIG_DPP3 */
+- bool v2 = os_strstr(cmd, " init=2") != NULL;
++ enum hostapd_dpp_pkex_ver ver = PKEX_VER_ONLY_1;
+ #endif /* CONFIG_DPP3 */
+
+- if (hostapd_dpp_pkex_init(hapd, v2) < 0)
++ pos = os_strstr(cmd, " ver=");
++ if (pos) {
++ int v;
++
++ pos += 5;
++ v = atoi(pos);
++ if (v == 1)
++ ver = PKEX_VER_ONLY_1;
++ else if (v == 2)
++ ver = PKEX_VER_ONLY_2;
++ else
++ return -1;
++ }
++
++ if (hostapd_dpp_pkex_init(hapd, ver) < 0)
+ return -1;
+ }
+
+diff --git a/src/common/dpp.h b/src/common/dpp.h
+index 8d62a0e..bfea446 100644
+--- a/src/common/dpp.h
++++ b/src/common/dpp.h
+@@ -177,6 +177,7 @@ struct dpp_pkex {
+ unsigned int exchange_done:1;
+ unsigned int failed:1;
+ unsigned int v2:1;
++ unsigned int forced_ver:1;
+ struct dpp_bootstrap_info *own_bi;
+ u8 own_mac[ETH_ALEN];
+ u8 peer_mac[ETH_ALEN];
+diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
+index 43c85d3..61b300f 100644
+--- a/wpa_supplicant/dpp_supplicant.c
++++ b/wpa_supplicant/dpp_supplicant.c
+@@ -2557,11 +2557,19 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ }
+
+
+-static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s, bool v2)
++enum wpas_dpp_pkex_ver {
++ PKEX_VER_AUTO,
++ PKEX_VER_ONLY_1,
++ PKEX_VER_ONLY_2,
++};
++
++static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
++ enum wpas_dpp_pkex_ver ver)
+ {
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+ unsigned int wait_time;
++ bool v2 = ver != PKEX_VER_ONLY_1;
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
+ dpp_pkex_free(wpa_s->dpp_pkex);
+@@ -2572,6 +2580,7 @@ static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s, bool v2)
+ pkex = wpa_s->dpp_pkex;
+ if (!pkex)
+ return -1;
++ pkex->forced_ver = ver != PKEX_VER_AUTO;
+
+ msg = pkex->exchange_req;
+ wait_time = wpa_s->max_remain_on_chan;
+@@ -2606,10 +2615,10 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ if (pkex->exch_req_tries >= 5) {
+ if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) {
+ #ifdef CONFIG_DPP3
+- if (pkex->v2) {
++ if (pkex->v2 && !pkex->forced_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Fall back to PKEXv1");
+- wpas_dpp_pkex_init(wpa_s, false);
++ wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1);
+ return;
+ }
+ #endif /* CONFIG_DPP3 */
+@@ -3360,14 +3369,28 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+ if (!wpa_s->dpp_pkex_code)
+ return -1;
+
+- if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
++ if (os_strstr(cmd, " init=1")) {
+ #ifdef CONFIG_DPP3
+- bool v2 = true;
++ enum wpas_dpp_pkex_ver ver = PKEX_VER_AUTO;
+ #else /* CONFIG_DPP3 */
+- bool v2 = os_strstr(cmd, " init=2") != NULL;
++ enum wpas_dpp_pkex_ver ver = PKEX_VER_ONLY_1;
+ #endif /* CONFIG_DPP3 */
+
+- if (wpas_dpp_pkex_init(wpa_s, v2) < 0)
++ pos = os_strstr(cmd, " ver=");
++ if (pos) {
++ int v;
++
++ pos += 5;
++ v = atoi(pos);
++ if (v == 1)
++ ver = PKEX_VER_ONLY_1;
++ else if (v == 2)
++ ver = PKEX_VER_ONLY_2;
++ else
++ return -1;
++ }
++
++ if (wpas_dpp_pkex_init(wpa_s, ver) < 0)
+ return -1;
+ }
+
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,941 @@
+From d7be749335f2585658cf98c4f0e7d6cd5ac06865 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <jouni@qca.qualcomm.com>
+Date: Tue, 25 Jan 2022 00:35:36 +0200
+Subject: [PATCH] DPP3: PKEX over TCP
+
+Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
+
+CVE: CVE-2022-37660
+
+Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=d7be749335f2585658cf98c4f0e7d6cd5ac06865]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ src/ap/dpp_hostapd.c | 155 ++++++++++++++--
+ src/common/dpp.h | 13 ++
+ src/common/dpp_pkex.c | 18 +-
+ src/common/dpp_tcp.c | 308 +++++++++++++++++++++++++++++++-
+ wpa_supplicant/dpp_supplicant.c | 122 ++++++++++++-
+ 5 files changed, 580 insertions(+), 36 deletions(-)
+
+diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
+index fdfdcf9..d956be9 100644
+--- a/src/ap/dpp_hostapd.c
++++ b/src/ap/dpp_hostapd.c
+@@ -28,12 +28,16 @@ static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
+ static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
+ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
++static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
++ struct dpp_authentication *auth);
+ #ifdef CONFIG_DPP2
+ static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf);
++static int hostapd_dpp_process_conf_obj(void *ctx,
++ struct dpp_authentication *auth);
+ #endif /* CONFIG_DPP2 */
+
+ static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+@@ -272,6 +276,75 @@ static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
+ }
+
+
++#ifdef CONFIG_DPP2
++static int hostapd_dpp_pkex_done(void *ctx, void *conn,
++ struct dpp_bootstrap_info *peer_bi)
++{
++ struct hostapd_data *hapd = ctx;
++ const char *cmd = hapd->dpp_pkex_auth_cmd;
++ const char *pos;
++ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
++ struct dpp_bootstrap_info *own_bi = NULL;
++ struct dpp_authentication *auth;
++
++ if (!cmd)
++ cmd = "";
++ wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
++ cmd);
++
++ pos = os_strstr(cmd, " own=");
++ if (pos) {
++ pos += 5;
++ own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp,
++ atoi(pos));
++ if (!own_bi) {
++ wpa_printf(MSG_INFO,
++ "DPP: Could not find bootstrapping info for the identified local entry");
++ return -1;
++ }
++
++ if (peer_bi->curve != own_bi->curve) {
++ wpa_printf(MSG_INFO,
++ "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
++ peer_bi->curve->name, own_bi->curve->name);
++ return -1;
++ }
++ }
++
++ pos = os_strstr(cmd, " role=");
++ if (pos) {
++ pos += 6;
++ if (os_strncmp(pos, "configurator", 12) == 0)
++ allowed_roles = DPP_CAPAB_CONFIGURATOR;
++ else if (os_strncmp(pos, "enrollee", 8) == 0)
++ allowed_roles = DPP_CAPAB_ENROLLEE;
++ else if (os_strncmp(pos, "either", 6) == 0)
++ allowed_roles = DPP_CAPAB_CONFIGURATOR |
++ DPP_CAPAB_ENROLLEE;
++ else
++ return -1;
++ }
++
++ auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx,
++ peer_bi, own_bi, allowed_roles, 0,
++ hapd->iface->hw_features,
++ hapd->iface->num_hw_features);
++ if (!auth)
++ return -1;
++
++ hostapd_dpp_set_testing_options(hapd, auth);
++ if (dpp_set_configurator(auth, cmd) < 0) {
++ dpp_auth_deinit(auth);
++ return -1;
++ }
++
++ return dpp_tcp_auth(hapd->iface->interfaces->dpp, conn, auth,
++ hapd->conf->dpp_name, DPP_NETROLE_AP,
++ hostapd_dpp_process_conf_obj);
++}
++#endif /* CONFIG_DPP2 */
++
++
+ enum hostapd_dpp_pkex_ver {
+ PKEX_VER_AUTO,
+ PKEX_VER_ONLY_1,
+@@ -279,7 +352,9 @@ enum hostapd_dpp_pkex_ver {
+ };
+
+ static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
+- enum hostapd_dpp_pkex_ver ver)
++ enum hostapd_dpp_pkex_ver ver,
++ const struct hostapd_ip_addr *ipaddr,
++ int tcp_port)
+ {
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+@@ -288,15 +363,26 @@ static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
+ dpp_pkex_free(hapd->dpp_pkex);
+- hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi,
+- hapd->own_addr,
+- hapd->dpp_pkex_identifier,
+- hapd->dpp_pkex_code, v2);
+- pkex = hapd->dpp_pkex;
++ hapd->dpp_pkex = NULL;
++ pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
++ hapd->dpp_pkex_identifier,
++ hapd->dpp_pkex_code, v2);
+ if (!pkex)
+ return -1;
+ pkex->forced_ver = ver != PKEX_VER_AUTO;
+
++ if (ipaddr) {
++#ifdef CONFIG_DPP2
++ return dpp_tcp_pkex_init(hapd->iface->interfaces->dpp, pkex,
++ ipaddr, tcp_port,
++ hapd->msg_ctx, hapd,
++ hostapd_dpp_pkex_done);
++#else /* CONFIG_DPP2 */
++ return -1;
++#endif /* CONFIG_DPP2 */
++ }
++
++ hapd->dpp_pkex = pkex;
+ msg = hapd->dpp_pkex->exchange_req;
+ wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
+ pkex->freq = 2437;
+@@ -326,7 +412,8 @@ static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ if (pkex->v2 && !pkex->forced_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Fall back to PKEXv1");
+- hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1);
++ hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1,
++ NULL, 0);
+ return;
+ }
+ #endif /* CONFIG_DPP3 */
+@@ -1883,7 +1970,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
+
+ static void
+ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
+- const u8 *buf, size_t len,
++ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq, bool v2)
+ {
+ struct wpabuf *msg;
+@@ -1897,14 +1984,14 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
+ if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code configured - ignore request");
+- return;
++ goto try_relay;
+ }
+
+ if (hapd->dpp_pkex) {
+ /* TODO: Support parallel operations */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Already in PKEX session - ignore new request");
+- return;
++ goto try_relay;
+ }
+
+ hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx,
+@@ -1916,7 +2003,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
+ if (!hapd->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to process the request - ignore it");
+- return;
++ goto try_relay;
+ }
+
+ msg = hapd->dpp_pkex->exchange_resp;
+@@ -1933,6 +2020,17 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ }
++
++ return;
++
++try_relay:
++#ifdef CONFIG_DPP2
++ if (v2)
++ dpp_relay_rx_action(hapd->iface->interfaces->dpp,
++ src, hdr, buf, len, freq, NULL, NULL, hapd);
++#else /* CONFIG_DPP2 */
++ wpa_printf(MSG_DEBUG, "DPP: No relay functionality included - skip");
++#endif /* CONFIG_DPP2 */
+ }
+
+
+@@ -2132,12 +2230,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
+ /* This is for PKEXv2, but for now, process only with
+ * CONFIG_DPP3 to avoid issues with a capability that has not
+ * been tested with other implementations. */
+- hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
++ hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq,
+ true);
+ break;
+ #endif /* CONFIG_DPP3 */
+ case DPP_PA_PKEX_V1_EXCHANGE_REQ:
+- hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
++ hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq,
+ false);
+ break;
+ case DPP_PA_PKEX_EXCHANGE_RESP:
+@@ -2303,6 +2401,29 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
+ {
+ struct dpp_bootstrap_info *own_bi;
+ const char *pos, *end;
++ int tcp_port = DPP_TCP_PORT;
++ struct hostapd_ip_addr *ipaddr = NULL;
++#ifdef CONFIG_DPP2
++ struct hostapd_ip_addr ipaddr_buf;
++ char *addr;
++
++ pos = os_strstr(cmd, " tcp_port=");
++ if (pos) {
++ pos += 10;
++ tcp_port = atoi(pos);
++ }
++
++ addr = get_param(cmd, " tcp_addr=");
++ if (addr) {
++ int res;
++
++ res = hostapd_parse_ip_addr(addr, &ipaddr_buf);
++ os_free(addr);
++ if (res)
++ return -1;
++ ipaddr = &ipaddr_buf;
++ }
++#endif /* CONFIG_DPP2 */
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+@@ -2366,8 +2487,14 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
+ return -1;
+ }
+
+- if (hostapd_dpp_pkex_init(hapd, ver) < 0)
++ if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0)
+ return -1;
++ } else {
++#ifdef CONFIG_DPP2
++ dpp_controller_pkex_add(hapd->iface->interfaces->dpp, own_bi,
++ hapd->dpp_pkex_code,
++ hapd->dpp_pkex_identifier);
++#endif /* CONFIG_DPP2 */
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+diff --git a/src/common/dpp.h b/src/common/dpp.h
+index bfea446..ca33fe3 100644
+--- a/src/common/dpp.h
++++ b/src/common/dpp.h
+@@ -550,6 +550,9 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
+ const u8 *attr_start, size_t attr_len);
+ int dpp_notify_new_qr_code(struct dpp_authentication *auth,
+ struct dpp_bootstrap_info *peer_bi);
++void dpp_controller_pkex_add(struct dpp_global *dpp,
++ struct dpp_bootstrap_info *bi,
++ const char *code, const char *identifier);
+ struct dpp_configuration * dpp_configuration_alloc(const char *type);
+ int dpp_akm_psk(enum dpp_akm akm);
+ int dpp_akm_sae(enum dpp_akm akm);
+@@ -688,12 +691,22 @@ struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
+ unsigned int id);
+ void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ struct dpp_bootstrap_info *bi);
++int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex,
++ const struct hostapd_ip_addr *addr, int port,
++ void *msg_ctx, void *cb_ctx,
++ int (*pkex_done)(void *ctx, void *conn,
++ struct dpp_bootstrap_info *bi));
+ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ const struct hostapd_ip_addr *addr, int port,
+ const char *name, enum dpp_netrole netrole, void *msg_ctx,
+ void *cb_ctx,
+ int (*process_conf_obj)(void *ctx,
+ struct dpp_authentication *auth));
++int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
++ struct dpp_authentication *auth, const char *name,
++ enum dpp_netrole netrole,
++ int (*process_conf_obj)(void *ctx,
++ struct dpp_authentication *auth));
+
+ struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi);
+ void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
+diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
+index 38349fa..72084d9 100644
+--- a/src/common/dpp_pkex.c
++++ b/src/common/dpp_pkex.c
+@@ -469,8 +469,10 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
+ pkex->t = bi->pkex_t;
+ pkex->msg_ctx = msg_ctx;
+ pkex->own_bi = bi;
+- os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
+- os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
++ if (own_mac)
++ os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
++ if (peer_mac)
++ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+ if (identifier) {
+ pkex->identifier = os_strdup(identifier);
+ if (!pkex->identifier)
+@@ -742,7 +744,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
+ }
+ #endif /* CONFIG_DPP2 */
+
+- os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
++ if (peer_mac)
++ os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
+
+ attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
+ &attr_status_len);
+@@ -1341,9 +1344,12 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
+ return NULL;
+ bi->id = dpp_next_id(dpp);
+ bi->type = DPP_BOOTSTRAP_PKEX;
+- os_memcpy(bi->mac_addr, peer, ETH_ALEN);
+- bi->num_freq = 1;
+- bi->freq[0] = freq;
++ if (peer)
++ os_memcpy(bi->mac_addr, peer, ETH_ALEN);
++ if (freq) {
++ bi->num_freq = 1;
++ bi->freq[0] = freq;
++ }
+ bi->curve = pkex->own_bi->curve;
+ bi->pubkey = pkex->peer_bootstrap_key;
+ pkex->peer_bootstrap_key = NULL;
+diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
+index fb8ef1c..1a8a7c7 100644
+--- a/src/common/dpp_tcp.c
++++ b/src/common/dpp_tcp.c
+@@ -24,10 +24,12 @@ struct dpp_connection {
+ struct dpp_controller *ctrl;
+ struct dpp_relay_controller *relay;
+ struct dpp_global *global;
++ struct dpp_pkex *pkex;
+ struct dpp_authentication *auth;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
++ int (*pkex_done)(void *ctx, void *conn, struct dpp_bootstrap_info *bi);
+ int sock;
+ u8 mac_addr[ETH_ALEN];
+ unsigned int freq;
+@@ -71,6 +73,9 @@ struct dpp_controller {
+ struct dl_list conn; /* struct dpp_connection */
+ char *configurator_params;
+ enum dpp_netrole netrole;
++ struct dpp_bootstrap_info *pkex_bi;
++ char *pkex_code;
++ char *pkex_identifier;
+ void *msg_ctx;
+ void *cb_ctx;
+ int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+@@ -102,6 +107,7 @@ static void dpp_connection_free(struct dpp_connection *conn)
+ wpabuf_free(conn->msg);
+ wpabuf_free(conn->msg_out);
+ dpp_auth_deinit(conn->auth);
++ dpp_pkex_free(conn->pkex);
+ os_free(conn->name);
+ os_free(conn);
+ }
+@@ -525,6 +531,8 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
+ /* TODO: Could send this to all configured Controllers. For now,
+ * only the first Controller is supported. */
+ ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx);
++ } else if (type == DPP_PA_PKEX_EXCHANGE_REQ) {
++ ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx);
+ } else {
+ if (!r_bootstrap)
+ return -1;
+@@ -609,6 +617,8 @@ static void dpp_controller_free(struct dpp_controller *ctrl)
+ eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
+ }
+ os_free(ctrl->configurator_params);
++ os_free(ctrl->pkex_code);
++ os_free(ctrl->pkex_identifier);
+ os_free(ctrl);
+ }
+
+@@ -955,6 +965,143 @@ static int dpp_controller_rx_reconfig_auth_resp(struct dpp_connection *conn,
+ }
+
+
++static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn,
++ const u8 *hdr, const u8 *buf,
++ size_t len)
++{
++ struct dpp_controller *ctrl = conn->ctrl;
++
++ if (!ctrl)
++ return 0;
++
++ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request");
++
++ /* TODO: Support multiple PKEX codes by iterating over all the enabled
++ * values here */
++
++ if (!ctrl->pkex_code || !ctrl->pkex_bi) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: No PKEX code configured - ignore request");
++ return 0;
++ }
++
++ if (conn->pkex || conn->auth) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: Already in PKEX/Authentication session - ignore new PKEX request");
++ return 0;
++ }
++
++ conn->pkex = dpp_pkex_rx_exchange_req(conn->ctrl->global, ctrl->pkex_bi,
++ NULL, NULL,
++ ctrl->pkex_identifier,
++ ctrl->pkex_code,
++ buf, len, true);
++ if (!conn->pkex) {
++ wpa_printf(MSG_DEBUG,
++ "DPP: Failed to process the request");
++ return -1;
++ }
++
++ return dpp_tcp_send_msg(conn, conn->pkex->exchange_resp);
++}
++
++
++static int dpp_controller_rx_pkex_exchange_resp(struct dpp_connection *conn,
++ const u8 *hdr, const u8 *buf,
++ size_t len)
++{
++ struct dpp_pkex *pkex = conn->pkex;
++ struct wpabuf *msg;
++ int res;
++
++ wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response");
++
++ if (!pkex || !pkex->initiator || pkex->exchange_done) {
++ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
++ return 0;
++ }
++
++ msg = dpp_pkex_rx_exchange_resp(pkex, NULL, buf, len);
++ if (!msg) {
++ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
++ return -1;
++ }
++
++ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request");
++ res = dpp_tcp_send_msg(conn, msg);
++ wpabuf_free(msg);
++ return res;
++}
++
++
++static int dpp_controller_rx_pkex_commit_reveal_req(struct dpp_connection *conn,
++ const u8 *hdr,
++ const u8 *buf, size_t len)
++{
++ struct dpp_pkex *pkex = conn->pkex;
++ struct wpabuf *msg;
++ int res;
++ struct dpp_bootstrap_info *bi;
++
++ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request");
++
++ if (!pkex || pkex->initiator || !pkex->exchange_done) {
++ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
++ return 0;
++ }
++
++ msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len);
++ if (!msg) {
++ wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
++ return -1;
++ }
++
++ wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response");
++ res = dpp_tcp_send_msg(conn, msg);
++ wpabuf_free(msg);
++ if (res < 0)
++ return res;
++ bi = dpp_pkex_finish(conn->global, pkex, NULL, 0);
++ if (!bi)
++ return -1;
++ conn->pkex = NULL;
++ return 0;
++}
++
++
++static int
++dpp_controller_rx_pkex_commit_reveal_resp(struct dpp_connection *conn,
++ const u8 *hdr,
++ const u8 *buf, size_t len)
++{
++ struct dpp_pkex *pkex = conn->pkex;
++ int res;
++ struct dpp_bootstrap_info *bi;
++
++ wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response");
++
++ if (!pkex || !pkex->initiator || !pkex->exchange_done) {
++ wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session");
++ return 0;
++ }
++
++ res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len);
++ if (res < 0) {
++ wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
++ return res;
++ }
++
++ bi = dpp_pkex_finish(conn->global, pkex, NULL, 0);
++ if (!bi)
++ return -1;
++ conn->pkex = NULL;
++
++ if (!conn->pkex_done)
++ return -1;
++ return conn->pkex_done(conn->cb_ctx, conn, bi);
++}
++
++
+ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
+ size_t len)
+ {
+@@ -1014,6 +1161,22 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
+ case DPP_PA_RECONFIG_AUTH_RESP:
+ return dpp_controller_rx_reconfig_auth_resp(conn, msg, pos,
+ end - pos);
++ case DPP_PA_PKEX_V1_EXCHANGE_REQ:
++ wpa_printf(MSG_DEBUG,
++ "DPP: Ignore PKEXv1 Exchange Request - not supported over TCP");
++ return -1;
++ case DPP_PA_PKEX_EXCHANGE_REQ:
++ return dpp_controller_rx_pkex_exchange_req(conn, msg, pos,
++ end - pos);
++ case DPP_PA_PKEX_EXCHANGE_RESP:
++ return dpp_controller_rx_pkex_exchange_resp(conn, msg, pos,
++ end - pos);
++ case DPP_PA_PKEX_COMMIT_REVEAL_REQ:
++ return dpp_controller_rx_pkex_commit_reveal_req(conn, msg, pos,
++ end - pos);
++ case DPP_PA_PKEX_COMMIT_REVEAL_RESP:
++ return dpp_controller_rx_pkex_commit_reveal_resp(conn, msg, pos,
++ end - pos);
+ default:
+ /* TODO: missing messages types */
+ wpa_printf(MSG_DEBUG,
+@@ -1559,6 +1722,101 @@ fail:
+ }
+
+
++int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex,
++ const struct hostapd_ip_addr *addr, int port,
++ void *msg_ctx, void *cb_ctx,
++ int (*pkex_done)(void *ctx, void *conn,
++ struct dpp_bootstrap_info *bi))
++{
++ struct dpp_connection *conn;
++ struct sockaddr_storage saddr;
++ socklen_t addrlen;
++ const u8 *hdr, *pos, *end;
++ char txt[100];
++
++ wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
++ hostapd_ip_txt(addr, txt, sizeof(txt)), port);
++ if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
++ addr, port) < 0) {
++ dpp_pkex_free(pkex);
++ return -1;
++ }
++
++ conn = os_zalloc(sizeof(*conn));
++ if (!conn) {
++ dpp_pkex_free(pkex);
++ return -1;
++ }
++
++ conn->msg_ctx = msg_ctx;
++ conn->cb_ctx = cb_ctx;
++ conn->pkex_done = pkex_done;
++ conn->global = dpp;
++ conn->pkex = pkex;
++ conn->sock = socket(AF_INET, SOCK_STREAM, 0);
++ if (conn->sock < 0)
++ goto fail;
++
++ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
++ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
++ strerror(errno));
++ goto fail;
++ }
++
++ if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
++ if (errno != EINPROGRESS) {
++ wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
++ strerror(errno));
++ goto fail;
++ }
++
++ /*
++ * Continue connecting in the background; eloop will call us
++ * once the connection is ready (or failed).
++ */
++ }
++
++ if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
++ dpp_conn_tx_ready, conn, NULL) < 0)
++ goto fail;
++ conn->write_eloop = 1;
++
++ hdr = wpabuf_head(pkex->exchange_req);
++ end = hdr + wpabuf_len(pkex->exchange_req);
++ hdr += 2; /* skip Category and Actiom */
++ pos = hdr + DPP_HDR_LEN;
++ conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
++ if (!conn->msg_out)
++ goto fail;
++ /* Message will be sent in dpp_conn_tx_ready() */
++
++ /* TODO: eloop timeout to clear a connection if it does not complete
++ * properly */
++ dl_list_add(&dpp->tcp_init, &conn->list);
++ return 0;
++fail:
++ dpp_connection_free(conn);
++ return -1;
++}
++
++
++static int dpp_tcp_auth_start(struct dpp_connection *conn,
++ struct dpp_authentication *auth)
++{
++ const u8 *hdr, *pos, *end;
++
++ hdr = wpabuf_head(auth->req_msg);
++ end = hdr + wpabuf_len(auth->req_msg);
++ hdr += 2; /* skip Category and Actiom */
++ pos = hdr + DPP_HDR_LEN;
++ conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
++ if (!conn->msg_out)
++ return -1;
++ /* Message will be sent in dpp_conn_tx_ready() */
++ return 0;
++}
++
++
+ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ const struct hostapd_ip_addr *addr, int port, const char *name,
+ enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
+@@ -1568,7 +1826,6 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ struct dpp_connection *conn;
+ struct sockaddr_storage saddr;
+ socklen_t addrlen;
+- const u8 *hdr, *pos, *end;
+ char txt[100];
+
+ wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
+@@ -1620,14 +1877,8 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
+ goto fail;
+ conn->write_eloop = 1;
+
+- hdr = wpabuf_head(auth->req_msg);
+- end = hdr + wpabuf_len(auth->req_msg);
+- hdr += 2; /* skip Category and Actiom */
+- pos = hdr + DPP_HDR_LEN;
+- conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
+- if (!conn->msg_out)
++ if (dpp_tcp_auth_start(conn, auth) < 0)
+ goto fail;
+- /* Message will be sent in dpp_conn_tx_ready() */
+
+ /* TODO: eloop timeout to clear a connection if it does not complete
+ * properly */
+@@ -1639,6 +1890,30 @@ fail:
+ }
+
+
++int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
++ struct dpp_authentication *auth, const char *name,
++ enum dpp_netrole netrole,
++ int (*process_conf_obj)(void *ctx,
++ struct dpp_authentication *auth))
++{
++ struct dpp_connection *conn = _conn;
++
++ /* Continue with Authentication exchange on an existing TCP connection.
++ */
++ conn->process_conf_obj = process_conf_obj;
++ os_free(conn->name);
++ conn->name = os_strdup(name ? name : "Test");
++ conn->netrole = netrole;
++ conn->auth = auth;
++
++ if (dpp_tcp_auth_start(conn, auth) < 0)
++ return -1;
++
++ dpp_conn_tx_ready(conn->sock, conn, NULL);
++ return 0;
++}
++
++
+ int dpp_controller_start(struct dpp_global *dpp,
+ struct dpp_controller_config *config)
+ {
+@@ -1789,6 +2064,23 @@ void dpp_controller_new_qr_code(struct dpp_global *dpp,
+ }
+
+
++void dpp_controller_pkex_add(struct dpp_global *dpp,
++ struct dpp_bootstrap_info *bi,
++ const char *code, const char *identifier)
++{
++ struct dpp_controller *ctrl = dpp->controller;
++
++ if (!ctrl)
++ return;
++
++ ctrl->pkex_bi = bi;
++ os_free(ctrl->pkex_code);
++ ctrl->pkex_code = code ? os_strdup(code) : NULL;
++ os_free(ctrl->pkex_identifier);
++ ctrl->pkex_identifier = identifier ? os_strdup(identifier) : NULL;
++}
++
++
+ void dpp_tcp_init_flush(struct dpp_global *dpp)
+ {
+ struct dpp_connection *conn, *tmp;
+diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
+index 61b300f..aab94cb 100644
+--- a/wpa_supplicant/dpp_supplicant.c
++++ b/wpa_supplicant/dpp_supplicant.c
+@@ -2557,6 +2557,71 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ }
+
+
++#ifdef CONFIG_DPP2
++static int wpas_dpp_pkex_done(void *ctx, void *conn,
++ struct dpp_bootstrap_info *peer_bi)
++{
++ struct wpa_supplicant *wpa_s = ctx;
++ const char *cmd = wpa_s->dpp_pkex_auth_cmd;
++ const char *pos;
++ u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
++ struct dpp_bootstrap_info *own_bi = NULL;
++ struct dpp_authentication *auth;
++
++ if (!cmd)
++ cmd = "";
++ wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
++ cmd);
++
++ pos = os_strstr(cmd, " own=");
++ if (pos) {
++ pos += 5;
++ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
++ if (!own_bi) {
++ wpa_printf(MSG_INFO,
++ "DPP: Could not find bootstrapping info for the identified local entry");
++ return -1;
++ }
++
++ if (peer_bi->curve != own_bi->curve) {
++ wpa_printf(MSG_INFO,
++ "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)",
++ peer_bi->curve->name, own_bi->curve->name);
++ return -1;
++ }
++ }
++
++ pos = os_strstr(cmd, " role=");
++ if (pos) {
++ pos += 6;
++ if (os_strncmp(pos, "configurator", 12) == 0)
++ allowed_roles = DPP_CAPAB_CONFIGURATOR;
++ else if (os_strncmp(pos, "enrollee", 8) == 0)
++ allowed_roles = DPP_CAPAB_ENROLLEE;
++ else if (os_strncmp(pos, "either", 6) == 0)
++ allowed_roles = DPP_CAPAB_CONFIGURATOR |
++ DPP_CAPAB_ENROLLEE;
++ else
++ return -1;
++ }
++
++ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
++ 0, wpa_s->hw.modes, wpa_s->hw.num_modes);
++ if (!auth)
++ return -1;
++
++ wpas_dpp_set_testing_options(wpa_s, auth);
++ if (dpp_set_configurator(auth, cmd) < 0) {
++ dpp_auth_deinit(auth);
++ return -1;
++ }
++
++ return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name,
++ DPP_NETROLE_STA, wpas_dpp_process_conf_obj);
++}
++#endif /* CONFIG_DPP2 */
++
++
+ enum wpas_dpp_pkex_ver {
+ PKEX_VER_AUTO,
+ PKEX_VER_ONLY_1,
+@@ -2564,7 +2629,9 @@ enum wpas_dpp_pkex_ver {
+ };
+
+ static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
+- enum wpas_dpp_pkex_ver ver)
++ enum wpas_dpp_pkex_ver ver,
++ const struct hostapd_ip_addr *ipaddr,
++ int tcp_port)
+ {
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+@@ -2573,15 +2640,24 @@ static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
+ dpp_pkex_free(wpa_s->dpp_pkex);
+- wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi,
+- wpa_s->own_addr,
+- wpa_s->dpp_pkex_identifier,
+- wpa_s->dpp_pkex_code, v2);
+- pkex = wpa_s->dpp_pkex;
++ wpa_s->dpp_pkex = NULL;
++ pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
++ wpa_s->dpp_pkex_identifier,
++ wpa_s->dpp_pkex_code, v2);
+ if (!pkex)
+ return -1;
+ pkex->forced_ver = ver != PKEX_VER_AUTO;
+
++ if (ipaddr) {
++#ifdef CONFIG_DPP2
++ return dpp_tcp_pkex_init(wpa_s->dpp, pkex, ipaddr, tcp_port,
++ wpa_s, wpa_s, wpas_dpp_pkex_done);
++#else /* CONFIG_DPP2 */
++ return -1;
++#endif /* CONFIG_DPP2 */
++ }
++
++ wpa_s->dpp_pkex = pkex;
+ msg = pkex->exchange_req;
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+@@ -2618,7 +2694,8 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
+ if (pkex->v2 && !pkex->forced_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Fall back to PKEXv1");
+- wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1);
++ wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1,
++ NULL, 0);
+ return;
+ }
+ #endif /* CONFIG_DPP3 */
+@@ -3327,6 +3404,29 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+ {
+ struct dpp_bootstrap_info *own_bi;
+ const char *pos, *end;
++ int tcp_port = DPP_TCP_PORT;
++ struct hostapd_ip_addr *ipaddr = NULL;
++#ifdef CONFIG_DPP2
++ struct hostapd_ip_addr ipaddr_buf;
++ char *addr;
++
++ pos = os_strstr(cmd, " tcp_port=");
++ if (pos) {
++ pos += 10;
++ tcp_port = atoi(pos);
++ }
++
++ addr = get_param(cmd, " tcp_addr=");
++ if (addr) {
++ int res;
++
++ res = hostapd_parse_ip_addr(addr, &ipaddr_buf);
++ os_free(addr);
++ if (res)
++ return -1;
++ ipaddr = &ipaddr_buf;
++ }
++#endif /* CONFIG_DPP2 */
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+@@ -3390,8 +3490,14 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
+ return -1;
+ }
+
+- if (wpas_dpp_pkex_init(wpa_s, ver) < 0)
++ if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0)
+ return -1;
++ } else {
++#ifdef CONFIG_DPP2
++ dpp_controller_pkex_add(wpa_s->dpp, own_bi,
++ wpa_s->dpp_pkex_code,
++ wpa_s->dpp_pkex_identifier);
++#endif /* CONFIG_DPP2 */
+ }
+
+ /* TODO: Support multiple PKEX info entries */
+--
+2.40.0
+
new file mode 100644
@@ -0,0 +1,144 @@
+From 15af83cf1846870873a011ed4d714732f01cd2e4 Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <quic_jouni@quicinc.com>
+Date: Tue, 19 Jul 2022 21:23:04 +0300
+Subject: [PATCH] DPP: Delete PKEX code and identifier on success completion of
+ PKEX
+
+We are not supposed to reuse these without being explicitly requested to
+perform PKEX again. There is not a strong use case for being able to
+provision an Enrollee multiple times with PKEX, so this should have no
+issues on the Enrollee. For a Configurator, there might be some use
+cases that would benefit from being able to use the same code with
+multiple Enrollee devices, e.g., for guess access with a laptop and a
+smart phone. That case will now require a new DPP_PKEX_ADD command on
+the Configurator after each completion of the provisioning exchange.
+
+Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
+
+CVE: CVE-2022-37660
+
+Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=15af83cf1846870873a011ed4d714732f01cd2e4]
+
+Signed-off-by: Divya Chellam <divya.chellam@windriver.com>
+---
+ src/ap/dpp_hostapd.c | 22 +++++++++++++++++++++-
+ wpa_supplicant/dpp_supplicant.c | 21 ++++++++++++++++++++-
+ 2 files changed, 41 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
+index d956be9..73b09ba 100644
+--- a/src/ap/dpp_hostapd.c
++++ b/src/ap/dpp_hostapd.c
+@@ -276,6 +276,22 @@ static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
+ }
+
+
++static void hostapd_dpp_pkex_clear_code(struct hostapd_data *hapd)
++{
++ if (!hapd->dpp_pkex_code && !hapd->dpp_pkex_identifier)
++ return;
++
++ /* Delete PKEX code and identifier on successful completion of
++ * PKEX. We are not supposed to reuse these without being
++ * explicitly requested to perform PKEX again. */
++ wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier");
++ os_free(hapd->dpp_pkex_code);
++ hapd->dpp_pkex_code = NULL;
++ os_free(hapd->dpp_pkex_identifier);
++ hapd->dpp_pkex_identifier = NULL;
++}
++
++
+ #ifdef CONFIG_DPP2
+ static int hostapd_dpp_pkex_done(void *ctx, void *conn,
+ struct dpp_bootstrap_info *peer_bi)
+@@ -287,6 +303,8 @@ static int hostapd_dpp_pkex_done(void *ctx, void *conn,
+ struct dpp_bootstrap_info *own_bi = NULL;
+ struct dpp_authentication *auth;
+
++ hostapd_dpp_pkex_clear_code(hapd);
++
+ if (!cmd)
+ cmd = "";
+ wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
+@@ -2114,6 +2132,7 @@ hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+
++ hostapd_dpp_pkex_clear_code(hapd);
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ if (!bi)
+ return;
+@@ -2145,6 +2164,7 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src,
+ return;
+ }
+
++ hostapd_dpp_pkex_clear_code(hapd);
+ bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ if (!bi)
+ return;
+@@ -2518,7 +2538,7 @@ int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id)
+ return -1;
+ }
+
+- if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
++ if ((id_val != 0 && id_val != 1))
+ return -1;
+
+ /* TODO: Support multiple PKEX entries */
+diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
+index aab94cb..015ae66 100644
+--- a/wpa_supplicant/dpp_supplicant.c
++++ b/wpa_supplicant/dpp_supplicant.c
+@@ -2557,6 +2557,22 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s,
+ }
+
+
++static void wpas_dpp_pkex_clear_code(struct wpa_supplicant *wpa_s)
++{
++ if (!wpa_s->dpp_pkex_code && !wpa_s->dpp_pkex_identifier)
++ return;
++
++ /* Delete PKEX code and identifier on successful completion of
++ * PKEX. We are not supposed to reuse these without being
++ * explicitly requested to perform PKEX again. */
++ os_free(wpa_s->dpp_pkex_code);
++ wpa_s->dpp_pkex_code = NULL;
++ os_free(wpa_s->dpp_pkex_identifier);
++ wpa_s->dpp_pkex_identifier = NULL;
++
++}
++
++
+ #ifdef CONFIG_DPP2
+ static int wpas_dpp_pkex_done(void *ctx, void *conn,
+ struct dpp_bootstrap_info *peer_bi)
+@@ -2568,6 +2584,8 @@ static int wpas_dpp_pkex_done(void *ctx, void *conn,
+ struct dpp_bootstrap_info *own_bi = NULL;
+ struct dpp_authentication *auth;
+
++ wpas_dpp_pkex_clear_code(wpa_s);
++
+ if (!cmd)
+ cmd = "";
+ wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
+@@ -2872,6 +2890,7 @@ wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
+ {
+ struct dpp_bootstrap_info *bi;
+
++ wpas_dpp_pkex_clear_code(wpa_s);
+ bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
+ if (!bi)
+ return NULL;
+@@ -3521,7 +3540,7 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id)
+ return -1;
+ }
+
+- if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
++ if ((id_val != 0 && id_val != 1))
+ return -1;
+
+ /* TODO: Support multiple PKEX entries */
+--
+2.40.0
+
@@ -31,6 +31,11 @@ SRC_URI = "http://w1.fi/releases/wpa_supplicant-${PV}.tar.gz \
file://0001-SAE-Check-for-invalid-Rejected-Groups-element-length.patch \
file://0002-SAE-Check-for-invalid-Rejected-Groups-element-length.patch \
file://0003-SAE-Reject-invalid-Rejected-Groups-element-in-the-pa.patch \
+ file://CVE-2022-37660-0001.patch \
+ file://CVE-2022-37660-0002.patch \
+ file://CVE-2022-37660-0003.patch \
+ file://CVE-2022-37660-0004.patch \
+ file://CVE-2022-37660-0005.patch \
"
SRC_URI[sha256sum] = "20df7ae5154b3830355f8ab4269123a87affdea59fe74fe9292a91d0d7e17b2f"