]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RSN: Split WPA(v1) processing of EAPOL-Key frames into a separate function
authorJouni Malinen <j@w1.fi>
Sun, 27 Nov 2022 06:30:58 +0000 (08:30 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 27 Nov 2022 06:30:58 +0000 (08:30 +0200)
This is a step in separating RSN and WPA(v1) processing of EAPOL-Key
frames into separate functions. This allows the implementation to be
simplified and potentially allows the validation rules to be made
stricter more easily. This is also a step towards allowing WPA(v1)
functionality to be removed from the build in the future.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/rsn_supp/wpa.c
tests/hwsim/test_ap_psk.py

index 5e4c60891d7cdf5e269bd13e8a4a689824857b96..e3a64f171b6850d44769eb18a4854b296c608325 100644 (file)
@@ -3251,6 +3251,87 @@ static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
 #endif /* CONFIG_FILS */
 
 
+static int wpa_sm_rx_eapol_wpa(struct wpa_sm *sm, const u8 *src_addr,
+                              struct wpa_eapol_key *key,
+                              enum frame_encryption encrypted,
+                              const u8 *tmp, size_t data_len,
+                              u8 *key_data, size_t key_data_len)
+{
+       u16 key_info, ver;
+
+       key_info = WPA_GET_BE16(key->key_info);
+
+       if (key->type != EAPOL_KEY_TYPE_WPA) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Unsupported EAPOL-Key type %d", key->type);
+               return -1;
+       }
+
+       ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+       if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+           ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Unsupported EAPOL-Key descriptor version %d",
+                       ver);
+               return -1;
+       }
+
+       if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+                  ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: CCMP is used, but EAPOL-Key descriptor version (%d) is not 2",
+                       ver);
+               if (sm->group_cipher != WPA_CIPHER_CCMP &&
+                   !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+                       /* Earlier versions of IEEE 802.11i did not explicitly
+                        * require version 2 descriptor for all EAPOL-Key
+                        * packets, so allow group keys to use version 1 if
+                        * CCMP is not used for them. */
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: Backwards compatibility: allow invalid version for non-CCMP group keys");
+               } else
+                       return -1;
+       }
+
+       if ((key_info & WPA_KEY_INFO_MIC) &&
+           wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+               return -1;
+
+       if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+               if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Ignored EAPOL-Key (Pairwise) with non-zero key index");
+                       return -1;
+               }
+               if (key_info & (WPA_KEY_INFO_MIC |
+                               WPA_KEY_INFO_ENCR_KEY_DATA)) {
+                       /* 3/4 4-Way Handshake */
+                       wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+                                                     key_data_len);
+               } else {
+                       /* 1/4 4-Way Handshake */
+                       wpa_supplicant_process_1_of_4(sm, src_addr, key,
+                                                     ver, key_data,
+                                                     key_data_len,
+                                                     encrypted);
+               }
+       } else {
+               if (key_info & WPA_KEY_INFO_MIC) {
+                       /* 1/2 Group Key Handshake */
+                       wpa_supplicant_process_1_of_2(sm, src_addr, key,
+                                                     key_data,
+                                                     key_data_len,
+                                                     ver);
+               } else {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: EAPOL-Key (Group) without Mic/Encr bit - dropped");
+               }
+       }
+
+       return 1;
+}
+
+
 /**
  * wpa_sm_rx_eapol - Process received WPA EAPOL frames
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -3362,19 +3443,77 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                goto out;
        }
 
+       if (sm->rx_replay_counter_set &&
+           os_memcmp(key->replay_counter, sm->rx_replay_counter,
+                     WPA_REPLAY_COUNTER_LEN) <= 0) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: EAPOL-Key Replay Counter did not increase - dropping packet");
+               goto out;
+       }
+
        eapol_sm_notify_lower_layer_success(sm->eapol, 0);
+
        key_info = WPA_GET_BE16(key->key_info);
+
+       if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Unsupported SMK bit in key_info");
+               goto out;
+       }
+
+       if (!(key_info & WPA_KEY_INFO_ACK)) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: No Ack bit in key_info");
+               goto out;
+       }
+
+       if (key_info & WPA_KEY_INFO_REQUEST) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: EAPOL-Key with Request bit - dropped");
+               goto out;
+       }
+
+       if (sm->proto == WPA_PROTO_WPA) {
+               ret = wpa_sm_rx_eapol_wpa(sm, src_addr, key, encrypted,
+                                         tmp, data_len,
+                                         key_data, key_data_len);
+               goto out;
+       }
+
+       if (key->type != EAPOL_KEY_TYPE_RSN) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: Unsupported EAPOL-Key type %d", key->type);
+               goto out;
+       }
+
        ver = key_info & WPA_KEY_INFO_TYPE_MASK;
        if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
            ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
            ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
            !wpa_use_akm_defined(sm->key_mgmt)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "WPA: Unsupported EAPOL-Key descriptor version %d",
+                       "RSN: Unsupported EAPOL-Key descriptor version %d",
+                       ver);
+               goto out;
+       }
+
+       if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+           sm->pairwise_cipher != WPA_CIPHER_TKIP) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: EAPOL-Key descriptor version %d not allowed without TKIP as the pairwise cipher",
                        ver);
                goto out;
        }
 
+       if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+           (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+            sm->key_mgmt != WPA_KEY_MGMT_PSK)) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: EAPOL-Key descriptor version %d not allowed due to negotiated AKM (0x%x)",
+                       ver, sm->key_mgmt);
+               goto out;
+       }
+
        if (wpa_use_akm_defined(sm->key_mgmt) &&
            ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -3398,63 +3537,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
                    !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");
+                               "RSN: AP did not use the negotiated AES-128-CMAC");
                        goto out;
                }
        } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
                   !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 "
-                       "descriptor version (%d) is not 2", ver);
-               if (sm->group_cipher != WPA_CIPHER_CCMP &&
-                   !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
-                       /* Earlier versions of IEEE 802.11i did not explicitly
-                        * require version 2 descriptor for all EAPOL-Key
-                        * packets, so allow group keys to use version 1 if
-                        * CCMP is not used for them. */
+                       "RSN: CCMP is used, but EAPOL-Key descriptor version (%d) is not 2", ver);
+               if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                               "WPA: Backwards compatibility: allow invalid "
-                               "version for non-CCMP group keys");
-               } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+                               "RSN: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
+               } else {
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                               "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
-               } else
+                               "RSN: Unexpected descriptor version %u", ver);
                        goto out;
+               }
        } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
                   !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 "
-                       "descriptor version (%d) is not 2", ver);
-               goto out;
-       }
-
-       if (sm->rx_replay_counter_set &&
-           os_memcmp(key->replay_counter, sm->rx_replay_counter,
-                     WPA_REPLAY_COUNTER_LEN) <= 0) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                       "WPA: EAPOL-Key Replay Counter did not increase - "
-                       "dropping packet");
-               goto out;
-       }
-
-       if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "WPA: Unsupported SMK bit in key_info");
-               goto out;
-       }
-
-       if (!(key_info & WPA_KEY_INFO_ACK)) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "WPA: No Ack bit in key_info");
-               goto out;
-       }
-
-       if (key_info & WPA_KEY_INFO_REQUEST) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "WPA: EAPOL-Key with Request bit - dropped");
+                       "RSN: GCMP is used, but EAPOL-Key descriptor version (%d) is not 2",
+                       ver);
                goto out;
        }
 
@@ -3491,8 +3595,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        if (key_info & WPA_KEY_INFO_KEY_TYPE) {
                if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: Ignored EAPOL-Key (Pairwise) with "
-                               "non-zero key index");
+                               "RSN: Ignored EAPOL-Key (Pairwise) with non-zero key index");
                        goto out;
                }
                if (key_info & (WPA_KEY_INFO_MIC |
@@ -3523,8 +3626,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                                                              ver);
                } else {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: EAPOL-Key (Group) without Mic/Encr bit - "
-                               "dropped");
+                               "RSN: EAPOL-Key (Group) without Mic/Encr bit - dropped");
                }
        }
 
index 6901cae74a9fe29843cbcd2a3fa94c258936ee47..fc9f894c2c1c444e420710f6fe91bdaf86f4c8bf 100644 (file)
@@ -1874,7 +1874,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               replay_counter=counter, key_info=0x13c8)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 0"])
+    ev = dev[0].wait_event(["RSN: Unsupported EAPOL-Key descriptor version 0"])
     if ev is None:
         raise Exception("Unsupported EAPOL-Key descriptor version 0 not reported")
 
@@ -1884,7 +1884,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               replay_counter=counter, key_info=0x13c9)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: CCMP is used, but EAPOL-Key descriptor version (1) is not 2"])
+    ev = dev[0].wait_event(["RSN: EAPOL-Key descriptor version 1 not allowed without TKIP as the pairwise cipher"])
     if ev is None:
         raise Exception("Not allowed EAPOL-Key descriptor version not reported")
 
@@ -1904,10 +1904,10 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               replay_counter=counter, key_info=0x13cb)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: CCMP is used, but EAPOL-Key descriptor version (3) is not 2"])
+    ev = dev[0].wait_event(["RSN: CCMP is used, but EAPOL-Key descriptor version (3) is not 2"])
     if ev is None:
         raise Exception("CCMP key descriptor mismatch not reported")
-    ev = dev[0].wait_event(["WPA: Interoperability workaround"])
+    ev = dev[0].wait_event(["RSN: Interoperability workaround"])
     if ev is None:
         raise Exception("AES-128-CMAC workaround not reported")
     ev = dev[0].wait_event(["WPA: Invalid EAPOL-Key MIC - dropping packet"])
@@ -1920,7 +1920,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               replay_counter=counter, key_info=0x13cc)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 4"])
+    ev = dev[0].wait_event(["RSN: Unsupported EAPOL-Key descriptor version 4"])
     if ev is None:
         raise Exception("Unsupported EAPOL-Key descriptor version 4 not reported")
 
@@ -1930,7 +1930,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               replay_counter=counter, key_info=0x13cf)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: Unsupported EAPOL-Key descriptor version 7"])
+    ev = dev[0].wait_event(["RSN: Unsupported EAPOL-Key descriptor version 7"])
     if ev is None:
         raise Exception("Unsupported EAPOL-Key descriptor version 7 not reported")
 
@@ -1969,7 +1969,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
                               key_info=0x13ea)
     counter += 1
     send_eapol(dev[0], bssid, build_eapol(msg))
-    ev = dev[0].wait_event(["WPA: Ignored EAPOL-Key (Pairwise) with non-zero key index"])
+    ev = dev[0].wait_event(["RSN: Ignored EAPOL-Key (Pairwise) with non-zero key index"])
     if ev is None:
         raise Exception("Non-zero key index not reported")