SAE: Fix EAPOL-Key integrity and key-wrap algorithm selection

The SAE AKM 00-0F-AC:8 is supposed to use EAPOL-Key Key Descriptor
Version 0 (AKM-defined) with AES-128-CMAC and NIST AES Key Wrap.
However, the previous implementation ended up using Key Descriptor
Version 2 (HMAC-SHA-1-128 and NIST AES Key Wrap). Fix this by using the
appropriate Key Descriptor Version and integrity algorithm. Use helper
functions to keep the selection clearer and more consistent between
wpa_supplicant and hostapd uses.

Note: This change is not backwards compatible. Both the AP and station
side implementations will need to be updated at the same time to
maintain functionality.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2018-03-16 13:04:15 +02:00 committed by Jouni Malinen
parent c63e69c379
commit 4bc801ab42
4 changed files with 82 additions and 76 deletions

View File

@ -238,23 +238,6 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
}
static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
{
int ret = 0;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
ret = 1;
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
ret = 1;
#endif /* CONFIG_IEEE80211W */
if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
ret = 1;
return ret;
}
static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
@ -1010,10 +993,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (sm->pairwise == WPA_CIPHER_CCMP ||
sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
!wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
if (wpa_use_cmac(sm->wpa_key_mgmt) &&
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@ -1023,11 +1004,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
return;
}
if (!wpa_use_aes_cmac(sm) &&
!wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OWE &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_DPP &&
if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@ -1037,10 +1015,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
}
}
if ((wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
wpa_key_mgmt_fils(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE) &&
if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
@ -1401,13 +1376,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (force_version)
version = force_version;
else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
wpa_key_mgmt_fils(sm->wpa_key_mgmt))
else if (wpa_use_akm_defined(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
else if (wpa_use_cmac(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@ -1429,10 +1400,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_data_len = kde_len;
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@ -1531,10 +1499,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
wpa_use_aes_key_wrap(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_printf(MSG_DEBUG,
"WPA: Encrypt Key Data using AES-WRAP (KEK length %u)",

View File

@ -81,6 +81,60 @@ unsigned int wpa_mic_len(int akmp, size_t pmk_len)
}
/**
* wpa_use_akm_defined - Is AKM-defined Key Descriptor Version used
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: 1 if AKM-defined Key Descriptor Version is used; 0 otherwise
*/
int wpa_use_akm_defined(int akmp)
{
return akmp == WPA_KEY_MGMT_OSEN ||
akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_sae(akmp) ||
wpa_key_mgmt_suite_b(akmp) ||
wpa_key_mgmt_fils(akmp);
}
/**
* wpa_use_cmac - Is CMAC integrity algorithm used for EAPOL-Key MIC
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: 1 if CMAC is used; 0 otherwise
*/
int wpa_use_cmac(int akmp)
{
return akmp == WPA_KEY_MGMT_OSEN ||
akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_ft(akmp) ||
wpa_key_mgmt_sha256(akmp) ||
wpa_key_mgmt_sae(akmp) ||
wpa_key_mgmt_suite_b(akmp);
}
/**
* wpa_use_aes_key_wrap - Is AES Keywrap algorithm used for EAPOL-Key Key Data
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: 1 if AES Keywrap is used; 0 otherwise
*
* Note: AKM 00-0F-AC:1 and 00-0F-AC:2 have special rules for selecting whether
* to use AES Keywrap based on the negotiated pairwise cipher. This function
* does not cover those special cases.
*/
int wpa_use_aes_key_wrap(int akmp)
{
return akmp == WPA_KEY_MGMT_OSEN ||
akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_ft(akmp) ||
wpa_key_mgmt_sha256(akmp) ||
wpa_key_mgmt_sae(akmp) ||
wpa_key_mgmt_suite_b(akmp);
}
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
@ -131,6 +185,13 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
switch (akmp) {
#ifdef CONFIG_SAE
case WPA_KEY_MGMT_SAE:
case WPA_KEY_MGMT_FT_SAE:
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
case WPA_KEY_MGMT_OSEN:
wpa_printf(MSG_DEBUG,

View File

@ -461,6 +461,9 @@ int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
unsigned int wpa_mic_len(int akmp, size_t pmk_len);
int wpa_use_akm_defined(int akmp);
int wpa_use_cmac(int akmp);
int wpa_use_aes_key_wrap(int akmp);
int fils_domain_name_hash(const char *domain, u8 *hash);
#endif /* WPA_COMMON_H */

View File

@ -181,8 +181,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->key_mgmt))
if (wpa_use_akm_defined(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
wpa_key_mgmt_sha256(sm->key_mgmt))
@ -1814,10 +1813,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
sm->key_mgmt == WPA_KEY_MGMT_OWE ||
sm->key_mgmt == WPA_KEY_MGMT_DPP ||
sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_use_aes_key_wrap(sm->key_mgmt)) {
u8 *buf;
wpa_printf(MSG_DEBUG,
@ -2094,29 +2090,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_fils(sm->key_mgmt) &&
sm->key_mgmt != WPA_KEY_MGMT_OWE &&
sm->key_mgmt != WPA_KEY_MGMT_DPP &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"OSEN: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
if ((wpa_key_mgmt_suite_b(sm->key_mgmt) ||
wpa_key_mgmt_fils(sm->key_mgmt) ||
sm->key_mgmt == WPA_KEY_MGMT_DPP ||
sm->key_mgmt == WPA_KEY_MGMT_OWE) &&
if (wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@ -2127,7 +2108,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"FT: AP did not use AES-128-CMAC");
goto out;
@ -2137,9 +2119,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
!wpa_key_mgmt_fils(sm->key_mgmt) &&
!wpa_key_mgmt_suite_b(sm->key_mgmt)) {
!wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@ -2148,10 +2128,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_fils(sm->key_mgmt) &&
sm->key_mgmt != WPA_KEY_MGMT_OWE &&
sm->key_mgmt != WPA_KEY_MGMT_DPP &&
!wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@ -2171,7 +2148,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
goto out;
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "