]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SAE: Fix EAPOL-Key integrity and key-wrap algorithm selection
authorJouni Malinen <jouni@codeaurora.org>
Fri, 16 Mar 2018 11:04:15 +0000 (13:04 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 16 Mar 2018 11:36:42 +0000 (13:36 +0200)
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>
src/ap/wpa_auth.c
src/common/wpa_common.c
src/common/wpa_common.h
src/rsn_supp/wpa.c

index f3d1bbdc487bcc053766354cd5f2b51391c87575..203329eeb2e55951bbcc6e3dc0fd059c0675d349 100644 (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)",
index 853594ad9b716bd3278a823bc76d108cbe6d38b6..13ae42272d954aacaae24a349367d83929425505 100644 (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,
index 3b8c1fb931a2f1f9f1c9cc7244bfeb010ef2ae3e..5c918a4e626669112156e520f0f9202328c507bd 100644 (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 */
index 07fad4517f5bdd706dd81d7da7ccc04e9668c2de..ea54f327ec82e6e93b52ad20f2cba25352221274 100644 (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 "