unit: Add an EAPOL+EAP-TLS test

This commit is contained in:
Andrew Zaborowski 2015-10-30 11:12:23 +01:00 committed by Denis Kenzior
parent cddb584501
commit 13e4432b5e
1 changed files with 398 additions and 0 deletions

View File

@ -28,11 +28,13 @@
#include <string.h>
#include <assert.h>
#include <ell/ell.h>
#include <ell/tls-private.h>
#include "src/sha1.h"
#include "src/eapol.h"
#include "src/crypto.h"
#include "src/ie.h"
#include "src/eap.h"
/* Our nonce to use + its size */
static const uint8_t *snonce;
@ -45,6 +47,8 @@ static size_t expected_step2_frame_size;
/* Whether step4 was called with the right info */
static bool verify_step4_called;
/* Whether install_tk was called with the right info */
static bool verify_install_tk_called;
/* PTK Handshake 4-of-4 frame we are expected to generate + its size */
static const uint8_t *expected_step4_frame;
static size_t expected_step4_frame_size;
@ -1953,6 +1957,397 @@ static void eapol_sm_test_wpa_ptk_gtk_2(const void *data)
eapol_exit();
}
static const uint8_t eap_identity_req[] = {
0x02, 0x00, 0x00, 0x05, 0x01, 0x01, 0x00, 0x05, 0x01
};
static const uint8_t eap_identity_resp[] = {
0x02, 0x00, 0x00, 0x14, 0x02, 0x01, 0x00, 0x14, 0x01, 0x61, 0x62, 0x63,
0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d
};
struct eapol_8021x_tls_test_state {
l_tls_write_cb_t app_data_cb;
l_tls_ready_cb_t ready_cb;
l_tls_disconnect_cb_t disconnect_cb;
uint8_t method;
struct l_tls *tls;
uint8_t last_id;
bool success;
bool pending_req;
bool tx_ack;
uint8_t tx_buf[16384];
unsigned int tx_buf_len, tx_buf_offset;
uint8_t pmk[32];
};
static int verify_8021x_identity_resp(uint32_t ifindex, const uint8_t *aa_addr,
const uint8_t *sta_addr,
const struct eapol_frame *ef,
void *user_data)
{
struct eapol_8021x_tls_test_state *s = user_data;
size_t len = sizeof(struct eapol_header) +
L_BE16_TO_CPU(ef->header.packet_len);
assert(ifindex == 1);
assert(!memcmp(sta_addr, spa, 6));
assert(!memcmp(aa_addr, aa, 6));
assert(len == sizeof(eap_identity_resp));
assert(!memcmp(ef, eap_identity_resp, sizeof(eap_identity_resp)));
assert(s->pending_req);
s->pending_req = 0;
return 0;
}
static int verify_8021x_tls_resp(uint32_t ifindex, const uint8_t *aa_addr,
const uint8_t *sta_addr,
const struct eapol_frame *ef,
void *user_data)
{
struct eapol_8021x_tls_test_state *s = user_data;
size_t len = sizeof(struct eapol_header) +
L_BE16_TO_CPU(ef->header.packet_len);
size_t fragment_len, header_len;
assert(ifindex == 1);
assert(!memcmp(sta_addr, spa, 6));
assert(!memcmp(aa_addr, aa, 6));
assert(len >= 10);
assert(ef->header.protocol_version == EAPOL_PROTOCOL_VERSION_2004);
assert(ef->header.packet_type == 0x00); /* EAPoL-EAP */
assert(ef->data[0] == EAP_CODE_RESPONSE);
assert(ef->data[1] == s->last_id);
assert(ef->data[4] == s->method);
assert((ef->data[5] & 0x3f) == 0); /* Flags */
/* Expecting an ACK? */
if (s->tx_buf_len || s->success) {
assert(ef->data[5] == 0);
assert(len == 10);
}
header_len = 6;
if (ef->data[5] & 0x80) { /* L flag */
assert(len >= 14);
header_len += 4;
assert(ef->data[5] & 0x40); /* M flag */
assert(l_get_be32(ef->data + 6) > fragment_len);
}
s->tx_ack = !!(ef->data[5] & 0x40); /* M flag */
fragment_len = l_get_be16(ef->data + 2) - header_len;
assert(len == 4 + header_len + fragment_len);
assert(s->pending_req);
s->pending_req = 0;
if (fragment_len)
l_tls_handle_rx(s->tls, ef->data + header_len, fragment_len);
return 0;
}
static void eapol_sm_test_tls_new_data(const uint8_t *data, size_t len,
void *user_data)
{
assert(false);
}
static void eapol_sm_test_tls_test_write(const uint8_t *data, size_t len,
void *user_data)
{
struct eapol_8021x_tls_test_state *s = user_data;
assert(!s->tx_ack);
assert(!s->tx_buf_offset);
memcpy(s->tx_buf + s->tx_buf_len, data, len);
s->tx_buf_len += len;
}
static void eapol_sm_test_tls_test_ready(const char *peer_identity,
void *user_data)
{
struct eapol_8021x_tls_test_state *s = user_data;
uint8_t seed[64];
assert(!s->tx_ack);
/* TODO: require the right peer_identity */
s->success = true;
memcpy(seed + 0, s->tls->pending.client_random, 32);
memcpy(seed + 32, s->tls->pending.server_random, 32);
tls_prf_get_bytes(s->tls, L_CHECKSUM_SHA256, 32,
s->tls->pending.master_secret,
sizeof(s->tls->pending.master_secret),
"client EAP encryption", seed, 64, s->pmk, 32);
}
static void eapol_sm_test_tls_test_disconnected(enum l_tls_alert_desc reason,
bool remote, void *user_data)
{
assert(false);
}
static void verify_deauthenticate(uint32_t ifindex, const uint8_t *aa,
const uint8_t *spa, uint16_t reason_code,
void *user_data)
{
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,
const char *config)
{
static const unsigned char ap_wpa_ie[] = {
0xdd, 0x16, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02 };
static uint8_t ap_address[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t sta_address[] = { 0x02, 0x00, 0x00, 0x00, 0x01, 0x00 };
bool r;
struct eapol_sm *sm;
struct l_settings *settings;
uint8_t tx_buf[2000];
size_t header_len, data_len, tx_len;
bool start;
uint8_t step1_buf[256], step2_buf[256], step3_buf[256], step4_buf[256];
struct eapol_key *step1, *step2, *step3, *step4;
uint8_t ptk_buf[64];
struct crypto_ptk *ptk;
aa = ap_address;
spa = sta_address;
eapol_init();
__eapol_set_protocol_version(EAPOL_PROTOCOL_VERSION_2004);
__eapol_set_get_nonce_func(test_nonce);
__eapol_set_deauthenticate_func(verify_deauthenticate);
sm = eapol_sm_new();
eapol_sm_set_authenticator_address(sm, ap_address);
eapol_sm_set_supplicant_address(sm, sta_address);
eapol_sm_set_tx_user_data(sm, s);
settings = l_settings_new();
l_settings_load_from_data(settings, config, strlen(config));
eapol_sm_set_8021x_config(sm, settings);
l_settings_free(settings);
r = eapol_sm_set_own_wpa(sm,
eapol_key_data_20 + sizeof(struct eapol_key),
eapol_key_test_20.key_data_len);
assert(r);
eapol_sm_set_ap_wpa(sm, ap_wpa_ie, sizeof(ap_wpa_ie));
eapol_start(1, sm);
__eapol_set_tx_packet_func(verify_8021x_identity_resp);
s->pending_req = 1;
__eapol_rx_packet(1, sta_address, ap_address, eap_identity_req,
sizeof(eap_identity_req));
assert(!s->pending_req);
s->tls = l_tls_new(true, s->app_data_cb, eapol_sm_test_tls_test_write,
s->ready_cb, s->disconnect_cb, s);
assert(s->tls);
s->last_id = 1;
s->success = false;
s->tx_buf_len = 0;
s->tx_buf_offset = 0;
l_tls_set_auth_data(s->tls, "ell/unit/cert-server.pem",
"ell/unit/cert-server-key.pem", NULL);
l_tls_set_cacert(s->tls, "ell/unit/cert-ca.pem");
start = 1;
__eapol_set_tx_packet_func(verify_8021x_tls_resp);
while (!s->success || s->tx_buf_len) {
tx_len = 0;
data_len = 1024 < s->tx_buf_len ? 1024 : s->tx_buf_len;
header_len = 6;
if (data_len < s->tx_buf_len && !s->tx_buf_offset)
header_len += 4;
tx_buf[tx_len++] = EAPOL_PROTOCOL_VERSION_2004;
tx_buf[tx_len++] = 0x00; /* EAPoL-EAP */
tx_buf[tx_len++] = (data_len + header_len) >> 8;
tx_buf[tx_len++] = (data_len + header_len) >> 0;
tx_buf[tx_len++] = EAP_CODE_REQUEST;
tx_buf[tx_len++] = ++s->last_id;
tx_buf[tx_len++] = (data_len + header_len) >> 8;
tx_buf[tx_len++] = (data_len + header_len) >> 0;
tx_buf[tx_len++] = s->method;
tx_buf[tx_len++] = 0x00; /* Flags */
if (start) {
tx_buf[tx_len - 1] |= 0x20; /* S flag */
start = 0;
}
if (data_len < s->tx_buf_len)
tx_buf[tx_len - 1] |= 0x40; /* M flag */
if (data_len < s->tx_buf_len && !s->tx_buf_offset) {
tx_buf[tx_len - 1] |= 0x80; /* L flag */
tx_buf[tx_len++] = s->tx_buf_len >> 24;
tx_buf[tx_len++] = s->tx_buf_len >> 16;
tx_buf[tx_len++] = s->tx_buf_len >> 8;
tx_buf[tx_len++] = s->tx_buf_len >> 0;
}
memcpy(tx_buf + tx_len, s->tx_buf + s->tx_buf_offset, data_len);
tx_len += data_len;
s->tx_buf_offset += data_len;
s->tx_buf_len -= data_len;
if (!s->tx_buf_len)
s->tx_buf_offset = 0;
s->pending_req = 1;
__eapol_rx_packet(1, sta_address, ap_address, tx_buf, tx_len);
assert(!s->pending_req);
while (s->tx_ack) {
tx_len = 0;
tx_buf[tx_len++] = EAPOL_PROTOCOL_VERSION_2004;
tx_buf[tx_len++] = 0x00; /* EAPoL-EAP */
tx_buf[tx_len++] = 0x00;
tx_buf[tx_len++] = 0x06; /* Length */
tx_buf[tx_len++] = EAP_CODE_REQUEST;
tx_buf[tx_len++] = ++s->last_id;
tx_buf[tx_len++] = 0x00;
tx_buf[tx_len++] = 0x06; /* Length */
tx_buf[tx_len++] = s->method;
tx_buf[tx_len++] = 0x00; /* Flags */
s->pending_req = 1;
__eapol_rx_packet(1, sta_address, ap_address,
tx_buf, tx_len);
assert(!s->pending_req);
}
}
l_tls_free(s->tls);
tx_len = 0;
tx_buf[tx_len++] = EAPOL_PROTOCOL_VERSION_2004;
tx_buf[tx_len++] = 0x00; /* EAPoL-EAP */
tx_buf[tx_len++] = 0x00;
tx_buf[tx_len++] = 0x04; /* Length */
tx_buf[tx_len++] = EAP_CODE_SUCCESS;
tx_buf[tx_len++] = s->last_id;
tx_buf[tx_len++] = 0x00;
tx_buf[tx_len++] = 0x04; /* Length */
__eapol_rx_packet(1, sta_address, ap_address, tx_buf, tx_len);
memcpy(step1_buf, eapol_key_data_13, sizeof(eapol_key_data_13));
step1 = (struct eapol_key *)
eapol_key_validate(step1_buf, sizeof(eapol_key_data_13));
memcpy(step2_buf, eapol_key_data_14, sizeof(eapol_key_data_14));
step2 = (struct eapol_key *)
eapol_key_validate(step2_buf, sizeof(eapol_key_data_14));
memcpy(step3_buf, eapol_key_data_15, sizeof(eapol_key_data_15));
step3 = (struct eapol_key *)
eapol_key_validate(step3_buf, sizeof(eapol_key_data_15));
memcpy(step4_buf, eapol_key_data_16, sizeof(eapol_key_data_16));
step4 = (struct eapol_key *)
eapol_key_validate(step4_buf, sizeof(eapol_key_data_16));
ptk = (struct crypto_ptk *) ptk_buf;
crypto_derive_pairwise_ptk(s->pmk, sta_address, ap_address,
step1->key_nonce, step2->key_nonce,
ptk, 64);
memset(step2->key_mic_data, 0, 16);
assert(eapol_calculate_mic(ptk->kck, step2, step2->key_mic_data));
memset(step3->key_mic_data, 0, 16);
assert(eapol_calculate_mic(ptk->kck, step3, step3->key_mic_data));
memset(step4->key_mic_data, 0, 16);
assert(eapol_calculate_mic(ptk->kck, step4, step4->key_mic_data));
snonce = step2->key_nonce;
verify_step2_called = false;
expected_step2_frame = step2_buf;
expected_step2_frame_size = sizeof(eapol_key_data_14);
__eapol_set_tx_packet_func(verify_step2);
__eapol_rx_packet(1, sta_address, ap_address, step1_buf,
sizeof(eapol_key_data_13));
assert(verify_step2_called);
verify_step4_called = false;
verify_install_tk_called = false;
expected_step4_frame = step4_buf;
expected_step4_frame_size = sizeof(eapol_key_data_16);
__eapol_set_tx_packet_func(verify_step4);
__eapol_set_install_tk_func(verify_install_tk);
eapol_sm_set_user_data(sm, ptk->tk);
__eapol_rx_packet(1, sta_address, ap_address, step3_buf,
sizeof(eapol_key_data_15));
assert(verify_step4_called);
assert(verify_install_tk_called);
eapol_exit();
}
static void eapol_sm_test_eap_tls(const void *data)
{
static const char *eapol_8021x_config = "[Security]\n"
"EAP-Method=TLS\n"
"EAP-Identity=abc@example.com\n"
"EAP-TLS-CACert=ell/unit/cert-ca.pem\n"
"EAP-TLS-ClientCert=ell/unit/cert-client.pem\n"
"EAP-TLS-ClientKey=ell/unit/cert-client-key.pem";
struct eapol_8021x_tls_test_state s;
s.app_data_cb = eapol_sm_test_tls_new_data;
s.ready_cb = eapol_sm_test_tls_test_ready;
s.disconnect_cb = eapol_sm_test_tls_test_disconnected;
s.method = EAP_TYPE_TLS_EAP;
eapol_sm_test_tls(&s, eapol_8021x_config);
}
int main(int argc, char *argv[])
{
l_test_init(&argc, &argv);
@ -2034,5 +2429,8 @@ int main(int argc, char *argv[])
l_test_add("EAPoL/WPA PTK & GTK State Machine Test 2",
&eapol_sm_test_wpa_ptk_gtk_2, NULL);
l_test_add("EAPoL/8021x EAP-TLS & 4-Way Handshake",
&eapol_sm_test_eap_tls, NULL);
return l_test_run();
}