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

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

 



On Fri, Mar 20, 2020 at 08:04:31PM +0100, Alexander Wetzel wrote:
> 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.

> This should have all the changes you requested.

Thanks!

> 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.)

I'm not sure I see the point of this checking since the use of Extended
Key ID is negotiated for the full association when (Re)Association
Request/Response frames are exchanged. Neither the AP nor the station
can change any of the items negotiated in RSNE during the association.

> 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...)

It is useful to run a semi-manual check of test cases working with the
new functionality forced to be enabled, but I don't think this should be
done for the testing in general. In other words, I want all the existing
test cases to continue working as they do today, i.e., without using
Extended Key ID. New test cases would be added to verify the new
functionality.

> 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...

I'd expect the testing default to be Extended Key ID disabled, i.e., any
test case that enabling this will need to make sure it gets disabled in
wpa_supplicant at the end (try: enable / finally: disable)

> 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.)

That's good to know.

> 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.

This should not be an issue with the approach I described above. None of
the existing test case behavior should change with the patches 1/3 and
2/3 applied.

>  - 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.

I'm not convinced that this should be done. Or well, at least it should
not be part of the main commit introducing this functionality into
hostapd.

> diff --git a/hostapd/config_file.c b/hostapd/config_file.c
>  	} else if (os_strcmp(buf, "own_ie_override") == 0) {
> +		struct wpa_ie_data data;

> +		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");

So I'm dropping these for now..

> diff --git 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)
> +#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 */

And dropping this as well. CONFIG_TESTING_OPTIONS build should not
change default behavior in this manner.

> diff --git 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,
> +#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 */

This does not feel correct to me. All cases including FILS, FT, and
others should determine whether Extended Key ID is used at the time of
association. The only AKM-specific detail here should be in checking
whether to use the special extended_key_id=2 behavior (i.e., disable
that for FT and FILS).

> diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
> @@ -3097,6 +3109,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
> +	if (handle_extended_key_id(sm, &kde))
> +		return;

This does not belong here -- it is not acceptable to modify negotiated
RSN parameters during an association (i.e., PTK rekeying cannot change
what was negotiated in association exchange). The AP is actually
checking that the RSNE in EAPOL-Key msg 2/4 is identical to the one in
(Re)Association Request frame.

> diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
> +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 ");
> +}

This is unnecessarily complex. Generic handling for all associations
should be sufficient.

> diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
> @@ -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;

This looks unnecessarily complex. This cannot really happen since RSNE
cannot be changed during PTK rekeying. All this can be replaced with the
generic association handling of RSNE just like other RSN parameter
negotiation items.

> +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 ");
> +}

Same for this.


I have not yet tested this (well, other than confirming it does not
cause regressions for existing functionality), but I'm considering
following simplified version of the patch:

 From: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
 Subject: [PATCH] AP: Support Extended Key ID

Support Extended Key ID in hostapd according to IEEE Std 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>
---
 hostapd/config_file.c  | 10 ++++++
 hostapd/ctrl_iface.c   |  8 +++++
 hostapd/hostapd.conf   | 11 +++++++
 src/ap/ap_config.h     |  1 +
 src/ap/wpa_auth.c      | 75 ++++++++++++++++++++++++++++++++++++------
 src/ap/wpa_auth.h      |  1 +
 src/ap/wpa_auth_ft.c   |  2 +-
 src/ap/wpa_auth_glue.c | 14 +++++++-
 src/ap/wpa_auth_i.h    |  2 ++
 src/ap/wpa_auth_ie.c   | 20 +++++++++++
 10 files changed, 132 insertions(+), 12 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 3c7bb395f9bd..73d86baa59e8 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2869,6 +2869,16 @@ 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) {
+		int val = 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;
+		}
+		bss->extended_key_id = val;
 	} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
 		bss->wpa_group_rekey = atoi(pos);
 		bss->wpa_group_rekey_set = 1;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 6d2ecbc9c275..1a369ed2aeda 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 bc5d1a7f697d..17f7a9cfd156 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1510,6 +1510,17 @@ 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
+#
+# Extended Key ID allows to rekey PTK keys without the impacts the "normal"
+# PTK rekeying with only a single Key ID 0 has. It can only be used when the
+# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher.
+#
+# 0 = force off, i.e., use only Key ID 0 (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.h b/src/ap/ap_config.h
index 80be7ed39087..5f4665c07c8e 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/wpa_auth.c b/src/ap/wpa_auth.c
index 64fc09ca66d0..717f41b08d01 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 Key ID */
 		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 && sm->use_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 Key ID 1 removal from the driver failed");
 	sm->pairwise_set = FALSE;
 	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
 }
@@ -1812,16 +1820,23 @@ 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) {
+		}
+
+		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;
 		}
+
+		if (sm->use_extended_key_id)
+			sm->keyidx_active ^= 1; /* flip Key ID */
+
 		if (sm->GUpdateStationKeys) {
 			/*
 			 * Reauthentication cancels the pending group key
@@ -3261,6 +3276,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 	u8 *wpa_ie;
 	int secure, gtkidx, encr = 0;
 	u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
+	u8 hdr[2];
 
 	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
 	sm->TimeoutEvt = FALSE;
@@ -3317,6 +3333,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 +3385,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 +3424,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 +3515,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)) {
+		int res;
+
+		if (sm->use_extended_key_id)
+			res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+					       sm->keyidx_active, NULL, 0,
+					       KEY_FLAG_PAIRWISE_RX_TX_MODIFY);
+		else
+			res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr,
+					       0, sm->PTK.tk, klen,
+					       KEY_FLAG_PAIRWISE_RX_TX);
+		if (res) {
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
@@ -5167,6 +5212,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
 	int wpa_ie_len, secure, gtkidx, encr = 0;
+	u8 hdr[2];
 
 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
 	   GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
@@ -5219,6 +5265,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 +5301,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 58aa9ff2142e..528516195c4c 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;
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 5ed78e6a6fa4..476a2be698d7 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2775,7 +2775,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;
 
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 926ff455f104..c7503b1ff852 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_DEBUG, "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 5d7b96c6f194..4d8368d327bd 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;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 2e6d05910409..4b71d1711813 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;
 
@@ -553,6 +555,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 			const u8 *mdie, size_t mdie_len,
 			const u8 *owe_dh, size_t owe_dh_len)
 {
+	struct wpa_auth_config *conf = &wpa_auth->conf;
 	struct wpa_ie_data data;
 	int ciphers, key_mgmt, res, version;
 	u32 selector;
@@ -944,6 +947,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 	}
 #endif /* CONFIG_DPP */
 
+	if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
+	    sm->pairwise != WPA_CIPHER_TKIP &&
+	    data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) {
+		sm->use_extended_key_id = 1;
+		if (conf->extended_key_id == 2 &&
+		    !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+		    !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
+			sm->keyidx_active = 1;
+		else
+			sm->keyidx_active = 0;
+		wpa_printf(MSG_DEBUG,
+			   "RSN: Extended Key ID supported (start with %d)",
+			   sm->keyidx_active);
+	} else {
+		sm->use_extended_key_id = 0;
+	}
+
 	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
 		os_free(sm->wpa_ie);
 		sm->wpa_ie = os_malloc(wpa_ie_len);
-- 
2.20.1

 
-- 
Jouni Malinen                                            PGP id EFC895FA

_______________________________________________
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