@@ -2849,6 +2849,8 @@ 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, "wpa_extended_key_id") == 0) {
+ bss->wpa_extended_key_id = atoi(pos);
} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
bss->wpa_group_rekey = atoi(pos);
bss->wpa_group_rekey_set = 1;
@@ -1356,6 +1356,16 @@ 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 based on IEEE 802.11-2016
+#
+# Extended Key ID allows to rekey the PTK key without impact for ongoing
+# transmissions
+# When enabled and supported by the driver the AP will offer and support it for
+# stations. (The setting is only relevant with wpa=2)
+# 0 = force off
+# 1 = enable Extended Key ID support when driver supports it (Default)
+#wpa_extended_key_id=1
+
# 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
@@ -59,6 +59,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->broadcast_key_idx_max = 2;
bss->eap_reauth_period = 3600;
+ bss->wpa_extended_key_id = 1;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
bss->wpa_group_update_count = 4;
@@ -332,6 +332,7 @@ struct hostapd_bss_config {
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+ int wpa_extended_key_id;
int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
@@ -754,6 +754,9 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
if (sm == NULL)
return;
+ if (sm->use_extended_key_id)
+ sm->keyidx_active ^= 1; /* flip keyID */
+
sm->PTKRequest = TRUE;
sm->PTK_valid = 0;
}
@@ -3137,11 +3140,11 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32], hdr[2];
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
- int wpa_ie_len, secure, keyidx, encr = 0;
+ int wpa_ie_len, secure, gtkidx, encr = 0;
SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
sm->TimeoutEvt = FALSE;
@@ -3178,6 +3181,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_NO_AUTO_TX)) {
+ 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];
@@ -3192,7 +3207,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
return;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -3200,7 +3215,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -3219,6 +3233,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
@@ -3255,10 +3273,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 & 0x03;
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0);
+ }
+
if (gtk) {
- u8 hdr[2];
- hdr[0] = keyidx & 0x03;
- hdr[1] = 0;
+ hdr[0] = gtkidx & 0x03;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gtk_len);
}
@@ -3329,7 +3352,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
- _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+ _rsc, sm->ANonce, kde, pos - kde, 0, encr);
os_free(kde);
}
@@ -3341,8 +3364,16 @@ 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, 0)) {
+ 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_SET_TX)) {
+ 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, 0)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
@@ -169,6 +169,7 @@ struct ft_remote_r1kh {
struct wpa_auth_config {
int wpa;
+ int wpa_extended_key_id;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
@@ -39,6 +39,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
{
os_memset(wconf, 0, sizeof(*wconf));
wconf->wpa = conf->wpa;
+ wconf->wpa_extended_key_id = conf->wpa_extended_key_id;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
@@ -1301,6 +1302,16 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
+
+ if (_conf.wpa_extended_key_id) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) {
+ wpa_printf(MSG_INFO, "Support Extended Key ID");
+ } else {
+ wpa_printf(MSG_INFO, "Extended Key ID not supported");
+ _conf.wpa_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.");
@@ -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;
@@ -280,6 +280,9 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
/* RSN Capabilities */
capab = 0;
+ if (conf->wpa_extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
if (conf->rsn_preauth)
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->wmm_enabled) {
@@ -809,6 +812,10 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_IEEE80211W */
+ if (wpa_auth->conf.wpa_extended_key_id &&
+ data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)
+ sm->use_extended_key_id = TRUE;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
Extended Key ID support based on IEEE 802.11 - 2016 for hostapd. Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de> --- Differences compared to v1: - Fixed a typo in the commit message pointed out by Johannes. - Reworded the commit log a bit. hostapd/config_file.c | 2 ++ hostapd/hostapd.conf | 10 +++++++++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 1 + src/ap/wpa_auth.c | 51 +++++++++++++++++++++++++++++++++--------- src/ap/wpa_auth.h | 1 + src/ap/wpa_auth_glue.c | 11 +++++++++ src/ap/wpa_auth_i.h | 2 ++ src/ap/wpa_auth_ie.c | 7 ++++++ 9 files changed, 76 insertions(+), 10 deletions(-)