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

eapol: allow 16, 24 and 32 byte MIC lengths

The MIC length was hard coded to 16 bytes everywhere, and since several
AKMs require larger MIC's (24/32) this needed to change. The main issue
was that the MIC was hard coded to 16 bytes inside eapol_key. Instead
of doing this, the MIC, key_data_length, and key_data elements were all
bundled into key_data[0]. In order to retrieve the MIC, key_data_len,
or key_data several macros were introduced which account for the MIC
length provided.

A consequence of this is that all the verify functions inside eapol now
require the MIC length as a parameter because without it they cannot
determine the byte offset of key_data or key_data_length.

The MIC length for a given handshake is set inside the SM when starting
EAPoL. This length is determined by the AKM for the handshake.
This commit is contained in:
James Prestwood 2019-01-17 12:25:28 -08:00 committed by Denis Kenzior
parent 80d4e9b572
commit 374b367ba4
5 changed files with 176 additions and 107 deletions

View File

@ -3839,7 +3839,7 @@ static void print_attributes(int indent, const struct attr_entry *table,
static void print_eapol_key(const void *data, uint32_t size)
{
const struct eapol_key *ek = eapol_key_validate(data, size);
const struct eapol_key *ek = eapol_key_validate(data, size, 16);
if (!ek)
return;
@ -3872,16 +3872,16 @@ static void print_eapol_key(const void *data, uint32_t size)
print_attr(1, "Key RSC ");
print_hexdump(2, ek->key_rsc, 8);
print_attr(1, "Key MIC Data");
print_hexdump(2, ek->key_mic_data, 16);
print_hexdump(2, EAPOL_KEY_MIC(ek), 16);
if (ek->encrypted_key_data) {
print_attr(1, "Key Data: len %d",
L_BE16_TO_CPU(ek->key_data_len));
print_hexdump(2, ek->key_data, L_BE16_TO_CPU(ek->key_data_len));
print_attr(1, "Key Data: len %d", EAPOL_KEY_DATA_LEN(ek, 16));
print_hexdump(2, EAPOL_KEY_DATA(ek, 16),
EAPOL_KEY_DATA_LEN(ek, 16));
return;
}
print_ie(1, "Key Data", ek->key_data, L_BE16_TO_CPU(ek->key_data_len));
print_ie(1, "Key Data", ek->key_data, EAPOL_KEY_DATA_LEN(ek, 16));
}
static void netlink_str(char *str, size_t size,

View File

@ -56,36 +56,38 @@ uint32_t next_frame_watch_id;
return false; \
} while (false) \
#define MIC_MAXLEN 32
/*
* MIC calculation depends on the selected hash function. The has function
* is given in the EAPoL Key Descriptor Version field.
*
* The MIC length is always 16 bytes for currently known Key Descriptor
* Versions.
*
* The input struct eapol_key *frame should have a zero-d MIC field
*/
bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
const struct eapol_key *frame, uint8_t *mic)
const struct eapol_key *frame, uint8_t *mic,
size_t mic_len)
{
size_t frame_len = sizeof(struct eapol_key);
frame_len += L_BE16_TO_CPU(frame->key_data_len);
size_t frame_len = EAPOL_FRAME_LEN(mic_len) +
EAPOL_KEY_DATA_LEN(frame, mic_len);
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
return hmac_md5(kck, 16, frame, frame_len, mic, 16);
return hmac_md5(kck, 16, frame, frame_len, mic, mic_len);
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
return hmac_sha1(kck, 16, frame, frame_len, mic, 16);
return hmac_sha1(kck, 16, frame, frame_len, mic, mic_len);
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
return cmac_aes(kck, 16, frame, frame_len, mic, 16);
return cmac_aes(kck, 16, frame, frame_len, mic, mic_len);
case EAPOL_KEY_DESCRIPTOR_VERSION_AKM_DEFINED:
switch (akm) {
case IE_RSN_AKM_SUITE_SAE_SHA256:
case IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256:
return cmac_aes(kck, 16, frame, frame_len, mic, 16);
return cmac_aes(kck, 16, frame, frame_len,
mic, mic_len);
case IE_RSN_AKM_SUITE_OWE:
return hmac_sha256(kck, 16, frame, frame_len, mic, 16);
return hmac_sha256(kck, mic_len, frame,
frame_len, mic,
mic_len);
default:
return false;
}
@ -95,24 +97,21 @@ bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
}
bool eapol_verify_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
const struct eapol_key *frame)
const struct eapol_key *frame, size_t mic_len)
{
size_t frame_len = sizeof(struct eapol_key);
uint8_t mic[16];
uint8_t mic[MIC_MAXLEN];
struct iovec iov[3];
struct l_checksum *checksum = NULL;
iov[0].iov_base = (void *) frame;
iov[0].iov_len = offsetof(struct eapol_key, key_mic_data);
iov[0].iov_len = offsetof(struct eapol_key, key_data);
memset(mic, 0, sizeof(mic));
iov[1].iov_base = mic;
iov[1].iov_len = sizeof(mic);
iov[1].iov_len = mic_len;
iov[2].iov_base = ((void *) frame) +
offsetof(struct eapol_key, key_data_len);
iov[2].iov_len = frame_len - offsetof(struct eapol_key, key_data_len) +
L_BE16_TO_CPU(frame->key_data_len);
iov[2].iov_base = (void *) EAPOL_KEY_DATA(frame, mic_len) - 2;
iov[2].iov_len = EAPOL_KEY_DATA_LEN(frame, mic_len) + 2;
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
@ -147,21 +146,35 @@ bool eapol_verify_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
return false;
l_checksum_updatev(checksum, iov, 3);
l_checksum_get_digest(checksum, mic, 16);
l_checksum_get_digest(checksum, mic, mic_len);
l_checksum_free(checksum);
if (!memcmp(frame->key_mic_data, mic, 16))
if (!memcmp(frame->key_data, mic, mic_len))
return true;
return false;
}
/*
* IEEE 802.11 Table 12-8 -- Integrity and key-wrap algorithms
*/
static size_t eapol_get_mic_length(enum ie_rsn_akm_suite akm)
{
switch (akm) {
case IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA384:
case IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384:
return 24;
default:
return 16;
}
}
uint8_t *eapol_decrypt_key_data(enum ie_rsn_akm_suite akm, const uint8_t *kek,
const struct eapol_key *frame,
size_t *decrypted_size)
size_t *decrypted_size, size_t mic_len)
{
size_t key_data_len = L_BE16_TO_CPU(frame->key_data_len);
const uint8_t *key_data = frame->key_data;
size_t key_data_len = EAPOL_KEY_DATA_LEN(frame, mic_len);
const uint8_t *key_data = EAPOL_KEY_DATA(frame, mic_len);
size_t expected_len;
uint8_t *buf;
@ -239,7 +252,7 @@ error:
*/
static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data,
size_t key_data_len,
struct eapol_key *out_frame)
struct eapol_key *out_frame, size_t mic_len)
{
switch (out_frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
@ -253,7 +266,8 @@ static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data,
while (key_data_len < 16 || key_data_len % 8)
key_data[key_data_len++] = 0x00;
if (!aes_wrap(kek, key_data, key_data_len, out_frame->key_data))
if (!aes_wrap(kek, key_data, key_data_len,
EAPOL_KEY_DATA(out_frame, mic_len)))
return false;
key_data_len += 8;
@ -261,26 +275,26 @@ static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data,
break;
}
out_frame->key_data_len = L_CPU_TO_BE16(key_data_len);
l_put_be16(key_data_len, EAPOL_KEY_DATA(out_frame, mic_len) - 2);
return true;
}
static void eapol_key_data_append(struct eapol_key *ek,
size_t mic_len,
enum handshake_kde selector,
const uint8_t *data, size_t data_len)
{
uint16_t key_data_len = L_BE16_TO_CPU(ek->key_data_len);
uint16_t key_data_len = EAPOL_KEY_DATA_LEN(ek, mic_len);
uint8_t *ptr = EAPOL_KEY_DATA(ek, mic_len);
ek->key_data[key_data_len++] = IE_TYPE_VENDOR_SPECIFIC;
ek->key_data[key_data_len++] = 4 + data_len; /* OUI + Data type + len */
l_put_be32(selector, ek->key_data + key_data_len);
ptr[key_data_len++] = IE_TYPE_VENDOR_SPECIFIC;
ptr[key_data_len++] = 4 + data_len;
l_put_be32(selector, ptr + key_data_len);
key_data_len += 4;
memcpy(ek->key_data + key_data_len, data, data_len);
memcpy(ptr + key_data_len, data, data_len);
key_data_len += data_len;
ek->key_data_len = L_CPU_TO_BE16(key_data_len);
l_put_be16(key_data_len, ek->key_data + mic_len);
}
#define VERIFY_PTK_COMMON(ek) \
@ -293,7 +307,7 @@ static void eapol_key_data_append(struct eapol_key *ek,
if (ek->error) \
return false \
bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek)
bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek, size_t mic_len)
{
/* Verify according to 802.11, Section 11.6.6.2 */
VERIFY_PTK_COMMON(ek);
@ -318,7 +332,9 @@ bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek)
VERIFY_IS_ZERO(ek->key_rsc);
VERIFY_IS_ZERO(ek->reserved);
VERIFY_IS_ZERO(ek->key_mic_data);
if (!util_mem_is_zero(EAPOL_KEY_MIC(ek), mic_len))
return false;
return true;
}
@ -545,9 +561,11 @@ static struct eapol_key *eapol_create_common(
size_t extra_len,
const uint8_t *extra_data,
int key_type,
bool is_wpa)
bool is_wpa,
size_t mic_len)
{
size_t to_alloc = sizeof(struct eapol_key);
size_t to_alloc = EAPOL_FRAME_LEN(mic_len);
struct eapol_key *out_frame = l_malloc(to_alloc + extra_len);
memset(out_frame, 0, to_alloc + extra_len);
@ -571,9 +589,11 @@ static struct eapol_key *eapol_create_common(
out_frame->key_replay_counter = L_CPU_TO_BE64(key_replay_counter);
memcpy(out_frame->key_nonce, snonce, sizeof(out_frame->key_nonce));
out_frame->key_data_len = L_CPU_TO_BE16(extra_len);
l_put_be16(extra_len, out_frame->key_data + mic_len);
if (extra_len)
memcpy(out_frame->key_data, extra_data, extra_len);
memcpy(EAPOL_KEY_DATA(out_frame, mic_len), extra_data,
extra_len);
return out_frame;
}
@ -585,18 +605,20 @@ struct eapol_key *eapol_create_ptk_2_of_4(
const uint8_t snonce[],
size_t extra_len,
const uint8_t *extra_data,
bool is_wpa)
bool is_wpa,
size_t mic_len)
{
return eapol_create_common(protocol, version, false, key_replay_counter,
snonce, extra_len, extra_data, 1,
is_wpa);
is_wpa, mic_len);
}
struct eapol_key *eapol_create_ptk_4_of_4(
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
uint64_t key_replay_counter,
bool is_wpa)
bool is_wpa,
size_t mic_len)
{
uint8_t snonce[32];
@ -604,14 +626,14 @@ struct eapol_key *eapol_create_ptk_4_of_4(
return eapol_create_common(protocol, version,
is_wpa ? false : true,
key_replay_counter, snonce, 0, NULL,
1, is_wpa);
1, is_wpa, mic_len);
}
struct eapol_key *eapol_create_gtk_2_of_2(
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
uint64_t key_replay_counter,
bool is_wpa, uint8_t wpa_key_id)
bool is_wpa, uint8_t wpa_key_id, size_t mic_len)
{
uint8_t snonce[32];
struct eapol_key *step2;
@ -619,7 +641,7 @@ struct eapol_key *eapol_create_gtk_2_of_2(
memset(snonce, 0, sizeof(snonce));
step2 = eapol_create_common(protocol, version, true,
key_replay_counter, snonce, 0, NULL,
0, is_wpa);
0, is_wpa, mic_len);
if (!step2)
return step2;
@ -694,6 +716,7 @@ struct eapol_sm {
uint8_t installed_gtk[CRYPTO_MAX_GTK_LEN];
uint8_t installed_igtk_len;
uint8_t installed_igtk[CRYPTO_MAX_IGTK_LEN];
unsigned int mic_len;
};
static void eapol_sm_destroy(void *value)
@ -892,7 +915,7 @@ static void eapol_send_ptk_1_of_4(struct eapol_sm *sm)
sm->replay_counter++;
memset(ek, 0, sizeof(struct eapol_key));
memset(ek, 0, EAPOL_FRAME_LEN(sm->mic_len));
ek->header.protocol_version = sm->protocol_version;
ek->header.packet_type = 0x3;
ek->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211;
@ -907,10 +930,11 @@ static void eapol_send_ptk_1_of_4(struct eapol_sm *sm)
/* Write the PMKID KDE into Key Data field unencrypted */
crypto_derive_pmkid(sm->handshake->pmk, sm->handshake->spa, aa,
pmkid, false);
eapol_key_data_append(ek, HANDSHAKE_KDE_PMKID, pmkid, 16);
ek->header.packet_len = L_CPU_TO_BE16(sizeof(struct eapol_key) +
L_BE16_TO_CPU(ek->key_data_len) - 4);
eapol_key_data_append(ek, sm->mic_len, HANDSHAKE_KDE_PMKID, pmkid, 16);
ek->header.packet_len = L_CPU_TO_BE16(EAPOL_FRAME_LEN(sm->mic_len) +
EAPOL_KEY_DATA_LEN(ek, sm->mic_len) - 4);
l_debug("STA: "MAC" retries=%u", MAC_STR(sm->handshake->spa),
sm->frame_retry);
@ -938,7 +962,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
{
const struct crypto_ptk *ptk;
struct eapol_key *step2;
uint8_t mic[16];
uint8_t mic[MIC_MAXLEN];
uint8_t *ies;
size_t ies_len;
const uint8_t *own_ie = sm->handshake->supplicant_ie;
@ -947,11 +971,11 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
l_debug("ifindex=%u", sm->handshake->ifindex);
if (!eapol_verify_ptk_1_of_4(ek))
if (!eapol_verify_ptk_1_of_4(ek, sm->mic_len))
goto error_unspecified;
pmkid = handshake_util_find_pmkid_kde(ek->key_data,
L_BE16_TO_CPU(ek->key_data_len));
pmkid = handshake_util_find_pmkid_kde(EAPOL_KEY_DATA(ek, sm->mic_len),
EAPOL_KEY_DATA_LEN(ek, sm->mic_len));
ie_parse_rsne_from_data(own_ie, own_ie[1] + 2, &rsn_info);
@ -1058,12 +1082,12 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
ek->key_descriptor_version,
L_BE64_TO_CPU(ek->key_replay_counter),
sm->handshake->snonce, ies_len, ies,
sm->handshake->wpa_ie);
sm->handshake->wpa_ie, sm->mic_len);
ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step2, mic)) {
step2, mic, sm->mic_len)) {
l_info("MIC calculation failed. "
"Ensure Kernel Crypto is available.");
l_free(step2);
@ -1072,7 +1096,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
return;
}
memcpy(step2->key_mic_data, mic, sizeof(mic));
memcpy(EAPOL_KEY_MIC(step2), mic, sm->mic_len);
eapol_sm_write(sm, (struct eapol_frame *) step2, false);
l_free(step2);
@ -1105,7 +1129,7 @@ static void eapol_send_ptk_3_of_4(struct eapol_sm *sm)
sm->replay_counter++;
memset(ek, 0, sizeof(struct eapol_key));
memset(ek, 0, EAPOL_FRAME_LEN(sm->mic_len));
ek->header.protocol_version = sm->protocol_version;
ek->header.packet_type = 0x3;
ek->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211;
@ -1151,15 +1175,16 @@ static void eapol_send_ptk_3_of_4(struct eapol_sm *sm)
}
if (!eapol_encrypt_key_data(ptk->kek, key_data_buf,
key_data_len, ek))
key_data_len, ek, sm->mic_len))
return;
key_data_len = L_BE16_TO_CPU(ek->key_data_len);
ek->header.packet_len = L_CPU_TO_BE16(sizeof(struct eapol_key) +
key_data_len - 4);
key_data_len = EAPOL_KEY_DATA_LEN(ek, sm->mic_len);
ek->header.packet_len = L_CPU_TO_BE16(EAPOL_FRAME_LEN(sm->mic_len) +
key_data_len - 4);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck, ek,
ek->key_mic_data))
EAPOL_KEY_MIC(ek), sm->mic_len))
return;
l_debug("STA: "MAC" retries=%u", MAC_STR(sm->handshake->spa),
@ -1239,15 +1264,16 @@ static void eapol_handle_ptk_2_of_4(struct eapol_sm *sm,
ek->key_nonce, ptk, ptk_size, false))
return;
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek))
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek,
sm->mic_len))
return;
/*
* 12.7.6.3 b) 2) "the Authenticator checks that the RSNE bitwise
* matches that from the (Re)Association Request frame.
*/
rsne = eapol_find_rsne(ek->key_data,
L_BE16_TO_CPU(ek->key_data_len), NULL);
rsne = eapol_find_rsne(EAPOL_KEY_DATA(ek, sm->mic_len),
EAPOL_KEY_DATA_LEN(ek, sm->mic_len), NULL);
if (!rsne || rsne[1] != sm->handshake->supplicant_ie[1] ||
memcmp(rsne + 2, sm->handshake->supplicant_ie + 2,
rsne[1])) {
@ -1292,7 +1318,7 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
{
const struct crypto_ptk *ptk;
struct eapol_key *step4;
uint8_t mic[16];
uint8_t mic[MIC_MAXLEN];
const uint8_t *gtk = NULL;
size_t gtk_len;
const uint8_t *igtk = NULL;
@ -1488,18 +1514,18 @@ retransmit:
step4 = eapol_create_ptk_4_of_4(sm->protocol_version,
ek->key_descriptor_version,
sm->replay_counter,
sm->handshake->wpa_ie);
sm->handshake->wpa_ie, sm->mic_len);
ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step4, mic)) {
step4, mic, sm->mic_len)) {
l_free(step4);
handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED);
return;
}
memcpy(step4->key_mic_data, mic, sizeof(mic));
memcpy(EAPOL_KEY_MIC(step4), mic, sm->mic_len);
eapol_sm_write(sm, (struct eapol_frame *) step4, false);
l_free(step4);
@ -1550,7 +1576,8 @@ static void eapol_handle_ptk_4_of_4(struct eapol_sm *sm,
if (L_BE64_TO_CPU(ek->key_replay_counter) != sm->replay_counter)
return;
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek))
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek,
sm->mic_len))
return;
l_timeout_remove(sm->timeout);
@ -1566,7 +1593,7 @@ static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm,
{
const struct crypto_ptk *ptk;
struct eapol_key *step2;
uint8_t mic[16];
uint8_t mic[MIC_MAXLEN];
const uint8_t *gtk;
size_t gtk_len;
uint8_t gtk_key_index;
@ -1634,18 +1661,19 @@ static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm,
step2 = eapol_create_gtk_2_of_2(sm->protocol_version,
ek->key_descriptor_version,
sm->replay_counter,
sm->handshake->wpa_ie, ek->wpa_key_id);
sm->handshake->wpa_ie, ek->wpa_key_id,
sm->mic_len);
ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step2, mic)) {
step2, mic, sm->mic_len)) {
l_free(step2);
handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED);
return;
}
memcpy(step2->key_mic_data, mic, sizeof(mic));
memcpy(EAPOL_KEY_MIC(step2), mic, sm->mic_len);
eapol_sm_write(sm, (struct eapol_frame *) step2, false);
l_free(step2);
@ -1687,7 +1715,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
ek = eapol_key_validate((const uint8_t *) frame,
sizeof(struct eapol_header) +
L_BE16_TO_CPU(frame->header.packet_len));
L_BE16_TO_CPU(frame->header.packet_len),
sm->mic_len);
if (!ek)
return;
@ -1739,7 +1768,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
if (!sm->handshake->have_snonce)
return;
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek))
if (!eapol_verify_mic(sm->handshake->akm_suite, ptk->kck, ek,
sm->mic_len))
return;
}
@ -1751,11 +1781,11 @@ static void eapol_key_handle(struct eapol_sm *sm,
decrypted_key_data = eapol_decrypt_key_data(
sm->handshake->akm_suite, ptk->kek,
ek, &key_data_len);
ek, &key_data_len, sm->mic_len);
if (!decrypted_key_data)
return;
} else
key_data_len = L_BE16_TO_CPU(ek->key_data_len);
key_data_len = EAPOL_KEY_DATA_LEN(ek, sm->mic_len);
if (ek->key_type == 0) {
/* GTK handshake allowed only after PTK handshake complete */
@ -1782,7 +1812,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
goto done;
eapol_handle_ptk_3_of_4(sm, ek,
decrypted_key_data ?: ek->key_data,
decrypted_key_data ?:
EAPOL_KEY_DATA(ek, sm->mic_len),
key_data_len);
}
@ -1869,6 +1900,21 @@ static void eapol_eap_results_cb(const uint8_t *msk_data, size_t msk_len,
if (msk_len > sizeof(sm->handshake->pmk))
msk_len = sizeof(sm->handshake->pmk);
sm->mic_len = eapol_get_mic_length(sm->handshake->akm_suite);
switch (sm->handshake->akm_suite) {
case IE_RSN_AKM_SUITE_FT_OVER_8021X:
msk_len = 64;
break;
case IE_RSN_AKM_SUITE_8021X_SUITE_B_SHA384:
case IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384:
msk_len = 48;
break;
default:
msk_len = 32;
break;
}
handshake_state_set_pmk(sm->handshake, msk_data, msk_len);
return;
@ -1909,7 +1955,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);
frame_len, sm->mic_len);
if (!ek)
return;
@ -2069,6 +2115,8 @@ void eapol_register(struct eapol_sm *sm)
eapol_rx_auth_packet, sm);
sm->started = true;
/* Since AP/AdHoc only support AKM PSK we can hard code this */
sm->mic_len = 16;
/* kick off handshake */
eapol_ptk_1_of_4_retry(NULL, sm);
@ -2112,6 +2160,8 @@ bool eapol_start(struct eapol_sm *sm)
l_timeout_create(1, send_eapol_start, sm, NULL);
}
sm->mic_len = eapol_get_mic_length(sm->handshake->akm_suite);
/* Process any frames received early due to scheduling */
if (sm->early_frame) {
eapol_rx_packet(ETH_P_PAE, sm->handshake->aa,

View File

@ -52,15 +52,16 @@ typedef void (*eapol_frame_watch_func_t)(uint16_t proto, const uint8_t *from,
void *user_data);
bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
const struct eapol_key *frame, uint8_t *mic);
const struct eapol_key *frame, uint8_t *mic,
size_t mic_len);
bool eapol_verify_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,
const struct eapol_key *frame);
const struct eapol_key *frame, size_t mic_len);
uint8_t *eapol_decrypt_key_data(enum ie_rsn_akm_suite akm, const uint8_t *kek,
const struct eapol_key *frame,
size_t *decrypted_size);
size_t *decrypted_size, size_t mic_len);
bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek);
bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek, size_t mic_len);
bool eapol_verify_ptk_2_of_4(const struct eapol_key *ek);
bool eapol_verify_ptk_3_of_4(const struct eapol_key *ek, bool is_wpa);
bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek, bool is_wpa);
@ -74,19 +75,22 @@ struct eapol_key *eapol_create_ptk_2_of_4(
const uint8_t snonce[],
size_t extra_len,
const uint8_t *extra_data,
bool is_wpa);
bool is_wpa,
size_t mic_len);
struct eapol_key *eapol_create_ptk_4_of_4(
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
uint64_t key_replay_counter,
bool is_wpa);
bool is_wpa,
size_t mic_len);
struct eapol_key *eapol_create_gtk_2_of_2(
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
uint64_t key_replay_counter,
bool is_wpa, uint8_t wpa_key_id);
bool is_wpa, uint8_t wpa_key_id,
size_t mic_len);
void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto,
const uint8_t *frame, size_t len, bool noencrypt);

View File

@ -29,16 +29,24 @@
#include "src/eapolutil.h"
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len,
size_t mic_len)
{
const struct eapol_key *ek;
uint16_t key_data_len;
if (len < sizeof(struct eapol_key))
/*
* Since EAPOL_KEY_DATA_LEN actually gets the key data length bytes we
* have to check this first, otherwise we could potentially overrun the
* frame buffer
*/
if (len < EAPOL_FRAME_LEN(mic_len))
return NULL;
ek = (const struct eapol_key *) frame;
if (len < EAPOL_FRAME_LEN(mic_len) + EAPOL_KEY_DATA_LEN(ek, mic_len))
return NULL;
switch (ek->header.protocol_version) {
case EAPOL_PROTOCOL_VERSION_2001:
case EAPOL_PROTOCOL_VERSION_2004:
@ -69,9 +77,5 @@ const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
return NULL;
}
key_data_len = L_BE16_TO_CPU(ek->key_data_len);
if (len < sizeof(struct eapol_key) + key_data_len)
return NULL;
return ek;
}

View File

@ -59,6 +59,18 @@ struct eapol_frame {
uint8_t data[0];
} __attribute__ ((packed));
/* gets pointer to MIC */
#define EAPOL_KEY_MIC(ek) ((ek)->key_data)
/* get key data length */
#define EAPOL_KEY_DATA_LEN(ek, mic_len) l_get_be16((ek)->key_data + (mic_len))
/* gets pointer to key data */
#define EAPOL_KEY_DATA(ek, mic_len) ((ek)->key_data + (mic_len) + 2)
/* gets frame length (not including key data) */
#define EAPOL_FRAME_LEN(mic_len) sizeof(struct eapol_key) + (mic_len) + 2
struct eapol_key {
struct eapol_header header;
uint8_t descriptor_type;
@ -98,9 +110,8 @@ struct eapol_key {
uint8_t eapol_key_iv[16];
uint8_t key_rsc[8];
uint8_t reserved[8];
uint8_t key_mic_data[16];
__be16 key_data_len;
uint8_t key_data[0];
} __attribute__ ((packed));
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len);
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len,
size_t mic_len);