3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-12-22 04:32:37 +01:00

eapol: prevent key reinstallation on retransmitted Msg4/4

Currently an adversary can retransmit EAPOL Msg4/4 to make the AP
reinstall the PTK. Against older Linux kernels this can subsequently
be used to decrypt, replay, and possibly decrypt frames. See the
KRACK attacks research at krackattacks.com for attack scenarios.
In this case no machine-in-the-middle position is needed to trigger
the key reinstallation.

Fix this by using the ptk_complete boolean to track when the 4-way
handshake has completed (similar to its usage for clients). When
receiving a retransmitted Msg4/4 accept this frame but do not reinstall
the PTK.

Credits to Chris M. Stone, Sam Thomas, and Tom Chothia of Birmingham
University to help discover this issue.
This commit is contained in:
Mathy Vanhoef 2020-08-12 15:17:21 +04:00 committed by Denis Kenzior
parent 59ce53ceb2
commit f22ba5aebb

View File

@ -1462,7 +1462,6 @@ static void eapol_handle_ptk_2_of_4(struct eapol_sm *sm,
memcpy(sm->handshake->snonce, ek->key_nonce,
sizeof(sm->handshake->snonce));
sm->handshake->have_snonce = true;
sm->handshake->ptk_complete = true;
sm->frame_retry = 0;
@ -1782,7 +1781,15 @@ static void eapol_handle_ptk_4_of_4(struct eapol_sm *sm,
l_timeout_remove(sm->timeout);
sm->timeout = NULL;
handshake_state_install_ptk(sm->handshake);
/*
* If ptk_complete is set, then we are receiving Message 4 again.
* This might be a retransmission, so accept but don't install
* the keys again.
*/
if (!sm->handshake->ptk_complete)
handshake_state_install_ptk(sm->handshake);
sm->handshake->ptk_complete = true;
}
static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm,
@ -2185,6 +2192,7 @@ static void eapol_auth_key_handle(struct eapol_sm *sm,
size_t frame_len = 4 + L_BE16_TO_CPU(frame->header.packet_len);
const struct eapol_key *ek = eapol_key_validate((const void *) frame,
frame_len, sm->mic_len);
uint16_t key_data_len;
if (!ek)
return;
@ -2199,7 +2207,8 @@ static void eapol_auth_key_handle(struct eapol_sm *sm,
if (!sm->handshake->have_anonce)
return; /* Not expecting an EAPoL-Key yet */
if (!sm->handshake->ptk_complete)
key_data_len = EAPOL_KEY_DATA_LEN(ek, sm->mic_len);
if (key_data_len != 0)
eapol_handle_ptk_2_of_4(sm, ek);
else
eapol_handle_ptk_4_of_4(sm, ek);