From: Jouni Malinen Date: Sun, 27 Nov 2022 06:30:58 +0000 (+0200) Subject: RSN: Split WPA(v1) processing of EAPOL-Key frames into a separate function X-Git-Tag: hostap_2_11~1480 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ab43c738e903897116c68826d202616f520f49d;p=thirdparty%2Fhostap.git RSN: Split WPA(v1) processing of EAPOL-Key frames into a separate function 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 --- diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 5e4c60891..e3a64f171 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -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"); } } diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py index 6901cae74..fc9f894c2 100644 --- a/tests/hwsim/test_ap_psk.py +++ b/tests/hwsim/test_ap_psk.py @@ -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")