[10/14] PASN: Add support for comeback flow to the wpa_supplicant
diff mbox series

Message ID 20200224091602.15306-11-ilan.peer@intel.com
State Deferred
Headers show
Series
  • Support PASN with SAE, FILS and FT
Related show

Commit Message

Peer, Ilan Feb. 24, 2020, 9:15 a.m. UTC
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
---
 wpa_supplicant/ctrl_iface.c       | 27 ++++++++--
 wpa_supplicant/pasn_supplicant.c  | 85 +++++++++++++++++++++++++++----
 wpa_supplicant/wpa_supplicant_i.h |  6 ++-
 3 files changed, 104 insertions(+), 14 deletions(-)

Patch
diff mbox series

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 1b09c88c15..60ecc36180 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10074,7 +10074,9 @@  static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 	u8 bssid[ETH_ALEN];
 	int akmp = -1, cipher = -1, got_bssid = 0;
 	u16 group = 0xFFFF;
-	int id = 0;
+	u8 *comeback = NULL;
+	size_t comeback_len = 0;
+	int id = 0, ret;
 
 	/*
 	 * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
@@ -10116,6 +10118,21 @@  static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 			group = atoi(token + 6);
 		} else if (os_strncmp(token, "nid=", 4) == 0) {
 			id = atoi(token + 4);
+		} else if (os_strncmp(token, "comeback=", 9) == 0) {
+			comeback_len = os_strlen(token + 9);
+
+			if (!comeback_len || comeback_len % 2)
+				return -1;
+
+			comeback_len /= 2;
+			comeback = os_malloc(comeback_len);
+			if (!comeback)
+				return -1;
+
+			if (hexstr2bin(token + 9, comeback, comeback_len)) {
+				os_free(comeback);
+				return -1;
+			}
 		} else {
 			wpa_printf(MSG_DEBUG,
 				   "CTRL: PASN Invalid parameter: '%s'",
@@ -10126,11 +10143,15 @@  static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 
 	if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
 		wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+		os_free(comeback);
 		return -1;
 	}
 
-	return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group,
-				    id);
+	ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group,
+				   id, comeback, comeback_len);
+
+	os_free(comeback);
+	return ret;
 }
 #endif /* CONFIG_PASN */
 
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 924f87daab..3d7971fc9e 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -33,6 +33,7 @@  struct wpa_pasn_auth_work {
 	int cipher;
 	u16 group;
 	int network_id;
+	struct wpabuf *comeback;
 };
 
 
@@ -57,8 +58,30 @@  static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
 
 
 static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
-				  int akmp, int cipher, u8 status)
+				  int akmp, int cipher, u8 status,
+				  struct wpabuf *comeback,
+				  u16 comeback_after)
 {
+	if (comeback) {
+		size_t comeback_len = wpabuf_len(comeback);
+		char *comeback_txt = os_malloc(comeback_len * 2 + 1);
+
+		if (comeback_txt) {
+			wpa_snprintf_hex(comeback_txt, comeback_len * 2 + 1,
+					 wpabuf_head(comeback), comeback_len);
+
+			wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+				" akmp=%s, status=%u comeback_after=%u"
+				" comeback=%s",
+				MAC2STR(bssid),
+				wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+				status, comeback_after, comeback_txt);
+
+			os_free(comeback_txt);
+			return;
+		}
+	}
+
 	wpa_msg(wpa_s, MSG_INFO,
 		PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
 		MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
@@ -601,7 +624,8 @@  static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
 }
 
 
-static struct wpabuf *wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
+static struct wpabuf *wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
+					     struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
@@ -654,7 +678,7 @@  static struct wpabuf *wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_NO_WRAPPED_DATA;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, NULL, 0);
+				  pubkey, comeback, 0);
 
 	wpa_pasn_add_wrapped_data(buf, wrapped_data_buf);
 
@@ -782,6 +806,10 @@  static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
 	wpabuf_free(pasn->beacon_rsne);
 	pasn->beacon_rsne = NULL;
 
+	wpabuf_free(pasn->comeback);
+	pasn->comeback = NULL;
+	pasn->comeback_after = 0;
+
 #ifdef CONFIG_SAE
 	sae_clear_data(&pasn->sae);
 #endif /* CONFIG_SAE */
@@ -876,7 +904,7 @@  static int wpas_pasn_set_pmk(struct wpa_supplicant *wpa_s,
 static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   int akmp, int cipher, u16 group, int freq,
 			   const u8 *beacon_rsne, u8 beacon_rsne_len,
-			   int network_id)
+			   int network_id, struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpa_ssid *ssid;
@@ -946,7 +974,7 @@  static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		   pasn->group);
 
 
-	frame = wpas_pasn_build_auth_1(wpa_s);
+	frame = wpas_pasn_build_auth_1(wpa_s, comeback);
 	if (!frame) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
 		goto fail;
@@ -1029,6 +1057,8 @@  static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 					     wpa_s, NULL);
 			wpa_s->pasn_auth_work = NULL;
 		}
+
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return;
 	}
@@ -1053,16 +1083,23 @@  static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 
 	ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
 			      awork->group, bss->freq,
-			      rsne, *(rsne + 1) + 2, awork->network_id);
+			      rsne, *(rsne + 1) + 2, awork->network_id,
+			      awork->comeback);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Failed to start PASN authentication");
 		goto fail;
 	}
 
+	/* comeback token is no longer needed at this stage */
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
+
 	wpa_s->pasn_auth_work = work;
 	return;
 fail:
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
 	os_free(awork);
 	work->ctx = NULL;
 	radio_work_done(work);
@@ -1071,7 +1108,8 @@  fail:
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 			 const u8 *bssid, int akmp, int cipher,
-			 u16 group, int network_id)
+			 u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len)
 {
 	struct wpa_pasn_auth_work *awork;
 	struct wpa_bss *bss;
@@ -1118,8 +1156,19 @@  int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 	awork->group = group;
 	awork->network_id = network_id;
 
+	if (comeback && comeback_len) {
+		awork->comeback = wpabuf_alloc(comeback_len);
+		if (!awork->comeback) {
+			os_free(awork);
+			return -1;
+		}
+
+		wpabuf_put_data(awork->comeback, comeback, comeback_len);
+	}
+
 	if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
 			   wpas_pasn_auth_start_cb, awork) < 0) {
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return -1;
 	}
@@ -1139,7 +1188,8 @@  void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
 	wpa_printf(MSG_DEBUG, "PASN: stopping authentication");
 
 	wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
-			      pasn->status);
+			      pasn->status, pasn->comeback,
+			      pasn->comeback_after);
 
 	wpas_pasn_reset(wpa_s);
 }
@@ -1237,10 +1287,21 @@  int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	/* TODO: handle comeback flow */
 	if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: authentication temporarily rejected");
+
+		if (pasn_params.comeback && pasn_params.comeback_len) {
+			pasn->comeback = wpabuf_alloc(pasn_params.comeback_len);
+			if (pasn->comeback) {
+				wpabuf_put_data(pasn->comeback,
+						pasn_params.comeback,
+						pasn_params.comeback_len);
+				pasn->comeback_after = pasn_params.after;
+			}
+		}
+
+		pasn->status = status;
 		goto fail;
 	}
 
@@ -1368,7 +1429,11 @@  fail:
 	 * the frame and terminate the authentication exchange. However, better
 	 * reply to the AP with an error status
 	 */
-	pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (status == WLAN_STATUS_SUCCESS)
+		pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	else
+		pasn->status = status;
+
 	wpas_pasn_auth_stop(wpa_s);
 	return -1;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 8c0bef57e4..f5951a8496 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -530,6 +530,9 @@  struct wpas_pasn {
 	struct wpa_ptk ptk;
 	struct crypto_ecdh *ecdh;
 
+	struct wpabuf *comeback;
+	u16 comeback_after;
+
 #ifdef CONFIG_SAE
 	struct sae_data sae;
 #endif /* CONFIG_SAE */
@@ -1646,7 +1649,8 @@  int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
 void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 			 const u8 *bssid, int akmp, int cipher,
-			 u16 group, int network_id);
+			 u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len);
 void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
 int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 			     const u8 *data, size_t data_len, u8 acked);