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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2022-11-27 08:30:58 +02:00
parent f7fd891c70
commit 5ab43c738e
2 changed files with 158 additions and 56 deletions

View file

@ -3251,6 +3251,87 @@ static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
#endif /* CONFIG_FILS */ #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 * wpa_sm_rx_eapol - Process received WPA EAPOL frames
* @sm: Pointer to WPA state machine data from wpa_sm_init() * @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; 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); eapol_sm_notify_lower_layer_success(sm->eapol, 0);
key_info = WPA_GET_BE16(key->key_info); 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; ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_use_akm_defined(sm->key_mgmt)) { !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d", "RSN: Unsupported EAPOL-Key descriptor version %d",
ver); ver);
goto out; 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) && if (wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, 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 && if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
!wpa_use_akm_defined(sm->key_mgmt)) { !wpa_use_akm_defined(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the " "RSN: AP did not use the negotiated AES-128-CMAC");
"negotiated AES-128-CMAC");
goto out; goto out;
} }
} else if (sm->pairwise_cipher == WPA_CIPHER_CCMP && } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
!wpa_use_akm_defined(sm->key_mgmt) && !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key " "RSN: CCMP is used, but EAPOL-Key descriptor version (%d) is not 2", ver);
"descriptor version (%d) is not 2", ver); if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
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_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Backwards compatibility: allow invalid " "RSN: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
"version for non-CCMP group keys"); } else {
} else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, 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"); "RSN: Unexpected descriptor version %u", ver);
} else
goto out; goto out;
}
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP && } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
!wpa_use_akm_defined(sm->key_mgmt) && !wpa_use_akm_defined(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key " "RSN: GCMP is used, but EAPOL-Key descriptor version (%d) is not 2",
"descriptor version (%d) is not 2", ver); 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");
goto out; 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_TYPE) {
if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Ignored EAPOL-Key (Pairwise) with " "RSN: Ignored EAPOL-Key (Pairwise) with non-zero key index");
"non-zero key index");
goto out; goto out;
} }
if (key_info & (WPA_KEY_INFO_MIC | 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); ver);
} else { } else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic/Encr bit - " "RSN: EAPOL-Key (Group) without Mic/Encr bit - dropped");
"dropped");
} }
} }

View file

@ -1874,7 +1874,7 @@ def test_ap_wpa2_psk_supp_proto(dev, apdev):
replay_counter=counter, key_info=0x13c8) replay_counter=counter, key_info=0x13c8)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("Unsupported EAPOL-Key descriptor version 0 not reported") 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) replay_counter=counter, key_info=0x13c9)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("Not allowed EAPOL-Key descriptor version not reported") 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) replay_counter=counter, key_info=0x13cb)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("CCMP key descriptor mismatch not reported") 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: if ev is None:
raise Exception("AES-128-CMAC workaround not reported") raise Exception("AES-128-CMAC workaround not reported")
ev = dev[0].wait_event(["WPA: Invalid EAPOL-Key MIC - dropping packet"]) 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) replay_counter=counter, key_info=0x13cc)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("Unsupported EAPOL-Key descriptor version 4 not reported") 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) replay_counter=counter, key_info=0x13cf)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("Unsupported EAPOL-Key descriptor version 7 not reported") 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) key_info=0x13ea)
counter += 1 counter += 1
send_eapol(dev[0], bssid, build_eapol(msg)) 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: if ev is None:
raise Exception("Non-zero key index not reported") raise Exception("Non-zero key index not reported")