[PATCH v2 2/3] STA: Support Extended Key ID

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Support Extended Key ID in wpa_supplicant according to
IEEE 802.11-2016 for infrastructure (AP) associations.

Extended Key ID allows to rekey pairwise keys without the otherwise
unavoidable MPDU losses on a busy link. The standard is fully backward
compatible, allowing STAs to also connect to APs not supporting it.

Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
---
 src/rsn_supp/wpa.c                      | 135 ++++++++++++++++++++++--
 src/rsn_supp/wpa.h                      |  13 +++
 src/rsn_supp/wpa_ft.c                   |  27 ++++-
 src/rsn_supp/wpa_i.h                    |   3 +
 src/rsn_supp/wpa_ie.c                   |   2 +
 wpa_supplicant/ap.c                     |   1 +
 wpa_supplicant/config.c                 |   2 +
 wpa_supplicant/config.h                 |  18 ++++
 wpa_supplicant/config_file.c            |   3 +
 wpa_supplicant/config_winreg.c          |  10 ++
 wpa_supplicant/ctrl_iface.c             |  35 +++++-
 wpa_supplicant/dbus/dbus_new_handlers.c |   3 +-
 wpa_supplicant/driver_i.h               |   9 +-
 wpa_supplicant/wpa_cli.c                |   3 +-
 wpa_supplicant/wpa_supplicant.c         |  24 ++++-
 wpa_supplicant/wpa_supplicant.conf      |   7 ++
 wpa_supplicant/wpas_glue.c              |   6 +-
 17 files changed, 278 insertions(+), 23 deletions(-)

diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5bb47bcbe..75d564b9c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -184,6 +184,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 	u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
 
 	if (pairwise && sm->wpa_deny_ptk0_rekey &&
+	    !sm->use_extended_key_id &&
 	    wpa_sm_get_state(sm) == WPA_COMPLETED) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: PTK0 rekey not allowed, reconnecting");
@@ -607,6 +608,58 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
 			      sm->pairwise_cipher, z, z_len);
 }
 
+#ifdef CONFIG_FILS
+static int fils_handle_extended_key_id(struct wpa_sm *sm,
+				       struct wpa_eapol_ie_parse *kde)
+{
+	struct wpa_ie_data rsn;
+
+	sm->keyidx_active = 0;
+	if (sm->extended_key_id && sm->pairwise_cipher != WPA_CIPHER_TKIP &&
+	    !wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &rsn) &&
+	    rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)
+		sm->use_extended_key_id = 1;
+	else
+		sm->use_extended_key_id = 0;
+	return 0;
+}
+#endif /* CONFIG_FILS */
+
+static int handle_extended_key_id(struct wpa_sm *sm,
+				  struct wpa_eapol_ie_parse *kde)
+{
+	struct wpa_ie_data rsn;
+
+	if (sm->extended_key_id && sm->pairwise_cipher != WPA_CIPHER_TKIP &&
+	    !wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &rsn) &&
+	    rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) {
+		if (!kde->key_id) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: No KeyID in Extended Key ID handshake");
+			return -1;
+		} else if (kde->key_id[0] & 0xfe) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: Invalid KeyID: %d", kde->key_id[0]);
+			return -1;
+		}
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: Using Extended Key ID");
+		sm->keyidx_active = kde->key_id[0];
+		sm->use_extended_key_id = 1;
+	} else {
+		if (kde->key_id && kde->key_id[0]) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"Non-zero Extended Key ID KeyID in PTK0 handshake");
+			return -1;
+		} else if (kde->key_id) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"Extended Key ID KeyID in PTK0 handshake");
+		}
+		sm->keyidx_active = 0;
+		sm->use_extended_key_id = 0;
+	}
+	return 0;
+}
 
 static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 					  const unsigned char *src_addr,
@@ -626,7 +679,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
 		return;
 	}
 
-	if (sm->wpa_deny_ptk0_rekey && wpa_sm_get_state(sm) == WPA_COMPLETED) {
+	if (sm->wpa_deny_ptk0_rekey && !sm->use_extended_key_id &&
+	    wpa_sm_get_state(sm) == WPA_COMPLETED) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: PTK0 rekey not allowed, reconnecting");
 		wpa_sm_reconnect(sm);
@@ -762,9 +816,10 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
 {
 	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 		"WPA: Key negotiation completed with "
-		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
+		MACSTR " [PTK=%s GTK=%s%s]", MAC2STR(addr),
 		wpa_cipher_txt(sm->pairwise_cipher),
-		wpa_cipher_txt(sm->group_cipher));
+		wpa_cipher_txt(sm->group_cipher),
+		sm->use_extended_key_id ? " Extended_Key_ID" : "");
 	wpa_sm_cancel_auth_timeout(sm);
 	wpa_sm_set_state(sm, WPA_COMPLETED);
 
@@ -859,13 +914,15 @@ 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,
+	if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
+			   rsclen, sm->ptk.tk, keylen,
 			   KEY_FLAG_PAIRWISE | key_flag) < 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));
+			"WPA: Failed to set PTK to the driver"
+			"(alg=%d keylen=%d bssid=" MACSTR
+			" idx=%d use_extended_key_id=%d key_flag=0x%x)",
+			alg, keylen, MAC2STR(sm->bssid),
+			sm->keyidx_active, sm->use_extended_key_id, key_flag);
 		return -1;
 	}
 
@@ -879,7 +936,22 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 		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: Activate PTK (idx=%d bssid=" MACSTR ")",
+		sm->keyidx_active, MAC2STR(sm->bssid));
+
+	if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active,
+	    0, NULL, 0, NULL, 0,  KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+			"WPA: Failed to activate PTK for Tx (idx=%d bssid="
+			MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+		return -1;
+	}
 	return 0;
 }
 
@@ -1582,6 +1654,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
 		goto failed;
 
+	if (handle_extended_key_id(sm, &ie))
+		goto failed;
+
 	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1626,6 +1701,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 		}
 	}
 #endif /* CONFIG_OCV */
+	if (sm->use_extended_key_id) {
+		if (wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
+			goto failed;
+	}
 
 	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
 				       &sm->ptk) < 0) {
@@ -1638,8 +1717,13 @@ 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, KEY_FLAG_RX_TX))
+		if (sm->use_extended_key_id) {
+			if (wpa_supplicant_activate_ptk(sm))
+				goto failed;
+		} else if (wpa_supplicant_install_ptk(sm, key,
+						      KEY_FLAG_RX_TX)) {
 			goto failed;
+		}
 	}
 
 	if (key_info & WPA_KEY_INFO_SECURE) {
@@ -2746,6 +2830,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;
@@ -3164,6 +3249,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
 	case WPA_PARAM_DENY_PTK0_REKEY:
 		sm->wpa_deny_ptk0_rekey = value;
 		break;
+	case WPA_PARAM_EXTENDED_KEY_ID:
+		sm->extended_key_id = value;
+		break;
 	default:
 		break;
 	}
@@ -3238,6 +3326,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
 }
 
 
+int wpa_sm_extended_key_id(struct wpa_sm *sm)
+{
+	return sm->extended_key_id;
+}
+
+
+int wpa_sm_extended_key_id_active(struct wpa_sm *sm)
+{
+	return sm->use_extended_key_id;
+}
+
+
 int wpa_sm_ocv_enabled(struct wpa_sm *sm)
 {
 	struct wpa_ie_data rsn;
@@ -4253,6 +4353,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
 		capab |= WPA_CAPABILITY_MFPR;
 	if (sm->ocv)
 		capab |= WPA_CAPABILITY_OCVC;
+	if (sm->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	wpabuf_put_le16(buf, capab);
 
 	/* PMKID Count */
@@ -4645,6 +4747,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 		wpa_printf(MSG_DEBUG, "FILS: No GTK KDE");
 		goto fail;
 	}
+
 	maxkeylen = gd.gtk_len = kde.gtk_len - 2;
 	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
 					      gd.gtk_len, maxkeylen,
@@ -4680,11 +4783,21 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 			   keylen, (long unsigned int) sm->ptk.tk_len);
 		goto fail;
 	}
+
+	if (elems.rsn_ie) {
+		/* link in RSN for fils_handle_extended_key_id() */
+		kde.rsn_ie = elems.rsn_ie - 2;
+		kde.rsn_ie_len = elems.rsn_ie_len + 2;
+	}
+	if (fils_handle_extended_key_id(sm, &kde))
+		goto fail;
+
 	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
 	wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
 			sm->ptk.tk, keylen);
-	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
-			   sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
+	if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1,
+			   null_rsc, rsclen, sm->ptk.tk, keylen,
+			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
 			MACSTR ")",
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 0bd14495a..585bbcc95 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -102,6 +102,7 @@ enum wpa_sm_conf_params {
 	WPA_PARAM_OCV,
 	WPA_PARAM_SAE_PWE,
 	WPA_PARAM_DENY_PTK0_REKEY,
+	WPA_PARAM_EXTENDED_KEY_ID,
 };
 
 struct rsn_supp_config {
@@ -154,6 +155,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
 int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
 		      int verbose);
 int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_extended_key_id(struct wpa_sm *sm);
+int wpa_sm_extended_key_id_active(struct wpa_sm *sm);
 int wpa_sm_ocv_enabled(struct wpa_sm *sm);
 
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -300,6 +303,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
 	return 0;
 }
 
+static inline int wpa_sm_extended_key_id(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline int wpa_sm_extended_key_id_active(struct wpa_sm *sm)
+{
+	return 0;
+}
+
 static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
 {
 	return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index baa185ffe..9592d10d7 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -263,6 +263,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
 		capab |= WPA_CAPABILITY_MFPR;
 	if (sm->ocv)
 		capab |= WPA_CAPABILITY_OCVC;
+	if (sm->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	WPA_PUT_LE16(pos, capab);
 	pos += 2;
 
@@ -429,8 +431,8 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
 	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
-	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
-			   (u8 *) sm->ptk.tk, keylen,
+	if (wpa_sm_set_key(sm, alg, bssid, sm->keyidx_active, 1, null_rsc,
+			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen,
 			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
@@ -440,6 +442,26 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 }
 
 
+static void ft_handle_extended_key_id(struct wpa_sm *sm,
+				      struct wpa_ft_ies *parse)
+{
+	if (sm->extended_key_id && parse->rsn &&
+	    sm->pairwise_cipher != WPA_CIPHER_TKIP &&
+	    parse->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: Using Extended Key ID");
+		sm->use_extended_key_id = 1;
+	} else {
+		sm->use_extended_key_id = 0;
+	}
+	/* There is no standardized way to hand over the KeyID in FT.
+	 * Since FT can only be used for the initial connect we assume
+	 * it must be 0.
+	 */
+	sm->keyidx_active = 0;
+}
+
+
 /**
  * wpa_ft_prepare_auth_request - Generate over-the-air auth request
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -661,6 +683,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
 		os_free(ft_ies);
 	}
 
+	ft_handle_extended_key_id(sm, &parse);
 	wpa_sm_mark_authenticated(sm, bssid);
 	ret = wpa_ft_install_ptk(sm, bssid);
 	if (ret) {
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 7af678dcd..27c31f8ca 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];
@@ -68,6 +69,8 @@ struct wpa_sm {
 	int wpa_rsc_relaxation;
 	int owe_ptk_workaround;
 	int beacon_prot;
+	int extended_key_id;
+	int use_extended_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 03c0d7e85..c9899595e 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -221,6 +221,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 		capab |= WPA_CAPABILITY_MFPR;
 	if (sm->ocv)
 		capab |= WPA_CAPABILITY_OCVC;
+	if (sm->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	WPA_PUT_LE16(pos, capab);
 	pos += 2;
 
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 87573ef10..ee7c755b5 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -344,6 +344,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 #endif /* CONFIG_IEEE80211AX */
 
 	bss->isolate = !wpa_s->conf->p2p_intra_bss;
+	bss->extended_key_id = wpa_s->conf->extended_key_id;
 	bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
 	bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey;
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2b9c3f53e..2fef83a5a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4293,6 +4293,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
 	config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
 	config->cert_in_cb = DEFAULT_CERT_IN_CB;
 	config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+	config->extended_key_id = DEFAULT_EXTENDED_KEY_ID;
 
 #ifdef CONFIG_MBO
 	config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
@@ -5057,6 +5058,7 @@ static const struct global_parse_data global_fields[] = {
 	{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
 #ifdef CONFIG_WNM
 	{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
+	{ INT_RANGE(extended_key_id, 0, 1), 0 },
 #endif /* CONFIG_WNM */
 };
 
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index b3c779233..165be35f7 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -44,6 +44,12 @@
 #define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED
 #define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
 #define DEFAULT_OCE_SUPPORT OCE_STA
+#ifdef CONFIG_TESTING_OPTIONS
+/* For now only testing is using Extended Key ID by default */
+#define DEFAULT_EXTENDED_KEY_ID 1
+#else /* CONFIG_TESTING_OPTIONS */
+#define DEFAULT_EXTENDED_KEY_ID 0
+#endif /* CONFIG_TESTING_OPTIONS */
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -1570,6 +1576,18 @@ struct wpa_config {
 	 * By default BSS transition management is enabled
 	 */
 	int disable_btm;
+
+	/** extended_key_id - Extended Key ID support
+	 *
+	 * IEEE 802.11-2016 optionally allows to use keyid 0 and 1 for PTK keys
+	 * with Extended Key ID.
+	 *
+	 * 0 = don't use Extended Key ID
+	 * 1 = use Extended Key ID when possible
+	 *
+	 * By default Extended Key ID support is disabled
+	 */
+	int extended_key_id;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index b8e56f5b2..e77cbca4f 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1596,6 +1596,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
 			config->p2p_interface_random_mac_addr);
 	if (config->disable_btm)
 		fprintf(f, "disable_btm=1\n");
+	if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
+		fprintf(f, "extended_key_id=%d\n",
+			config->extended_key_id);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 598bc7790..2ff5f27ec 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -277,6 +277,16 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
 	wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
 	wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
 	config->pmf = val;
+	if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
+				      &config->extended_key_id) == 0) {
+		if (config->extended_key_id < 0 ||
+		    config->extended_key_id > 1) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid Extended Key ID setting (%d)",
+				   config->extended_key_id);
+			errors++;
+		}
+	}
 
 	return errors ? -1 : 0;
 }
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 2321fc358..20ea5a515 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -746,11 +746,28 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 			pos++;
 		}
 	} else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
+		struct wpa_ie_data data;
+
 		wpabuf_free(wpa_s->rsne_override_eapol);
-		if (os_strcmp(value, "NULL") == 0)
+		if (os_strcmp(value, "NULL") == 0) {
 			wpa_s->rsne_override_eapol = NULL;
-		else
+		} else {
 			wpa_s->rsne_override_eapol = wpabuf_parse_bin(value);
+			if (!wpa_parse_wpa_ie_rsn(
+				wpabuf_head(wpa_s->rsne_override_eapol),
+				wpabuf_len(wpa_s->rsne_override_eapol),
+				&data) &&
+			    (data.capabilities &
+				WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+				wpa_s->conf->extended_key_id = 1;
+				wpa_printf(MSG_DEBUG,
+					   "TESTING: rsne_override_eapol enables Extended Key ID");
+			} else {
+				wpa_s->conf->extended_key_id = 0;
+				wpa_printf(MSG_DEBUG,
+					   "TESTING: rsne_override_eapol disables Extended Key ID");
+			}
+		}
 	} else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) {
 		wpabuf_free(wpa_s->rsnxe_override_assoc);
 		if (os_strcmp(value, "NULL") == 0)
@@ -5372,6 +5389,9 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
 
 	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
 			0, KEY_FLAG_PAIRWISE);
+	if (wpa_sm_extended_key_id(wpa_s->wpa))
+		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+				NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
 	/* MLME-SETPROTECTION.request(None) */
 	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
 				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -9338,6 +9358,7 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
 static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
 				   const char *cmd)
 {
+	struct wpa_ie_data data;
 	struct wpabuf *buf;
 	size_t len;
 
@@ -9360,6 +9381,16 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
 	}
 
 	wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+	if (!wpa_parse_wpa_ie_rsn(wpabuf_head(buf), wpabuf_len(buf), &data) &&
+	    (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+		wpa_s->conf->extended_key_id = 1;
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Forced own IE enables Extended Key ID");
+	} else {
+		wpa_s->conf->extended_key_id = 0;
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Forced own IE disables Extended Key ID");
+	}
 	return 0;
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index c842c50e9..d99242473 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -991,7 +991,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
 	const struct wpa_dbus_property_desc *property_desc,
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
-	const char *capabilities[11];
+	const char *capabilities[12];
 	size_t num_items = 0;
 #ifdef CONFIG_FILS
 	struct wpa_global *global = user_data;
@@ -1037,6 +1037,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
 #ifdef CONFIG_OWE
 	capabilities[num_items++] = "owe";
 #endif /* CONFIG_OWE */
+	capabilities[num_items++] = "extended_key_id";
 
 	return wpas_dbus_simple_array_property_getter(iter,
 						      DBUS_TYPE_STRING,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index d3fb58707..edde6fa99 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -165,7 +165,14 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 	params.key_flag = key_flag;
 
 	if (alg != WPA_ALG_NONE) {
-		if (key_idx >= 0 && key_idx <= 6)
+		/* keyidx = 1 can be either a broadcast or - with
+		 * Extended Key ID - an unicast key. Use bit 15 for
+		 * the pairwise keyidx 1 which is hopefully high enough
+		 * to not clash with future extensions.
+		 */
+		if (key_idx == 1 && key_flag & KEY_FLAG_PAIRWISE)
+			wpa_s->keys_cleared &= ~BIT(15);
+		else if (key_idx >= 0 && key_idx <= 5)
 			wpa_s->keys_cleared &= ~BIT(key_idx);
 		else
 			wpa_s->keys_cleared = 0;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 22885e646..730d749fe 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -502,6 +502,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
 		"ignore_auth_resp",
 #endif /* CONFIG_TESTING_OPTIONS */
 		"relative_rssi", "relative_band_adjust",
+		"extended_key_id",
 	};
 	int i, num_fields = ARRAY_SIZE(fields);
 
@@ -593,7 +594,7 @@ static char ** wpa_cli_complete_get(const char *str, int pos)
 		"tdls_external_control", "osu_dir", "wowlan_triggers",
 		"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
 		"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
-		"reassoc_same_bss_optim"
+		"reassoc_same_bss_optim", "extended_key_id"
 	};
 	int i, num_fields = ARRAY_SIZE(fields);
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index c638fe535..d82e8828f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -748,10 +748,15 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
 				NULL, 0, KEY_FLAG_GROUP);
 	}
-	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+	/* Pairwise key idx 1 for Extended Key ID is tracked in bit 15 */
+	if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
 	    !is_zero_ether_addr(addr)) {
-		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
-				0, KEY_FLAG_PAIRWISE);
+		if (!(wpa_s->keys_cleared & (BIT(0))))
+			wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
+					0, NULL, 0, KEY_FLAG_PAIRWISE);
+		if (!(wpa_s->keys_cleared & (BIT(15))))
+			wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
+					0, NULL, 0, KEY_FLAG_PAIRWISE);
 		/* MLME-SETPROTECTION.request(None) */
 		wpa_drv_mlme_setprotection(
 			wpa_s, addr,
@@ -1635,6 +1640,19 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 		sae_pwe = 1;
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
 
+	/* Extended Key ID is only supported in INFRA mode so far */
+	if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id &&
+	    ssid->proto & WPA_PROTO_RSN &&
+	    ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+				     WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+	    wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) {
+		wpa_msg(wpa_s, MSG_INFO, "Enable Extended Key ID support");
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID,
+				 wpa_s->conf->extended_key_id);
+	} else {
+		wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID, 0);
+	}
+
 	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
 		return -1;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index f3a750e3c..c75cc9248 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -802,6 +802,13 @@ fast_reauth=1
 # Set BIT(1) to Enable OCE in STA-CFON mode
 #oce=1
 
+# extended_key_id:
+# "Extended Key ID support for Individually Addressed Frames" according to
+# IEEE 802.11-2016.
+#
+# 0 = force off: Do not use Extended Key ID (default)
+# 1 = auto: Activate Extended Key ID support
+
 # network block
 #
 # Each network (usually AP's sharing the same SSID) is configured as a separate
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 39b05b2b9..7ca1a9f64 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -533,7 +533,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 	}
 #endif /* CONFIG_TESTING_GET_GTK */
 #ifdef CONFIG_TESTING_OPTIONS
-	if (addr && !is_broadcast_ether_addr(addr)) {
+	if (addr && !is_broadcast_ether_addr(addr) &&
+	    !(key_flag & KEY_FLAG_MODIFY)) {
 		wpa_s->last_tk_alg = alg;
 		os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
 		wpa_s->last_tk_key_idx = key_idx;
@@ -1077,7 +1078,8 @@ static int wpa_supplicant_eap_auth_start_cb(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
-	if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey) {
+	if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey &&
+	    !wpa_sm_extended_key_id_active(wpa_s->wpa)) {
 		wpa_msg(wpa_s, MSG_INFO,
 			"WPA: PTK0 rekey not allowed, reconnecting");
 		wpa_supplicant_reconnect(wpa_s);
-- 
2.25.2


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux