[PATCH 4/8] 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.

The standard is not covering how to use it with extensions like FILS or
FT and hostapd sticks to the save settings by default but allows the
user to enable non-standard Extended Key ID support for FT and FILS.

BASIC Extended Key ID support does nothing not clearly covered by the
standard and force it to be off for compatibility when needed.
FT0, FILS0 and FILS_CUSTOM are not standardized extensions to also allow
Extended Key ID support to be used with FT and/or FILS.

When Extended Key ID can be used and the AP is free to chose the keyid
between 0..1 it will use 1 to force potential interoperability issues to
the initial connect and not delay them till the connection is rekeyed.
By also setting PREFER0 (e.g. BASIC+PREFER0) the AP will use prefer the
keyid 0 instead.

Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
---
 hostapd/config_file.c  | 18 +++++++++
 hostapd/ctrl_iface.c   | 16 ++++++++
 hostapd/hostapd.conf   | 38 +++++++++++++++++
 src/ap/ap_config.c     | 25 ++++++++++++
 src/ap/ap_config.h     |  1 +
 src/ap/ieee802_11.c    |  7 ++++
 src/ap/wpa_auth.c      | 92 +++++++++++++++++++++++++++++++++++-------
 src/ap/wpa_auth.h      |  3 ++
 src/ap/wpa_auth_ft.c   | 26 +++++++++++-
 src/ap/wpa_auth_glue.c | 14 ++++++-
 src/ap/wpa_auth_i.h    |  4 ++
 src/ap/wpa_auth_ie.c   | 77 ++++++++++++++++++++++++++++++++++-
 12 files changed, 303 insertions(+), 18 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 98e9fd21b..24dda816d 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -847,6 +847,18 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
 #endif /* CONFIG_WEP */
 
 
+static int hostapd_config_extended_key_id(struct hostapd_bss_config *bss,
+					  const char *value)
+{
+	int val = wpa_parse_extended_key_id(value);
+
+	if (val < 0)
+		return -1;
+	bss->extended_key_id = val;
+	return 0;
+}
+
+
 static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
 {
 	char *pos;
@@ -2869,6 +2881,12 @@ 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) {
+		if (hostapd_config_extended_key_id(bss, pos) < 0) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid extended_key_id setting",
+				   line);
+			return 1;
+		}
 	} 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 6d2ecbc9c..ca0a30889 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1290,6 +1290,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
 	if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) {
 		ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n",
 				  hapd->conf->wpa_deny_ptk0_rekey);
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
+	    hapd->conf->extended_key_id != EXT_KEY_ID_DEFAULT) {
+		ret = os_snprintf(pos, end - pos, "extended_key_id=");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+
+		ret = wpa_write_extended_key_id(pos, end,
+						hapd->conf->extended_key_id);
+		if (ret < 0)
+			return pos - buf;
+		pos += ret;
+
+		ret = os_snprintf(pos, end - pos, "\n");
 		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index bc5d1a7f6..1f77100dd 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1510,6 +1510,44 @@ 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.
+#
+# The standard is not regulating if or how Extended Key ID can be used in
+# combination with FT or FILS. Enabling it for FT or FILS may therefore be
+# incompatible with other implementations.
+#
+# Available options, can be combined with '+':
+# OFF		: Disable Extended Key ID support unconditionally
+# BASIC		: Enable core Extended Key ID support according to
+#		  IEEE 802.11-2016 when the driver supports it
+# PREFER0	: Use key 0 for the initial key when either 0 or 1 can be used
+# 		  (Can delay interoperability issues till the first rekey)
+# FT0		: - NOT PART OF IEEE 802.11-2016 -
+#		  Enable Extended Key ID support for FT and assume keyid 0 for
+#		  all FT handshakes
+# FILS0		: - NOT PART OF IEEE 802.11-2016 -
+#		  Enable Extended Key ID support for FILS and assume keyid 0 for
+#		  all FILS handshakes
+# FILS_CUSTOM	: - NOT PART OF IEEE 802.11-2016 -
+#		  Allow Extended Key ID support for FILS and add the keyid to
+#		  the FILS handshakes
+#
+# Rules:
+# - Either OFF or BASIC must be defined when the setting is used
+# - BASIC can be combined with anything except OFF
+# - FILS0 and FILS_CUSTOM are mutually exclusive
+#
+# Example:
+# extended_key_id=BASIC+FT0+FILS0
+#
+# Default:
+# extended_key_id=BASIC
+
 # 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 0166c3164..996c6251c 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -66,6 +66,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #endif /* CONFIG_WEP */
 	bss->eap_reauth_period = 3600;
 
+	bss->extended_key_id = EXT_KEY_ID_DEFAULT;
 	bss->wpa_group_rekey = 600;
 	bss->wpa_gmk_rekey = 86400;
 	bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS;
@@ -1169,7 +1170,31 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
 		}
 	}
 
+	if (full_config && bss->extended_key_id &&
+	    !(bss->wpa & WPA_PROTO_RSN &&
+	      bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+				   WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256))) {
+		wpa_printf(MSG_INFO,
+			   "Extended Key ID disabled (reason: not using WPA2 and CCMP/GCMP");
+		bss->extended_key_id = 0;
+	}
+#ifdef CONFIG_FILS
+	if (full_config && wpa_key_mgmt_fils(bss->wpa_key_mgmt) &&
+	    !(bss->extended_key_id & EXT_KEY_ID_FILS)) {
+		wpa_printf(MSG_INFO,
+			   "Extended Key ID disabled (reason: FILS enabled)");
+		bss->extended_key_id = 0;
+	}
+#endif /* CONFIG_FILS */
+
 #ifdef CONFIG_IEEE80211R_AP
+	if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    !(bss->extended_key_id & EXT_KEY_ID_FT0)) {
+		wpa_printf(MSG_INFO,
+			   "Extended Key ID disabled (reason: FT enabled)");
+		bss->extended_key_id = 0;
+	}
+
 	if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
 	    (bss->nas_identifier == NULL ||
 	     os_strlen(bss->nas_identifier) < 1 ||
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8b57500ce..62d3ac3d6 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 */
+	enum ext_key_id_support 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 7937b8120..595fe8950 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..281ac789f 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
@@ -2725,6 +2737,16 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
 	wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
 	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
 			    wpabuf_put(plain, WPA_KEY_RSC_LEN));
+
+	hdr[1] = 0;
+	if (sm->use_extended_key_id &&
+	    sm->wpa_auth->conf.extended_key_id & EXT_KEY_ID_FILS_CUSTOM) {
+		hdr[0] = sm->keyidx_active & 0x01;
+		tmp = wpabuf_put(plain, 0);
+		tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+		wpabuf_put(plain, tmp2 - tmp);
+	}
+
 	/* GTK KDE */
 	gtk = gsm->GTK[gsm->GN - 1];
 	gtk_len = gsm->GTK_len;
@@ -2741,7 +2763,6 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
 		gtk = dummy_gtk;
 	}
 	hdr[0] = gsm->GN & 0x03;
-	hdr[1] = 0;
 	tmp = wpabuf_put(plain, 0);
 	tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 			   gtk, gtk_len);
@@ -2796,7 +2817,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 +3118,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 +3279,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 +3341,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 +3393,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 +3432,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 +3523,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 +5214,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 +5272,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 +5308,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 d1324d501..41eafa3d9 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;
+	enum ext_key_id_support extended_key_id;
 	int wpa_key_mgmt;
 	int wpa_pairwise;
 	int wpa_group;
@@ -468,6 +469,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 c0b462558..8dd300ab4 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2703,6 +2703,29 @@ 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. This is not standardized and only done
+	 * when the user activated "FT0" for extended_key_id.
+	 */
+	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;
@@ -2731,7 +2754,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;
 
@@ -3093,6 +3116,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 ff2302cd2..eaa5de1da 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;
@@ -415,7 +416,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);
@@ -1401,6 +1407,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..21c8a9fb8 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;
 
@@ -447,8 +449,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 {
 	u8 *pos, buf[128];
 	int res;
-
 #ifdef CONFIG_TESTING_OPTIONS
+	struct wpa_ie_data data;
+
 	if (wpa_auth->conf.own_ie_override_len) {
 		wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
 			    wpa_auth->conf.own_ie_override,
@@ -461,6 +464,14 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 		os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
 			  wpa_auth->conf.own_ie_override_len);
 		wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
+		if (wpa_parse_wpa_ie_rsn(wpa_auth->wpa_ie,
+					 wpa_auth->wpa_ie_len, &data) ||
+		    !(data.capabilities &
+		       WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+			wpa_printf(MSG_DEBUG,
+				   "WPA: Forced own IE disables Extended Key ID");
+			wpa_auth->conf.extended_key_id = 0;
+		}
 		return 0;
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
@@ -546,6 +557,70 @@ 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 & EXT_KEY_ID_PREFER0)
+				sm->keyidx_active = 0;
+			else
+				sm->keyidx_active = 1;
+		}
+	} 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;
+
+	if (conf->extended_key_id & EXT_KEY_ID_FILS &&
+	    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;
+		if (conf->extended_key_id & EXT_KEY_ID_FILS_CUSTOM &&
+		    !(conf->extended_key_id & EXT_KEY_ID_PREFER0))
+			sm->keyidx_active = 1;
+		else
+			sm->keyidx_active = 0;
+	} else {
+		sm->use_extended_key_id = 0;
+		sm->keyidx_active = 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.1


_______________________________________________
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