[PATCH v2 1/3] AP: Support Extended Key ID

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

 



Support Extended Key ID in hostapd according to IEEE 802.11-2016.

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 an AP to serve STAs with and without Extended Key
ID support in the same BSS.

Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
---

This should have all the changes you requested.
We still verify that the Extended Key ID bit is used consequently and
disconnect anyone who violates the rule. (I figure it makes no sense to
add workarounds when there are no known broken implementations, yet.)

The biggest challenge was getting all tests using Extended Key ID while
having it off by default. The tests are updated assuming it's off but
after tripping over sigma.dut I gave up and changed the default for test
builds back to on. When you don't like that you can simply use the
"production" defaults and some tests will start using PTK0 again.
(Or you may know a better way to handle it...)

The decision to use a global config variable in wpa_supplicant is also
making deterministic tests a bit harder: I tried to make sure the test
revert to the default setting but I know I failed for many tests.
Especially when a test is executed with Extended Key ID disabled and
triggers an Exception the next test can be run without Extended Key ID
when it's not resetting the interface itself...

That said tests are looking great for me now. We are using Extended Key
ID now everywhere where I expect it. (Ignoring WEP we can't use it for
TKIP, WPA1, OWE, IBSS or when not using nl80211.)

I also should point out that merging the patches will break bissecting
when you use tests. With nl80211 already supporting Extended Key ID the
only "safe" merges would be all three patches as one or add two patches
sabotaging/fixing nl80211 Extended key ID at the beginning/end.

I also made some other improvements:
 - Don't disable Extended key ID when loading the config.

 - I reworked the code handling IE/RSN overloading. The code is now
   checking (hopefully all) overload strings if they allows Extended
   Key ID or not and force enable/disable it accordingly.
   And the handling has been moved to the config parse sections.

- Some cosmetic fixes
  (But I'm sure there are I still got quite some wrong...)

 hostapd/config_file.c  | 51 ++++++++++++++++++++++++++
 hostapd/ctrl_iface.c   |  8 +++++
 hostapd/hostapd.conf   | 12 +++++++
 src/ap/ap_config.c     |  6 ++++
 src/ap/ap_config.h     |  1 +
 src/ap/ieee802_11.c    |  7 ++++
 src/ap/wpa_auth.c      | 81 ++++++++++++++++++++++++++++++++++--------
 src/ap/wpa_auth.h      |  3 ++
 src/ap/wpa_auth_ft.c   | 25 ++++++++++++-
 src/ap/wpa_auth_glue.c | 14 +++++++-
 src/ap/wpa_auth_i.h    |  4 +++
 src/ap/wpa_auth_ie.c   | 59 ++++++++++++++++++++++++++++++
 12 files changed, 255 insertions(+), 16 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 1a5b742b2..63ca2cb9d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2869,6 +2869,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		}
 	} else if (os_strcmp(buf, "wpa") == 0) {
 		bss->wpa = atoi(pos);
+	} else if (os_strcmp(buf, "extended_key_id") == 0) {
+		bss->extended_key_id = atoi(pos);
+		if (bss->extended_key_id < 0 || bss->extended_key_id > 2) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: Invalid wpa_extended_key_id=%d; allowed range 0..2",
+				   line, bss->extended_key_id);
+			return 1;
+		}
 	} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
 		bss->wpa_group_rekey = atoi(pos);
 		bss->wpa_group_rekey_set = 1;
@@ -4154,6 +4162,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 			bss->radio_measurements[0] |=
 				WLAN_RRM_CAPS_NEIGHBOR_REPORT;
 	} else if (os_strcmp(buf, "own_ie_override") == 0) {
+		struct wpa_ie_data data;
 		struct wpabuf *tmp;
 		size_t len = os_strlen(pos) / 2;
 
@@ -4171,20 +4180,62 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 
 		wpabuf_free(bss->own_ie_override);
 		bss->own_ie_override = tmp;
+		if (!wpa_parse_wpa_ie_rsn(wpabuf_head(tmp), wpabuf_len(tmp),
+					  &data) &&
+		    (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST))
+			bss->extended_key_id = 1;
+		else
+			bss->extended_key_id = 0;
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Forced own IE %sables Extended Key ID",
+			   bss->extended_key_id ? "en" : "dis");
 	} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
 		bss->sae_reflection_attack = atoi(pos);
 	} else if (os_strcmp(buf, "sae_commit_override") == 0) {
 		wpabuf_free(bss->sae_commit_override);
 		bss->sae_commit_override = wpabuf_parse_bin(pos);
 	} else if (os_strcmp(buf, "rsne_override_eapol") == 0) {
+		struct wpa_ie_data data;
+
 		wpabuf_free(bss->rsne_override_eapol);
 		bss->rsne_override_eapol = wpabuf_parse_bin(pos);
+
+		if (!wpa_parse_wpa_ie_rsn(wpabuf_head(
+			bss->rsne_override_eapol),
+			wpabuf_len(bss->rsne_override_eapol),
+			&data) &&
+		    (data.capabilities &
+			WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+			bss->extended_key_id = 1;
+			wpa_printf(MSG_DEBUG,
+				   "WPA: rsne_override_eapol enables Extended Key ID");
+		} else {
+			bss->extended_key_id = 0;
+			wpa_printf(MSG_DEBUG,
+				   "WPA: rsne_override_eapol disables Extended Key ID");
+		}
 	} else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) {
 		wpabuf_free(bss->rsnxe_override_eapol);
 		bss->rsnxe_override_eapol = wpabuf_parse_bin(pos);
 	} else if (os_strcmp(buf, "rsne_override_ft") == 0) {
+		struct wpa_ie_data data;
+
 		wpabuf_free(bss->rsne_override_ft);
 		bss->rsne_override_ft = wpabuf_parse_bin(pos);
+
+		if (!wpa_parse_wpa_ie_rsn(wpabuf_head(bss->rsne_override_ft),
+					  wpabuf_len(bss->rsne_override_ft),
+					  &data) &&
+		    (data.capabilities &
+			WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+			bss->extended_key_id = 1;
+			wpa_printf(MSG_DEBUG,
+				   "WPA: rsne_override_ft enables Extended Key ID");
+		} else {
+			bss->extended_key_id = 0;
+			wpa_printf(MSG_DEBUG,
+				   "WPA: rsne_override_ft disables Extended Key ID");
+		}
 	} else if (os_strcmp(buf, "rsnxe_override_ft") == 0) {
 		wpabuf_free(bss->rsnxe_override_ft);
 		bss->rsnxe_override_ft = wpabuf_parse_bin(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 6d2ecbc9c..1a369ed2a 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1295,6 +1295,14 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
 		pos += ret;
 	}
 
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) {
+		ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n",
+				  hapd->conf->extended_key_id);
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+
 	return pos - buf;
 }
 
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index bc5d1a7f6..98e3cb510 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1510,6 +1510,18 @@ own_ip_addr=127.0.0.1
 # wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
 #wpa=2
 
+# "Extended Key ID support for Individually Addressed Frames" according to
+# IEEE 802.11-2016.
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK0 rekeying has. It can only be used when the driver supports it and
+# requires wpa=2 with a CCMP/GCMP cipher.
+#
+# 0 = force off (default)
+# 1 = enable and use Extended Key ID support when possible
+# 2 = identical to 1 but start with Key ID 1 when possible
+#wpa_extended_key_id=0
+
 # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
 # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
 # (8..63 characters) that will be converted to PSK. This conversion uses SSID
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5bf4502b0..07ea4858b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -68,6 +68,12 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
 	bss->wpa_group_rekey = 600;
 	bss->wpa_gmk_rekey = 86400;
+#ifdef CONFIG_TESTING_OPTIONS
+	/* For now only testing is using Extended Key ID by default */
+	bss->extended_key_id = 2;
+#else /* CONFIG_TESTING_OPTIONS */
+	bss->extended_key_id = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
 	bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
 	bss->wpa_group_update_count = 4;
 	bss->wpa_pairwise_update_count = 4;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 0cb10c118..4d14e15d3 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -354,6 +354,7 @@ struct hostapd_bss_config {
 			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
 
 	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+	int extended_key_id;
 	int wpa_key_mgmt;
 	enum mfp_options ieee80211w;
 	int group_mgmt_cipher;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 46cc7fae7..78c5bfc2a 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -3490,6 +3490,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 	}
 #endif /* CONFIG_MBO */
 
+#if defined(CONFIG_FILS)
+	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+	    sta->auth_alg == WLAN_AUTH_FILS_PK)
+		fils_handle_extended_key_id(sta->wpa_sm, wpa_ie, wpa_ie_len);
+#endif /* CONFIG_FILS */
+
 #if defined(CONFIG_FILS) && defined(CONFIG_OCV)
 	if (wpa_auth_uses_ocv(sta->wpa_sm) &&
 	    (sta->auth_alg == WLAN_AUTH_FILS_SK ||
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index ab20705f0..0954018cf 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -781,7 +781,8 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 	if (sm == NULL)
 		return;
 
-	if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+	if (!sm->use_extended_key_id &&
+	    sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
 		wpa_printf(MSG_INFO,
 			   "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
 			   MAC2STR(sm->addr));
@@ -790,6 +791,8 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 		sm->disconnect_reason =
 			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
 	} else {
+		if (sm->use_extended_key_id)
+			sm->keyidx_active ^= 1; /* flip keyID */
 		sm->PTKRequest = TRUE;
 		sm->PTK_valid = 0;
 	}
@@ -1754,6 +1757,11 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
 			     0, KEY_FLAG_PAIRWISE))
 		wpa_printf(MSG_DEBUG,
 			   "RSN: PTK removal from the driver failed");
+	if (sm->wpa_auth->conf.extended_key_id &&
+	    wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL,
+			     0, KEY_FLAG_PAIRWISE))
+		wpa_printf(MSG_DEBUG,
+			   "RSN: PTK ID1 removal from the driver failed");
 	sm->pairwise_set = FALSE;
 	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
 }
@@ -1812,16 +1820,20 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
 			sm->Init = FALSE;
 			sm->AuthenticationRequest = TRUE;
 			break;
-		} else if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+		} else if (!sm->use_extended_key_id &&
+			   sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
 			wpa_printf(MSG_INFO,
 				   "WPA: PTK0 rekey not allowed, disconnect "
 				   MACSTR, MAC2STR(sm->addr));
 			sm->Disconnect = TRUE;
-			/* Try to encourage the STA reconnect */
+			/* Try to encourage the STA to reconnect */
 			sm->disconnect_reason =
 				WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
 			break;
+		} else if (sm->use_extended_key_id) {
+			sm->keyidx_active ^= 1; /* flip keyID */
 		}
+
 		if (sm->GUpdateStationKeys) {
 			/*
 			 * Reauthentication cancels the pending group key
@@ -2796,7 +2808,7 @@ int fils_set_tk(struct wpa_state_machine *sm)
 	klen = wpa_cipher_key_len(sm->pairwise);
 
 	wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
-	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
 			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
 		return -1;
@@ -3097,6 +3109,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 		return;
 	}
 
+	if (handle_extended_key_id(sm, &kde))
+		return;
+
 	sm->pending_1_of_4_timeout = 0;
 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
@@ -3255,12 +3270,12 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
 
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *pos, dummy_gtk[32], hdr[2];
 	size_t gtk_len, kde_len, wpa_ie_len;
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
 	int secure, gtkidx, encr = 0;
-	u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+	u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL, *kde = NULL;
 
 	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
 	sm->TimeoutEvt = FALSE;
@@ -3317,6 +3332,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
 			"sending 3/4 msg of 4-Way Handshake");
 	if (sm->wpa == WPA_VERSION_WPA2) {
+		if (sm->use_extended_key_id && sm->TimeoutCtr == 1 &&
+		    wpa_auth_set_key(sm->wpa_auth, 0,
+				     wpa_cipher_to_alg(sm->pairwise),
+				     sm->addr,
+				     sm->keyidx_active, sm->PTK.tk,
+				     wpa_cipher_key_len(sm->pairwise),
+				     KEY_FLAG_PAIRWISE_RX)) {
+			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+			return;
+		}
+
 		/* WPA2 send GTK in the 4-way handshake */
 		secure = 1;
 		gtk = gsm->GTK[gsm->GN - 1];
@@ -3357,6 +3384,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+	if (sm->use_extended_key_id)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
 	if (gtk)
 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -3392,10 +3423,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 		pos += elen;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
+	hdr[1] = 0;
+
+	if (sm->use_extended_key_id) {
+		hdr[0] = sm->keyidx_active & 0x01;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+	}
+
 	if (gtk) {
-		u8 hdr[2];
 		hdr[0] = gtkidx & 0x03;
-		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gtk_len);
 	}
@@ -3478,9 +3514,17 @@ SM_STATE(WPA_PTK, PTKINITDONE)
 	if (sm->Pair) {
 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
 		int klen = wpa_cipher_key_len(sm->pairwise);
-		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk, klen,
-				     KEY_FLAG_PAIRWISE_RX_TX)) {
+		if (sm->use_extended_key_id) {
+			if (wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+					     sm->keyidx_active, NULL, 0,
+					     KEY_FLAG_PAIRWISE_RX_TX_MODIFY)) {
+				wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+						   WLAN_REASON_PREV_AUTH_NOT_VALID);
+				return;
+			}
+		} else if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+					    sm->PTK.tk, klen,
+					    KEY_FLAG_PAIRWISE_RX_TX)) {
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
@@ -5161,7 +5205,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 		       void (*cb)(void *ctx1, void *ctx2),
 		       void *ctx1, void *ctx2)
 {
-	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, hdr[2];
 	u8 *opos;
 	size_t gtk_len, kde_len;
 	struct wpa_group *gsm = sm->group;
@@ -5219,6 +5263,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
+
+	if (sm->use_extended_key_id)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
 	if (gtk)
 		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -5251,10 +5299,15 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 		pos += elen;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
+	hdr[1] = 0;
+
+	if (sm->use_extended_key_id) {
+		hdr[0] = sm->keyidx_active & 0x01;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+	}
+
 	if (gtk) {
-		u8 hdr[2];
 		hdr[0] = gtkidx & 0x03;
-		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gtk_len);
 	}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 4edeea151..107389f7b 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -169,6 +169,7 @@ struct ft_remote_r1kh {
 
 struct wpa_auth_config {
 	int wpa;
+	int extended_key_id;
 	int wpa_key_mgmt;
 	int wpa_pairwise;
 	int wpa_group;
@@ -474,6 +475,8 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
 		       size_t current_len, size_t max_len,
 		       const struct wpabuf *hlp);
 int fils_set_tk(struct wpa_state_machine *sm);
+void fils_handle_extended_key_id(struct wpa_state_machine *sm,
+				 const u8 *rsn_ie, size_t rsn_ie_len);
 u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *eid,
 				    const u8 *fils_session,
 				    struct wpabuf *fils_hlp_resp);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 1795848e1..293275056 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2738,6 +2738,28 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 }
 
 
+static void ft_handle_extended_key_id(struct wpa_state_machine *sm,
+				      struct wpa_ft_ies *parse)
+{
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+
+	if (conf->extended_key_id && sm->pairwise != WPA_CIPHER_TKIP &&
+	    parse->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)
+		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 can simply
+	 * agree to always use 0.
+	 */
+	sm->keyidx_active = 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "FT: STA " MACSTR " is %susing Extended Key ID",
+		   MAC2STR(sm->addr), sm->use_extended_key_id ? "" : "not ");
+}
+
 void wpa_ft_install_ptk(struct wpa_state_machine *sm)
 {
 	enum wpa_alg alg;
@@ -2766,7 +2788,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
 	 * again after association to get the PTK configured, but that could be
 	 * optimized by adding the STA entry earlier.
 	 */
-	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active,
 			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
 		return;
 
@@ -3128,6 +3150,7 @@ pmk_r1_derived:
 			      pairwise) < 0)
 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
+	ft_handle_extended_key_id(sm, &parse);
 	sm->pairwise = pairwise;
 	sm->PTK_valid = TRUE;
 	sm->tk_already_set = FALSE;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 926ff455f..01b3f494e 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -41,6 +41,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
 
 	os_memset(wconf, 0, sizeof(*wconf));
 	wconf->wpa = conf->wpa;
+	wconf->extended_key_id = conf->extended_key_id;
 	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
 	wconf->wpa_pairwise = conf->wpa_pairwise;
 	wconf->wpa_group = conf->wpa_group;
@@ -433,7 +434,12 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	}
 
 #ifdef CONFIG_TESTING_OPTIONS
-	if (addr && !is_broadcast_ether_addr(addr)) {
+	if (key_flag & KEY_FLAG_MODIFY) {
+		/* We are updating an already installed key.
+		 * Don't overwrite the already stored key
+		 * information with zeros.
+		 */
+	} else if (addr && !is_broadcast_ether_addr(addr)) {
 		struct sta_info *sta;
 
 		sta = ap_get_sta(hapd, addr);
@@ -1419,6 +1425,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 		_conf.wpa_deny_ptk0_rekey = 1;
 	}
 
+	if (_conf.extended_key_id &&
+	    hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "Extended Key ID supported");
+	else
+		_conf.extended_key_id = 0;
+
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
 	if (hapd->wpa_auth == NULL) {
 		wpa_printf(MSG_ERROR, "WPA initialization failed.");
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index c2b22eba1..be9cd70bb 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -61,6 +61,8 @@ struct wpa_state_machine {
 	unsigned int pmk_len;
 	u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */
 	struct wpa_ptk PTK;
+	u8 keyidx_active;
+	Boolean use_extended_key_id;
 	Boolean PTK_valid;
 	Boolean pairwise_set;
 	Boolean tk_already_set;
@@ -287,6 +289,8 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
 int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
 			   int (*cb)(struct wpa_authenticator *a, void *ctx),
 			   void *cb_ctx);
+int handle_extended_key_id(struct wpa_state_machine *sm,
+			   struct wpa_eapol_ie_parse *kde);
 
 #ifdef CONFIG_IEEE80211R_AP
 int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e6d05910..d9fa88d37 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 	if (rsn_testing)
 		capab |= BIT(8) | BIT(15);
 #endif /* CONFIG_RSN_TESTING */
+	if (conf->extended_key_id)
+		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
 	WPA_PUT_LE16(pos, capab);
 	pos += 2;
 
@@ -546,6 +548,63 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
 }
 
 
+int handle_extended_key_id(struct wpa_state_machine *sm,
+			   struct wpa_eapol_ie_parse *kde)
+{
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	struct wpa_ie_data rsn;
+
+	if (conf->extended_key_id && sm->pairwise != 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 (!sm->use_extended_key_id && sm->pairwise_set) {
+			wpa_printf(MSG_ERROR, "STA " MACSTR
+				   " tries to start using Extended Key ID on rekey",
+				   MAC2STR(sm->addr));
+			return -1;
+		} else if (!sm->use_extended_key_id) {
+			sm->use_extended_key_id = TRUE;
+			if (conf->extended_key_id == 2)
+				sm->keyidx_active = 1;
+			else
+				sm->keyidx_active = 0;
+		}
+	} else {
+		if (sm->use_extended_key_id && sm->pairwise_set) {
+			wpa_printf(MSG_ERROR, "STA " MACSTR
+				   " is using Extended Key ID but tries to rekey without it",
+				   MAC2STR(sm->addr));
+			return -1;
+		} else if (!sm->pairwise_set) {
+			sm->use_extended_key_id = FALSE;
+			sm->keyidx_active = 0;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " is %susing Extended Key ID",
+		   MAC2STR(sm->addr), sm->use_extended_key_id ? "" : "not ");
+	return 0;
+}
+
+
+void fils_handle_extended_key_id(struct wpa_state_machine *sm,
+				 const u8 *rsn_ie, size_t rsn_ie_len)
+{
+	struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+	struct wpa_ie_data rsn;
+
+	sm->keyidx_active = 0;
+	if (conf->extended_key_id && sm->pairwise != WPA_CIPHER_TKIP &&
+	    !wpa_parse_wpa_ie_rsn(rsn_ie, 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;
+	wpa_printf(MSG_DEBUG,
+		   "FILS: STA " MACSTR " is %susing Extended Key ID",
+		   MAC2STR(sm->addr), sm->use_extended_key_id ? "":"not ");
+}
+
+
 int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 			struct wpa_state_machine *sm, int freq,
 			const u8 *wpa_ie, size_t wpa_ie_len,
-- 
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