@@ -2790,6 +2790,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->wpa_strict_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
bss->wpa_gmk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_ext_key_id") == 0) {
+ bss->wpa_ext_key_id = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
@@ -1342,8 +1342,17 @@ own_ip_addr=127.0.0.1
# (in seconds).
#wpa_gmk_rekey=86400
+# Control Extended Key ID support from IEEE802.11-2016.
+# 0 = force off
+# 1 = use Extended Key ID for PTK keys when supported by driver (Default)
+# When supported this will use KeyID 0 and 1 for PTK keys and shift GTK
+# keys to 2 and 3.
+#wpa_ext_key_id=1
+
# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
# PTK to mitigate some attacks against TKIP deficiencies.
+# WARNING: PTK rekeys without also using Extended Key ID is broken in many
+# implementations. (Linux versions before 4.20 are known to be problematic.)
#wpa_ptk_rekey=600
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
@@ -62,6 +62,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
bss->wpa_group_update_count = 4;
+ bss->wpa_ext_key_id = 1;
bss->wpa_pairwise_update_count = 4;
bss->wpa_disable_eapol_key_retries =
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
@@ -347,6 +347,7 @@ struct hostapd_bss_config {
int wpa_group_rekey_set;
int wpa_strict_rekey;
int wpa_gmk_rekey;
+ int wpa_ext_key_id;
int wpa_ptk_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
@@ -658,14 +658,14 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
+ int key_idx, int key_flag,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
- key_idx, set_tx, seq, seq_len, key,
+ key_idx, key_flag, seq, seq_len, key,
key_len);
}
@@ -133,12 +133,12 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len, int key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -711,6 +711,9 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
if (sm == NULL)
return;
+ if (sm->Ext_Key_ID)
+ sm->keyidx_active ^= 1; /* flip keyID */
+
sm->PTKRequest = TRUE;
sm->PTK_valid = 0;
}
@@ -1637,7 +1640,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
sm->PTK_valid = FALSE;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
- 0))
+ 0, 0))
wpa_printf(MSG_DEBUG,
"RSN: PTK removal from the driver failed");
sm->pairwise_set = FALSE;
@@ -2582,7 +2585,7 @@ int fils_set_tk(struct wpa_state_machine *sm)
wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen)) {
+ sm->PTK.tk, klen, 0)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
@@ -2885,11 +2888,11 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
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;
@@ -2926,6 +2929,19 @@ 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->Ext_Key_ID && sm->TimeoutCtr == 1) {
+ if (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_RX_ONLY)) {
+ 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];
@@ -2940,7 +2956,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
return;
gtk = dummy_gtk;
}
- keyidx = gsm->GN;
+ gtkidx = gsm->GN;
_rsc = rsc;
encr = 1;
} else {
@@ -2948,7 +2964,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
secure = 0;
gtk = NULL;
gtk_len = 0;
- keyidx = 0;
_rsc = NULL;
if (sm->rx_eapol_key_secure) {
/*
@@ -2967,6 +2982,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
}
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+
+ if (sm->Ext_Key_ID)
+ kde_len += 2 + RSN_SELECTOR_LEN + 2;
+
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3003,10 +3022,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
pos += elen;
}
#endif /* CONFIG_IEEE80211R_AP */
+ hdr[1] = 0;
+
+ if (sm->Ext_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);
}
@@ -3073,7 +3097,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);
}
@@ -3085,11 +3109,22 @@ 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)) {
- wpa_sta_disconnect(sm->wpa_auth, sm->addr,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ if (sm->Ext_Key_ID) {
+ if (wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr,
+ sm->keyidx_active, NULL, 0,
+ KEY_FLAG_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,
+ sm->keyidx_active, sm->PTK.tk,
+ klen, 0)) {
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
}
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = TRUE;
@@ -3457,8 +3492,13 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
/* GTK[0..N] = 0 */
os_memset(group->GTK, 0, sizeof(group->GTK));
- group->GN = 1;
- group->GM = 2;
+ if (wpa_auth->conf.wpa_ext_key_id) {
+ group->GN = 2;
+ group->GM = 3;
+ } else {
+ group->GN = 1;
+ group->GM = 2;
+ }
#ifdef CONFIG_IEEE80211W
group->GN_igtk = 4;
group->GM_igtk = 5;
@@ -3627,7 +3667,8 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
broadcast_ether_addr, group->GN,
- group->GTK[group->GN - 1], group->GTK_len) < 0)
+ group->GTK[group->GN - 1], group->GTK_len,
+ KEY_FLAG_DEFAULT_KEY) < 0)
ret = -1;
#ifdef CONFIG_IEEE80211W
@@ -3641,7 +3682,8 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
if (ret == 0 &&
wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
broadcast_ether_addr, group->GN_igtk,
- group->IGTK[group->GN_igtk - 4], len) < 0)
+ group->IGTK[group->GN_igtk - 4], len,
+ KEY_FLAG_DEFAULT_KEY) < 0)
ret = -1;
}
#endif /* CONFIG_IEEE80211W */
@@ -174,6 +174,7 @@ struct wpa_auth_config {
int wpa_group_rekey;
int wpa_strict_rekey;
int wpa_gmk_rekey;
+ int wpa_ext_key_id;
int wpa_ptk_rekey;
u32 wpa_group_update_count;
u32 wpa_pairwise_update_count;
@@ -252,8 +253,8 @@ struct wpa_auth_callbacks {
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *p2p_dev_addr,
const u8 *prev_psk, size_t *psk_len);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
- int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
- const u8 *addr, int idx, u8 *key, size_t key_len);
+ int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, const u8 *addr,
+ int idx, u8 *key, size_t key_len, int key_flag);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
@@ -2504,12 +2504,12 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
int vlan_id,
enum wpa_alg alg, const u8 *addr, int idx,
- u8 *key, size_t key_len)
+ u8 *key, size_t key_len, int key_flag)
{
if (wpa_auth->cb->set_key == NULL)
return -1;
return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ key, key_len, key_flag);
}
@@ -2542,7 +2542,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
* optimized by adding the STA entry earlier.
*/
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk, klen))
+ sm->PTK.tk, klen, 0))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -44,6 +44,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->wpa_group_rekey = conf->wpa_group_rekey;
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
+ wconf->wpa_ext_key_id = conf->wpa_ext_key_id;
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
wconf->wpa_group_update_count = conf->wpa_group_update_count;
wconf->wpa_disable_eapol_key_retries =
@@ -342,7 +343,7 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
- size_t key_len)
+ size_t key_len, int key_flag)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
@@ -384,7 +385,7 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, key_flag, NULL, 0,
key, key_len);
}
@@ -1211,6 +1212,14 @@ 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_ext_key_id &&
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) {
+ wpa_printf(MSG_INFO, "Extended Key ID disabled, not "
+ "supported by driver.");
+ _conf.wpa_ext_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.");
@@ -60,6 +60,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 Ext_Key_ID;
Boolean PTK_valid;
Boolean pairwise_set;
Boolean tk_already_set;
@@ -280,6 +280,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
/* RSN Capabilities */
capab = 0;
+ if (conf->wpa_ext_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
if (conf->rsn_preauth)
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->wmm_enabled) {
@@ -773,6 +775,11 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
#endif /* CONFIG_IEEE80211W */
+ /* Enable Extended Key ID if possible */
+ if (wpa_auth->conf.wpa_ext_key_id &&
+ data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)
+ sm->Ext_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) {