Extended Key ID support based on IEEE 802.11 - 2016 for hostapd. Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx> --- 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(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 42f3b40ef..75e8713e1 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -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; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index f8caa5623..4b50c9f4b 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -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 diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index e640e9984..5828aecfc 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -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; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 509677a45..b6757beb6 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -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; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index d70e2982b..d33925827 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 783ad6007..e646f919a 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 wpa_extended_key_id; int wpa_key_mgmt; int wpa_pairwise; int wpa_group; diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index a977b60f2..567892398 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -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."); diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index 4babd0cbb..b098a84a6 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 8580a5a69..a75d91bd8 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -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) { -- 2.21.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap