[RFC,3/3] wpa_supplicant support for Extended Key ID

Message ID 20181111115441.15015-4-alexander.wetzel@web.de
State New
Headers show
Series
  • Extended Key ID support
Related show

Commit Message

Alexander Wetzel Nov. 11, 2018, 11:54 a.m.
From: Alexander Wetzel <alexander@wetzel-home.de>

Experimental support for Extended Key ID for wpa_supplicant for
participation in BSS.
Tested for basic functionality and backward compatibility but still WIP.

Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
 src/rsn_supp/wpa.c              | 67 +++++++++++++++++++++++++++++----
 src/rsn_supp/wpa.h              |  4 +-
 src/rsn_supp/wpa_i.h            |  3 ++
 src/rsn_supp/wpa_ie.c           | 11 ++++++
 src/rsn_supp/wpa_ie.h           |  1 +
 wpa_supplicant/config.c         |  2 +
 wpa_supplicant/config_file.c    |  1 +
 wpa_supplicant/config_ssid.h    | 11 ++++++
 wpa_supplicant/ibss_rsn.c       | 11 +++---
 wpa_supplicant/mesh_rsn.c       |  3 +-
 wpa_supplicant/wpa_supplicant.c |  6 +++
 wpa_supplicant/wpas_glue.c      |  1 +
 12 files changed, 107 insertions(+), 14 deletions(-)

Patch

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e0c913074..ea7b68110 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -714,7 +714,8 @@  static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
 
 
 static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key)
+				      const struct wpa_eapol_key *key,
+				      int key_flag)
 {
 	int keylen, rsclen;
 	enum wpa_alg alg;
@@ -749,6 +750,11 @@  static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 			   keylen, (long unsigned int) sm->ptk.tk_len);
 		return -1;
 	}
+
+	if (key_flag && key_flag != KEY_FLAG_RX_ONLY) {
+		wpa_printf(MSG_DEBUG, "WPA: key_flag=%d invalid", key_flag);
+		return -1;
+	}
 	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
 
 	if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
@@ -758,18 +764,47 @@  static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
 	}
 
-	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+	if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, key_flag,
+			   key_rsc, rsclen, sm->ptk.tk, keylen) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set PTK to the "
-			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
-			alg, keylen, MAC2STR(sm->bssid));
+			"driver (alg=%d extID=%d key_flag=%d keylen=%d bssid="
+			MACSTR ")", alg, sm->Ext_Key_ID, key_flag, keylen,
+			MAC2STR(sm->bssid));
 		return -1;
 	}
 
 	/* TK is not needed anymore in supplicant */
 	os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
 	sm->ptk.tk_len = 0;
+
+	if (!key_flag) {
+		sm->ptk.installed = 1;
+
+		if (sm->wpa_ptk_rekey) {
+			eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+			eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
+					       sm, NULL);
+		}
+	}
+
+	return 0;
+}
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Activating PTK in driver");
+
+	if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active,
+	    KEY_FLAG_TX, 0, 0, NULL, 0) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to activate PTK in the "
+			"driver (idx=%d bssid=" MACSTR ")",
+			sm->keyidx_active, MAC2STR(sm->bssid));
+		return -1;
+	}
+
 	sm->ptk.installed = 1;
 
 	if (sm->wpa_ptk_rekey) {
@@ -781,7 +816,6 @@  static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 	return 0;
 }
 
-
 static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
 					     int group_cipher,
 					     int keylen, int maxkeylen,
@@ -1367,6 +1401,12 @@  static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
 	if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
 		goto failed;
+
+	if (ie.ptk_id && sm->wpa_ext_key_id) {
+		sm->keyidx_active = ie.ptk_id[0];
+		sm->Ext_Key_ID = 1;
+	}
+
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: GTK IE in unencrypted key data");
@@ -1418,6 +1458,11 @@  static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	}
 #endif /* CONFIG_P2P */
 
+	if (sm->Ext_Key_ID) {
+		if (wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX_ONLY))
+			goto failed;
+	}
+
 	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
 				       &sm->ptk) < 0) {
 		goto failed;
@@ -1429,8 +1474,12 @@  static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	sm->renew_snonce = 1;
 
 	if (key_info & WPA_KEY_INFO_INSTALL) {
-		if (wpa_supplicant_install_ptk(sm, key))
+		if (sm->Ext_Key_ID) {
+			if (wpa_supplicant_activate_ptk(sm))
+				goto failed;
+		} else if (wpa_supplicant_install_ptk(sm, key, 0)) {
 			goto failed;
+		}
 	}
 
 	if (key_info & WPA_KEY_INFO_SECURE) {
@@ -2464,6 +2513,7 @@  struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
 		return NULL;
 	dl_list_init(&sm->pmksa_candidates);
 	sm->renew_snonce = 1;
+	sm->keyidx_active = 0;
 	sm->ctx = ctx;
 
 	sm->dot11RSNAConfigPMKLifetime = 43200;
@@ -2847,6 +2897,9 @@  int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
 	case WPA_PARAM_PAIRWISE:
 		sm->pairwise_cipher = value;
 		break;
+	case WPA_PARAM_SUPP_EXT_KEY_ID:
+		sm->wpa_ext_key_id = value;
+		break;
 	case WPA_PARAM_GROUP:
 		sm->group_cipher = value;
 		break;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 21f4b1781..e02c68cd8 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -95,7 +95,8 @@  enum wpa_sm_conf_params {
 	WPA_PARAM_KEY_MGMT,
 	WPA_PARAM_MGMT_GROUP,
 	WPA_PARAM_RSN_ENABLED,
-	WPA_PARAM_MFP
+	WPA_PARAM_MFP,
+	WPA_PARAM_SUPP_EXT_KEY_ID
 };
 
 struct rsn_supp_config {
@@ -106,6 +107,7 @@  struct rsn_supp_config {
 	void *eap_conf_ctx;
 	const u8 *ssid;
 	size_t ssid_len;
+	int wpa_ext_key_id;
 	int wpa_ptk_rekey;
 	int p2p;
 	int wpa_rsc_relaxation;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index b94b17a85..f1b7e8983 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -26,6 +26,7 @@  struct wpa_sm {
 	u8 snonce[WPA_NONCE_LEN];
 	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
 	int renew_snonce;
+	int keyidx_active;
 	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int rx_replay_counter_set;
 	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
@@ -65,6 +66,8 @@  struct wpa_sm {
 	int wpa_ptk_rekey;
 	int p2p;
 	int wpa_rsc_relaxation;
+	int wpa_ext_key_id;
+	int Ext_Key_ID;
 
 	u8 own_addr[ETH_ALEN];
 	const char *ifname;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index a3410d154..358c6d595 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -223,6 +223,9 @@  static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 	if (sm->mfp == 2)
 		capab |= WPA_CAPABILITY_MFPR;
 #endif /* CONFIG_IEEE80211W */
+	if (sm->wpa_ext_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
 	WPA_PUT_LE16(pos, capab);
 	pos += 2;
 
@@ -415,6 +418,14 @@  static int wpa_parse_generic(const u8 *pos, const u8 *end,
 		return 0;
 	}
 
+	if (pos[1] > RSN_SELECTOR_LEN + 1 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
+		ie->ptk_id = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
 		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 0e72af560..5adc4c8e0 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -17,6 +17,7 @@  struct wpa_eapol_ie_parse {
 	const u8 *rsn_ie;
 	size_t rsn_ie_len;
 	const u8 *pmkid;
+	const u8 *ptk_id;
 	const u8 *gtk;
 	size_t gtk_len;
 	const u8 *mac_addr;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c43960697..840d8be82 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2252,6 +2252,7 @@  static const struct parse_data ssid_fields[] = {
 	{ INT(dot11MeshConfirmTimeout) },
 	{ INT(dot11MeshHoldingTimeout) },
 #endif /* CONFIG_MESH */
+	{ INT(wpa_ext_key_id) },
 	{ INT(wpa_ptk_rekey) },
 	{ INT(group_rekey) },
 	{ STR(bgscan) },
@@ -2764,6 +2765,7 @@  void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
 {
 	ssid->proto = DEFAULT_PROTO;
 	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+	ssid->wpa_ext_key_id = DEFAULT_EXT_KEY_ID;
 	ssid->group_cipher = DEFAULT_GROUP;
 	ssid->key_mgmt = DEFAULT_KEY_MGMT;
 	ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 09115e19d..7732b44a3 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -869,6 +869,7 @@  static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 	INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
 	INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
 #endif /* CONFIG_MESH */
+	INT(wpa_ext_key_id);
 	INT(wpa_ptk_rekey);
 	INT(group_rekey);
 	INT(ignore_broadcast_ssid);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index d2a52d760..52bd189d2 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -22,6 +22,7 @@ 
 #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
 #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
 #define DEFAULT_FRAGMENT_SIZE 1398
+#define DEFAULT_EXT_KEY_ID 1
 
 #define DEFAULT_BG_SCAN_PERIOD -1
 #define DEFAULT_MESH_MAX_RETRIES 2
@@ -510,6 +511,16 @@  struct wpa_ssid {
 	unsigned int vht_center_freq1;
 	unsigned int vht_center_freq2;
 
+	/** wpa_ext_key_id - Control support for Extended Key ID
+	 *
+	 * IEEE Std 802.11-2016 optionally allows to use key id 0 and 1 for
+	 * PTK keys and shift GTK keys to id 2 and 3.
+	 * default: auto (1)
+	 * 0 = force off. Do not announce or use Extended Key ID.
+	 * 1 = auto. Allow the AP to use Extended Key ID when possible.
+	 */
+	int wpa_ext_key_id;
+
 	/**
 	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
 	 *
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 00919d14a..a3b0e91c2 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -137,15 +137,15 @@  static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
 
 
 static int supp_set_key(void *ctx, enum wpa_alg alg,
-			const u8 *addr, int key_idx, int set_tx,
+			const u8 *addr, int key_idx, int key_flag,
 			const u8 *seq, size_t seq_len,
 			const u8 *key, size_t key_len)
 {
 	struct ibss_rsn_peer *peer = ctx;
 
 	wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
-		   "set_tx=%d)",
-		   __func__, alg, MAC2STR(addr), key_idx, set_tx);
+		   "key_flag=%d)",
+		   __func__, alg, MAC2STR(addr), key_idx, key_flag);
 	wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
 	wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
 
@@ -166,7 +166,7 @@  static int supp_set_key(void *ctx, enum wpa_alg alg,
 	if (is_broadcast_ether_addr(addr))
 		addr = peer->addr;
 	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
-			       set_tx, seq, seq_len, key, key_len);
+			       key_flag, seq, seq_len, key, key_len);
 }
 
 
@@ -293,7 +293,8 @@  static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			int key_flag)
 {
 	struct ibss_rsn *ibss_rsn = ctx;
 	u8 seq[6];
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e74cb16b0..62dc0f66e 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -98,7 +98,8 @@  static const u8 *auth_get_psk(void *ctx, const u8 *addr,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			int key_flag)
 {
 	struct mesh_rsn *mesh_rsn = ctx;
 	u8 seq[6];
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6090e0662..341062aa2 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1194,6 +1194,12 @@  int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 	int sel, proto;
 	const u8 *bss_wpa, *bss_rsn, *bss_osen;
 
+	if (ssid->wpa_ext_key_id &&
+	    wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Enable Extended Key ID support.");
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SUPP_EXT_KEY_ID, 1);
+	}
+
 	if (bss) {
 		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
 		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 4634ed7fc..9bc1583bb 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1263,6 +1263,7 @@  void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
 #endif /* IEEE8021X_EAPOL */
 		conf.ssid = ssid->ssid;
 		conf.ssid_len = ssid->ssid_len;
+		conf.wpa_ext_key_id = ssid->wpa_ext_key_id;
 		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
 #ifdef CONFIG_P2P
 		if (ssid->p2p_group && wpa_s->current_bss &&