diff mbox

supplicant: Allow ignoring specific mgt frame types.

Message ID 1485300080-5554-1-git-send-email-greearb@candelatech.com
State Changes Requested
Headers show

Commit Message

Ben Greear Jan. 24, 2017, 11:21 p.m. UTC
From: Ben Greear <greearb@candelatech.com>

Allow supplicant to specifically ignore some common management
frame types.  This gives more control than just randomly ignoring
any of the auth frames.

This adds support for ignoring assoc, deauth, eapol 1/4,
eapol 3/4, and eapol 1/2 messages.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---
 src/rsn_supp/wpa.c                 | 68 ++++++++++++++++++++++++++++++++++++++
 src/rsn_supp/wpa.h                 | 23 +++++++++++++
 wpa_supplicant/config.c            | 10 ++++++
 wpa_supplicant/config.h            |  5 +++
 wpa_supplicant/events.c            | 16 +++++----
 wpa_supplicant/wpa_supplicant.c    | 28 ++++++++++++++++
 wpa_supplicant/wpa_supplicant.conf |  9 +++++
 7 files changed, 153 insertions(+), 6 deletions(-)

Comments

Jouni Malinen Feb. 5, 2017, 7:45 p.m. UTC | #1
On Tue, Jan 24, 2017 at 06:21:20PM -0500, greearb@candelatech.com wrote:
> Allow supplicant to specifically ignore some common management
> frame types.  This gives more control than just randomly ignoring
> any of the auth frames.
> 
> This adds support for ignoring assoc, deauth, eapol 1/4,
> eapol 3/4, and eapol 1/2 messages.

Same here.. External management and/or EAPOL frame processing can be
used for testing purposes to drop, delay, and modify frames with much
more flexibility. Adding a different mechanism for doing that is extra
complexity that does not look justifiable.
diff mbox

Patch

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 365845f..4d68998 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1878,6 +1878,74 @@  static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
 }
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_TESTING_OPTIONS
+/* Mostly same as below, but this should not change any state.  Returns the
+ * message type so we can make decisions before feeding this into the state
+ * machine.
+ */
+enum eapol_key_msg_type wpa_eapol_key_type(struct wpa_sm *sm, const u8 *buf, size_t len)
+{
+	size_t plen;
+	const struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info;
+	enum eapol_key_msg_type ret = EAPOL_MSG_TYPE_UNKNOWN;
+	size_t mic_len, keyhdrlen;
+
+	mic_len = wpa_mic_len(sm->key_mgmt);
+	keyhdrlen = sizeof(*key) + mic_len + 2;
+
+	if (len < sizeof(*hdr) + keyhdrlen) {
+		return ret;
+	}
+
+	hdr = (const struct ieee802_1x_hdr *) buf;
+	plen = be_to_host16(hdr->length);
+
+	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
+		goto out;
+	}
+	if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
+		goto out;
+	}
+
+	key = (struct wpa_eapol_key *) (buf + sizeof(struct ieee802_1x_hdr));
+
+	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
+	{
+		goto out;
+	}
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+		if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
+			goto out;
+		}
+
+		if (key_info & (WPA_KEY_INFO_MIC |
+				WPA_KEY_INFO_ENCR_KEY_DATA)) {
+			/* 3/4 4-Way Handshake */
+			ret = EAPOL_MSG_TYPE_3_OF_4;
+			goto out;
+		} else {
+			/* 1/4 4-Way Handshake */
+			ret = EAPOL_MSG_TYPE_1_OF_4;
+			goto out;
+		}
+	} else {
+		if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
+		    (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
+			/* 1/2 Group Key Handshake */
+			ret = EAPOL_MSG_TYPE_GROUP_1_OF_2;
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+#endif
 
 /**
  * wpa_sm_rx_eapol - Process received WPA EAPOL frames
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index c9f278a..29b2f33 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -109,8 +109,24 @@  struct rsn_supp_config {
 	int wpa_rsc_relaxation;
 };
 
+enum eapol_key_msg_type {
+	EAPOL_MSG_TYPE_UNKNOWN,
+	EAPOL_MSG_TYPE_1_OF_4, /* rx by sta */
+	EAPOL_MSG_TYPE_2_OF_4, /* sent by sta */
+	EAPOL_MSG_TYPE_3_OF_4, /* rx by sta */
+	EAPOL_MSG_TYPE_4_OF_4, /* sent by sta */
+	EAPOL_MSG_TYPE_GROUP_1_OF_2, /* rx by sta */
+	EAPOL_MSG_TYPE_GROUP_2_OF_2, /* sent by sta */
+};
+
+
 #ifndef CONFIG_NO_WPA
 
+#ifdef CONFIG_TESTING_OPTIONS
+enum eapol_key_msg_type wpa_eapol_key_type(struct wpa_sm *sm, const u8 *buf, size_t len);
+#endif
+
+
 struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
 void wpa_sm_deinit(struct wpa_sm *sm);
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
@@ -169,6 +185,13 @@  void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
 
 #else /* CONFIG_NO_WPA */
 
+#ifdef CONFIG_TESTING_OPTIONS
+enum eapol_key_msg_type wpa_eapol_key_type(struct wpa_sm *sm, const u8 *src_addr,
+					   const u8 *buf, size_t len) {
+	return EAPOL_MSG_TYPE_UNKNOWN;
+}
+#endif
+
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
 {
 	return (struct wpa_sm *) 1;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 9a1cc36..2bff8e7 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3833,6 +3833,11 @@  struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->accept_external_scan_results = DEFAULT_ACCEPT_EXTERNAL_SCAN_RESULTS;
 #if CONFIG_TESTING_OPTIONS
 	config->ignore_auth_resp = DEFAULT_IGNORE_AUTH_RESP;
+	config->ignore_assoc = DEFAULT_IGNORE_AUTH_RESP;
+	config->ignore_deauth = DEFAULT_IGNORE_AUTH_RESP;
+	config->ignore_eapol_1_of_4 = DEFAULT_IGNORE_AUTH_RESP;
+	config->ignore_eapol_3_of_4 = DEFAULT_IGNORE_AUTH_RESP;
+	config->ignore_eapol_1_of_2 = DEFAULT_IGNORE_AUTH_RESP;
 #endif
 
 	return config;
@@ -4553,6 +4558,11 @@  static const struct global_parse_data global_fields[] = {
 	{ INT(concurrent_assoc_ok), 0 },
 #if CONFIG_TESTING_OPTIONS
 	{ INT(ignore_auth_resp), 0 },
+	{ INT(ignore_assoc), 0 },
+	{ INT(ignore_deauth), 0 },
+	{ INT(ignore_eapol_1_of_4), 0 },
+	{ INT(ignore_eapol_3_of_4), 0 },
+	{ INT(ignore_eapol_1_of_2), 0 },
 #endif
 	{ INT(accept_external_scan_results), 0 },
 	{ STR(wowlan_triggers), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3600f1f..f93ca78 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -886,6 +886,11 @@  struct wpa_config {
 	 * 0 == never, 65535 == always
 	 */
 	unsigned short ignore_auth_resp;
+	unsigned short ignore_assoc;
+	unsigned short ignore_deauth;
+	unsigned short ignore_eapol_1_of_4;
+	unsigned short ignore_eapol_3_of_4;
+	unsigned short ignore_eapol_1_of_2;
 #endif
 
 	/**
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 828019f..4635dff 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3725,10 +3725,12 @@  void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		break;
 	case EVENT_ASSOC:
 #ifdef CONFIG_TESTING_OPTIONS
-		if (wpa_s->conf->ignore_auth_resp &&
-		    (os_random_16() < wpa_s->conf->ignore_auth_resp)) {
+		if ((wpa_s->conf->ignore_auth_resp &&
+		     (os_random_16() < wpa_s->conf->ignore_auth_resp)) ||
+		    (wpa_s->conf->ignore_assoc &&
+		     (os_random_16() < wpa_s->conf->ignore_assoc))) {
 			wpa_dbg(wpa_s, MSG_INFO,
-				"EVENT_ASSOC - ignore_auth_resp active!");
+				"EVENT_ASSOC - ignore_assoc active!");
 			break;
 		}
 #endif /* CONFIG_TESTING_OPTIONS */
@@ -3747,10 +3749,12 @@  void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		break;
 	case EVENT_DEAUTH:
 #ifdef CONFIG_TESTING_OPTIONS
-		if (wpa_s->conf->ignore_auth_resp &&
-		    (os_random_16() < wpa_s->conf->ignore_auth_resp)) {
+		if ((wpa_s->conf->ignore_auth_resp &&
+		     (os_random_16() < wpa_s->conf->ignore_auth_resp)) ||
+		    (wpa_s->conf->ignore_deauth &&
+		     (os_random_16() < wpa_s->conf->ignore_deauth))) {
 			wpa_dbg(wpa_s, MSG_INFO,
-				"EVENT_DEAUTH - ignore_auth_resp active!");
+				"EVENT_DEAUTH - ignore_deauth active!");
 			break;
 		}
 #endif /* CONFIG_TESTING_OPTIONS */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 19a2710..52a986a 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3502,6 +3502,9 @@  void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 			     const u8 *buf, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
+#ifdef CONFIG_TESTING_OPTIONS
+	enum eapol_key_msg_type emt;
+#endif
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
@@ -3512,6 +3515,31 @@  void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 		wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
 		return;
 	}
+
+
+	/* Check for dropping specific eapol frames */
+	emt = wpa_eapol_key_type(wpa_s->wpa, buf, len);
+	if (emt == EAPOL_MSG_TYPE_1_OF_4) {
+		if (wpa_s->conf->ignore_eapol_1_of_4 &&
+		    (os_random_16() < wpa_s->conf->ignore_eapol_1_of_4)) {
+			wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - ignore_eapol_1_of_4 active!");
+			return;
+		}
+	}
+	else if (emt == EAPOL_MSG_TYPE_3_OF_4) {
+		if (wpa_s->conf->ignore_eapol_3_of_4 &&
+		    (os_random_16() < wpa_s->conf->ignore_eapol_3_of_4)) {
+			wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - ignore_eapol_3_of_4 active!");
+			return;
+		}
+	}
+	else if (emt == EAPOL_MSG_TYPE_GROUP_1_OF_2) {
+		if (wpa_s->conf->ignore_eapol_1_of_2 &&
+		    (os_random_16() < wpa_s->conf->ignore_eapol_1_of_2)) {
+			wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - ignore_eapol_1_of_2 active!");
+			return;
+		}
+	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_PEERKEY
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index fbe9b25..27985a3 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1367,9 +1367,18 @@  fast_reauth=1
 # Testing logic, not for use in production systems.
 # Value is 0-65535, where 0 means never ignore, 65535 means always
 # ignore, and the range between is a percentage chance.
+# This matches all eapol messages, AUTH, and DEAUTH messages.
 # You must enable CONFIG_TESTING_OPTIONS when compiling to enable this.
 #ignore_auth_resp=1000
 
+# More specific ways to ignore certain frame types.  Same range as
+# ignore_auth_resp
+#ignore_assoc=1000
+#ignore_deauth=1000
+#ignore_eapol_1_of_4=1000
+#ignore_eapol_3_of_4=1000
+#ignore_eapol_1_of_2=1000
+
 
 # Example blocks: