mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-22 06:29:23 +01:00
unit: Add EAPoL retransmission test
This commit is contained in:
parent
7f8f45220e
commit
a1f4a9901d
@ -50,6 +50,7 @@ static size_t expected_step2_frame_size;
|
|||||||
static bool verify_step4_called;
|
static bool verify_step4_called;
|
||||||
/* Whether install_tk was called with the right info */
|
/* Whether install_tk was called with the right info */
|
||||||
static bool verify_install_tk_called;
|
static bool verify_install_tk_called;
|
||||||
|
static bool verify_install_gtk_called;
|
||||||
/* PTK Handshake 4-of-4 frame we are expected to generate + its size */
|
/* PTK Handshake 4-of-4 frame we are expected to generate + its size */
|
||||||
static const uint8_t *expected_step4_frame;
|
static const uint8_t *expected_step4_frame;
|
||||||
static size_t expected_step4_frame_size;
|
static size_t expected_step4_frame_size;
|
||||||
@ -2424,6 +2425,252 @@ static void eapol_sm_test_wpa_ptk_gtk_2(const void *data)
|
|||||||
eapol_exit();
|
eapol_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void verify_install_tk(uint32_t ifindex, const uint8_t *aa_addr,
|
||||||
|
const uint8_t *tk, uint32_t cipher,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
assert(ifindex == 1);
|
||||||
|
assert(!memcmp(aa_addr, aa, 6));
|
||||||
|
|
||||||
|
if (user_data) {
|
||||||
|
assert(!memcmp(tk, user_data, 32));
|
||||||
|
assert(cipher == CRYPTO_CIPHER_TKIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_install_tk_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void verify_install_gtk(uint32_t ifindex, uint8_t key_index,
|
||||||
|
const uint8_t *gtk, uint8_t gtk_len,
|
||||||
|
const uint8_t *rsc, uint8_t rsc_len,
|
||||||
|
uint32_t cipher, void *user_data)
|
||||||
|
{
|
||||||
|
assert(ifindex == 1);
|
||||||
|
verify_install_gtk_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t EKL(const struct eapol_key *frame)
|
||||||
|
{
|
||||||
|
return sizeof(*frame) + L_BE16_TO_CPU(frame->key_data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct eapol_key *UPDATED_REPLAY_COUNTER(const struct eapol_key *frame,
|
||||||
|
uint64_t replay_counter,
|
||||||
|
struct crypto_ptk *ptk)
|
||||||
|
{
|
||||||
|
struct eapol_key *ret = l_memdup(frame, EKL(frame));
|
||||||
|
uint8_t mic[16];
|
||||||
|
|
||||||
|
ret->key_replay_counter = L_CPU_TO_BE64(replay_counter);
|
||||||
|
memset(ret->key_mic_data, 0, sizeof(ret->key_mic_data));
|
||||||
|
eapol_calculate_mic(ptk->kck, ret, mic);
|
||||||
|
memcpy(ret->key_mic_data, mic, sizeof(mic));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eapol_sm_wpa2_retransmit_test(const void *data)
|
||||||
|
{
|
||||||
|
static uint8_t ap_address[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
static uint8_t sta_address[] = { 0x02, 0x00, 0x00, 0x00, 0x01, 0x00 };
|
||||||
|
const char *passphrase = "EasilyGuessedPassword";
|
||||||
|
const char *ssid = "TestWPA";
|
||||||
|
unsigned char psk[32];
|
||||||
|
const unsigned char ap_rsne[] = {
|
||||||
|
0x30, 0x12, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04,
|
||||||
|
0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00,
|
||||||
|
0x00, 0x0f, 0xac, 0x02 };
|
||||||
|
uint8_t new_snonce[32];
|
||||||
|
struct crypto_ptk *ptk;
|
||||||
|
size_t ptk_len;
|
||||||
|
struct eapol_key *expect;
|
||||||
|
struct eapol_key *retransmit;
|
||||||
|
bool r;
|
||||||
|
const struct eapol_key *ptk_step1;
|
||||||
|
const struct eapol_key *ptk_step2;
|
||||||
|
const struct eapol_key *ptk_step3;
|
||||||
|
const struct eapol_key *ptk_step4;
|
||||||
|
const struct eapol_key *gtk_step1;
|
||||||
|
const struct eapol_key *gtk_step2;
|
||||||
|
struct handshake_state *hs;
|
||||||
|
struct eapol_sm *sm;
|
||||||
|
uint64_t replay_counter;
|
||||||
|
|
||||||
|
aa = ap_address;
|
||||||
|
spa = sta_address;
|
||||||
|
|
||||||
|
crypto_psk_from_passphrase(passphrase, (uint8_t *) ssid,
|
||||||
|
strlen(ssid), psk);
|
||||||
|
|
||||||
|
eapol_init();
|
||||||
|
hs = handshake_state_new(1);
|
||||||
|
sm = eapol_sm_new(hs);
|
||||||
|
eapol_register(sm);
|
||||||
|
|
||||||
|
handshake_state_set_pmk(hs, psk);
|
||||||
|
handshake_state_set_authenticator_address(hs, ap_address);
|
||||||
|
handshake_state_set_supplicant_address(hs, sta_address);
|
||||||
|
|
||||||
|
r = handshake_state_set_own_rsn(hs,
|
||||||
|
eapol_key_data_8 + sizeof(struct eapol_key));
|
||||||
|
assert(r);
|
||||||
|
|
||||||
|
handshake_state_set_ap_rsn(hs, ap_rsne);
|
||||||
|
eapol_start(sm);
|
||||||
|
|
||||||
|
ptk_step1 = eapol_key_validate(eapol_key_data_7,
|
||||||
|
sizeof(eapol_key_data_7));
|
||||||
|
assert(ptk_step1);
|
||||||
|
|
||||||
|
ptk_step2 = eapol_key_validate(eapol_key_data_8,
|
||||||
|
sizeof(eapol_key_data_8));
|
||||||
|
assert(ptk_step2);
|
||||||
|
|
||||||
|
replay_counter = L_BE64_TO_CPU(ptk_step1->key_replay_counter);
|
||||||
|
snonce = ptk_step2->key_nonce;
|
||||||
|
__handshake_set_get_nonce_func(test_nonce);
|
||||||
|
__handshake_set_install_tk_func(verify_install_tk);
|
||||||
|
__handshake_set_install_gtk_func(verify_install_gtk);
|
||||||
|
|
||||||
|
ptk_len = sizeof(struct crypto_ptk) +
|
||||||
|
crypto_cipher_key_len(CRYPTO_CIPHER_CCMP);
|
||||||
|
ptk = l_malloc(ptk_len);
|
||||||
|
assert(crypto_derive_pairwise_ptk(psk, aa, spa,
|
||||||
|
ptk_step1->key_nonce,
|
||||||
|
ptk_step2->key_nonce,
|
||||||
|
ptk, ptk_len, false));
|
||||||
|
|
||||||
|
verify_step2_called = false;
|
||||||
|
expected_step2_frame = (const uint8_t *) ptk_step2;
|
||||||
|
expected_step2_frame_size = EKL(ptk_step2);
|
||||||
|
__eapol_set_tx_packet_func(verify_step2);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) ptk_step1, EKL(ptk_step1));
|
||||||
|
assert(verify_step2_called);
|
||||||
|
|
||||||
|
/* Detect whether we generate a new snonce when we shouldn't */
|
||||||
|
memset(new_snonce, 0xff, sizeof(new_snonce));
|
||||||
|
snonce = new_snonce;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now retransmit frame 1 again without updating the counter. This
|
||||||
|
* seems to be legal since the STA should not update the replay counter
|
||||||
|
* unless the packet has a MIC.
|
||||||
|
*/
|
||||||
|
verify_step2_called = false;
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) ptk_step1, EKL(ptk_step1));
|
||||||
|
assert(verify_step2_called);
|
||||||
|
|
||||||
|
/* Now retransmit frame 1 with an updated counter */
|
||||||
|
replay_counter += 1;
|
||||||
|
retransmit = l_memdup(ptk_step1, EKL(ptk_step1));
|
||||||
|
retransmit->key_replay_counter = L_CPU_TO_BE64(replay_counter);
|
||||||
|
|
||||||
|
expect = UPDATED_REPLAY_COUNTER(ptk_step2, replay_counter, ptk);
|
||||||
|
|
||||||
|
verify_step2_called = false;
|
||||||
|
expected_step2_frame = (const uint8_t *) expect;
|
||||||
|
expected_step2_frame_size = EKL(expect);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) retransmit, EKL(retransmit));
|
||||||
|
assert(verify_step2_called);
|
||||||
|
|
||||||
|
l_free(expect);
|
||||||
|
l_free(retransmit);
|
||||||
|
|
||||||
|
ptk_step3 = eapol_key_validate(eapol_key_data_9,
|
||||||
|
sizeof(eapol_key_data_9));
|
||||||
|
assert(ptk_step3);
|
||||||
|
|
||||||
|
ptk_step4 = eapol_key_validate(eapol_key_data_10,
|
||||||
|
sizeof(eapol_key_data_10));
|
||||||
|
assert(ptk_step4);
|
||||||
|
|
||||||
|
verify_install_tk_called = false;
|
||||||
|
verify_step4_called = false;
|
||||||
|
expected_step4_frame = (const uint8_t *) ptk_step4;
|
||||||
|
expected_step4_frame_size = EKL(ptk_step4);
|
||||||
|
__eapol_set_tx_packet_func(verify_step4);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) ptk_step3, EKL(ptk_step3));
|
||||||
|
assert(verify_step4_called);
|
||||||
|
assert(verify_install_tk_called);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now retransmit message 3. Make sure install_tk_called is false
|
||||||
|
* this time. This prevents KRACK style attacks.
|
||||||
|
*/
|
||||||
|
replay_counter += 1;
|
||||||
|
retransmit = UPDATED_REPLAY_COUNTER(ptk_step3, replay_counter, ptk);
|
||||||
|
expect = UPDATED_REPLAY_COUNTER(ptk_step4, replay_counter, ptk);
|
||||||
|
|
||||||
|
verify_install_tk_called = false;
|
||||||
|
verify_step4_called = false;
|
||||||
|
expected_step4_frame = (const uint8_t *) expect;
|
||||||
|
expected_step4_frame_size = EKL(expect);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) retransmit, EKL(retransmit));
|
||||||
|
assert(verify_step4_called);
|
||||||
|
assert(!verify_install_tk_called);
|
||||||
|
|
||||||
|
l_free(expect);
|
||||||
|
l_free(retransmit);
|
||||||
|
|
||||||
|
gtk_step1 = eapol_key_validate(eapol_key_data_11,
|
||||||
|
sizeof(eapol_key_data_11));
|
||||||
|
assert(gtk_step1);
|
||||||
|
|
||||||
|
gtk_step2 = eapol_key_validate(eapol_key_data_12,
|
||||||
|
sizeof(eapol_key_data_12));
|
||||||
|
assert(gtk_step2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now run the GTK handshake. Since we retransmitted Step 3 above,
|
||||||
|
* update the replay counter and perform the initial transmission
|
||||||
|
*/
|
||||||
|
replay_counter += 1;
|
||||||
|
retransmit = UPDATED_REPLAY_COUNTER(gtk_step1, replay_counter, ptk);
|
||||||
|
expect = UPDATED_REPLAY_COUNTER(gtk_step2, replay_counter, ptk);
|
||||||
|
|
||||||
|
verify_install_gtk_called = false;
|
||||||
|
verify_gtk_step2_called = false;
|
||||||
|
expected_gtk_step2_frame = (const uint8_t *) expect;
|
||||||
|
expected_gtk_step2_frame_size = EKL(expect);
|
||||||
|
__eapol_set_tx_packet_func(verify_step2_gtk);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) retransmit, EKL(retransmit));
|
||||||
|
assert(verify_gtk_step2_called);
|
||||||
|
assert(verify_install_gtk_called);
|
||||||
|
|
||||||
|
l_free(retransmit);
|
||||||
|
l_free(expect);
|
||||||
|
|
||||||
|
/* Now send a retransmit, make sure GTK isn't installed again */
|
||||||
|
replay_counter += 1;
|
||||||
|
retransmit = UPDATED_REPLAY_COUNTER(gtk_step1, replay_counter, ptk);
|
||||||
|
expect = UPDATED_REPLAY_COUNTER(gtk_step2, replay_counter, ptk);
|
||||||
|
|
||||||
|
verify_install_gtk_called = false;
|
||||||
|
verify_gtk_step2_called = false;
|
||||||
|
expected_gtk_step2_frame = (const uint8_t *) expect;
|
||||||
|
expected_gtk_step2_frame_size = EKL(expect);
|
||||||
|
__eapol_set_tx_packet_func(verify_step2_gtk);
|
||||||
|
__eapol_rx_packet(1, ap_address, ETH_P_PAE,
|
||||||
|
(const uint8_t *) retransmit, EKL(retransmit));
|
||||||
|
assert(verify_gtk_step2_called);
|
||||||
|
assert(!verify_install_gtk_called);
|
||||||
|
|
||||||
|
l_free(retransmit);
|
||||||
|
l_free(expect);
|
||||||
|
|
||||||
|
l_free(ptk);
|
||||||
|
|
||||||
|
eapol_sm_free(sm);
|
||||||
|
handshake_state_free(hs);
|
||||||
|
eapol_exit();
|
||||||
|
}
|
||||||
|
|
||||||
static const uint8_t eap_identity_req[] = {
|
static const uint8_t eap_identity_req[] = {
|
||||||
0x02, 0x00, 0x00, 0x05, 0x01, 0x01, 0x00, 0x05, 0x01
|
0x02, 0x00, 0x00, 0x05, 0x01, 0x01, 0x00, 0x05, 0x01
|
||||||
};
|
};
|
||||||
@ -2575,19 +2822,6 @@ static void verify_deauthenticate(uint32_t ifindex, const uint8_t *aa,
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_install_tk(uint32_t ifindex, const uint8_t *aa_addr,
|
|
||||||
const uint8_t *tk, uint32_t cipher,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
assert(ifindex == 1);
|
|
||||||
assert(!memcmp(aa_addr, aa, 6));
|
|
||||||
assert(!memcmp(tk, user_data, 32));
|
|
||||||
assert(cipher == CRYPTO_CIPHER_TKIP);
|
|
||||||
|
|
||||||
assert(!verify_install_tk_called);
|
|
||||||
verify_install_tk_called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eapol_sm_test_tls(struct eapol_8021x_tls_test_state *s,
|
static void eapol_sm_test_tls(struct eapol_8021x_tls_test_state *s,
|
||||||
const char *config)
|
const char *config)
|
||||||
{
|
{
|
||||||
@ -3212,6 +3446,9 @@ int main(int argc, char *argv[])
|
|||||||
l_test_add("EAPoL/WPA PTK & GTK State Machine Test 2",
|
l_test_add("EAPoL/WPA PTK & GTK State Machine Test 2",
|
||||||
&eapol_sm_test_wpa_ptk_gtk_2, NULL);
|
&eapol_sm_test_wpa_ptk_gtk_2, NULL);
|
||||||
|
|
||||||
|
l_test_add("EAPoL/WPA2 Retransmit Test",
|
||||||
|
&eapol_sm_wpa2_retransmit_test, NULL);
|
||||||
|
|
||||||
l_test_add("EAPoL/8021x EAP-TLS & 4-Way Handshake",
|
l_test_add("EAPoL/8021x EAP-TLS & 4-Way Handshake",
|
||||||
&eapol_sm_test_eap_tls, NULL);
|
&eapol_sm_test_eap_tls, NULL);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user