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

