From: Alexander Wetzel <alexander@xxxxxxxxxxxxxx> Experimental support for Extended Key ID for APs. Tested for basic functionality and backward compatibility but still WIP. Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx> --- hostapd/config_file.c | 2 + hostapd/hostapd.conf | 9 +++++ src/ap/ap_config.c | 1 + src/ap/ap_config.h | 1 + src/ap/ap_drv_ops.c | 4 +- src/ap/wpa_auth.c | 84 +++++++++++++++++++++++++++++++----------- src/ap/wpa_auth.h | 5 ++- src/ap/wpa_auth_ft.c | 6 +-- src/ap/wpa_auth_glue.c | 13 ++++++- src/ap/wpa_auth_i.h | 2 + src/ap/wpa_auth_ie.c | 7 ++++ 11 files changed, 104 insertions(+), 30 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index b26da71a8..2e164e1d0 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -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) { diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index a00521711..4ae7a4617 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -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 diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index f9b6f2959..f37ec6f1a 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -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; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 778366d49..61db24a04 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -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; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 067cf863e..ff8124cc7 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -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); } diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 34969e79e..9f63bd424 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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 */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index fad5536f7..e60a7da57 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -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); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index e8d46ab0d..f4c220935 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -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) */ diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 812740301..99107d292 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -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."); diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index b1cea1b49..2df37a4e2 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -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; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 253fe6e10..21efdc5f4 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -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) { -- 2.19.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap