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) 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) if (!ek)
return; return;
@ -3872,16 +3872,16 @@ static void print_eapol_key(const void *data, uint32_t size)
print_attr(1, "Key RSC "); print_attr(1, "Key RSC ");
print_hexdump(2, ek->key_rsc, 8); print_hexdump(2, ek->key_rsc, 8);
print_attr(1, "Key MIC Data"); 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) { if (ek->encrypted_key_data) {
print_attr(1, "Key Data: len %d", print_attr(1, "Key Data: len %d", EAPOL_KEY_DATA_LEN(ek, 16));
L_BE16_TO_CPU(ek->key_data_len)); print_hexdump(2, EAPOL_KEY_DATA(ek, 16),
print_hexdump(2, ek->key_data, L_BE16_TO_CPU(ek->key_data_len)); EAPOL_KEY_DATA_LEN(ek, 16));
return; 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, static void netlink_str(char *str, size_t size,

View File

@ -56,36 +56,38 @@ uint32_t next_frame_watch_id;
return false; \ return false; \
} while (false) \ } while (false) \
#define MIC_MAXLEN 32
/* /*
* MIC calculation depends on the selected hash function. The has function * MIC calculation depends on the selected hash function. The has function
* is given in the EAPoL Key Descriptor Version field. * 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 * 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, 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); size_t frame_len = EAPOL_FRAME_LEN(mic_len) +
EAPOL_KEY_DATA_LEN(frame, mic_len);
frame_len += L_BE16_TO_CPU(frame->key_data_len);
switch (frame->key_descriptor_version) { switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4: 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: 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: 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: case EAPOL_KEY_DESCRIPTOR_VERSION_AKM_DEFINED:
switch (akm) { switch (akm) {
case IE_RSN_AKM_SUITE_SAE_SHA256: case IE_RSN_AKM_SUITE_SAE_SHA256:
case IE_RSN_AKM_SUITE_FT_OVER_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: 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: default:
return false; 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, 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[MIC_MAXLEN];
uint8_t mic[16];
struct iovec iov[3]; struct iovec iov[3];
struct l_checksum *checksum = NULL; struct l_checksum *checksum = NULL;
iov[0].iov_base = (void *) frame; 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)); memset(mic, 0, sizeof(mic));
iov[1].iov_base = mic; iov[1].iov_base = mic;
iov[1].iov_len = sizeof(mic); iov[1].iov_len = mic_len;
iov[2].iov_base = ((void *) frame) + iov[2].iov_base = (void *) EAPOL_KEY_DATA(frame, mic_len) - 2;
offsetof(struct eapol_key, key_data_len); iov[2].iov_len = EAPOL_KEY_DATA_LEN(frame, mic_len) + 2;
iov[2].iov_len = frame_len - offsetof(struct eapol_key, key_data_len) +
L_BE16_TO_CPU(frame->key_data_len);
switch (frame->key_descriptor_version) { switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4: 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; return false;
l_checksum_updatev(checksum, iov, 3); 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); l_checksum_free(checksum);
if (!memcmp(frame->key_mic_data, mic, 16)) if (!memcmp(frame->key_data, mic, mic_len))
return true; return true;
return false; 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, uint8_t *eapol_decrypt_key_data(enum ie_rsn_akm_suite akm, const uint8_t *kek,
const struct eapol_key *frame, 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); size_t key_data_len = EAPOL_KEY_DATA_LEN(frame, mic_len);
const uint8_t *key_data = frame->key_data; const uint8_t *key_data = EAPOL_KEY_DATA(frame, mic_len);
size_t expected_len; size_t expected_len;
uint8_t *buf; uint8_t *buf;
@ -239,7 +252,7 @@ error:
*/ */
static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data, static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data,
size_t key_data_len, 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) { switch (out_frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4: 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) while (key_data_len < 16 || key_data_len % 8)
key_data[key_data_len++] = 0x00; 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; return false;
key_data_len += 8; key_data_len += 8;
@ -261,26 +275,26 @@ static bool eapol_encrypt_key_data(const uint8_t *kek, uint8_t *key_data,
break; 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; return true;
} }
static void eapol_key_data_append(struct eapol_key *ek, static void eapol_key_data_append(struct eapol_key *ek,
size_t mic_len,
enum handshake_kde selector, enum handshake_kde selector,
const uint8_t *data, size_t data_len) 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; ptr[key_data_len++] = IE_TYPE_VENDOR_SPECIFIC;
ek->key_data[key_data_len++] = 4 + data_len; /* OUI + Data type + len */ ptr[key_data_len++] = 4 + data_len;
l_put_be32(selector, ek->key_data + key_data_len); l_put_be32(selector, ptr + key_data_len);
key_data_len += 4; key_data_len += 4;
memcpy(ptr + key_data_len, data, data_len);
memcpy(ek->key_data + key_data_len, data, data_len);
key_data_len += data_len; key_data_len += data_len;
l_put_be16(key_data_len, ek->key_data + mic_len);
ek->key_data_len = L_CPU_TO_BE16(key_data_len);
} }
#define VERIFY_PTK_COMMON(ek) \ #define VERIFY_PTK_COMMON(ek) \
@ -293,7 +307,7 @@ static void eapol_key_data_append(struct eapol_key *ek,
if (ek->error) \ if (ek->error) \
return false \ 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 according to 802.11, Section 11.6.6.2 */
VERIFY_PTK_COMMON(ek); 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->key_rsc);
VERIFY_IS_ZERO(ek->reserved); 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; return true;
} }
@ -545,9 +561,11 @@ static struct eapol_key *eapol_create_common(
size_t extra_len, size_t extra_len,
const uint8_t *extra_data, const uint8_t *extra_data,
int key_type, 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); struct eapol_key *out_frame = l_malloc(to_alloc + extra_len);
memset(out_frame, 0, 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); out_frame->key_replay_counter = L_CPU_TO_BE64(key_replay_counter);
memcpy(out_frame->key_nonce, snonce, sizeof(out_frame->key_nonce)); 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) 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; return out_frame;
} }
@ -585,18 +605,20 @@ struct eapol_key *eapol_create_ptk_2_of_4(
const uint8_t snonce[], const uint8_t snonce[],
size_t extra_len, size_t extra_len,
const uint8_t *extra_data, 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, return eapol_create_common(protocol, version, false, key_replay_counter,
snonce, extra_len, extra_data, 1, snonce, extra_len, extra_data, 1,
is_wpa); is_wpa, mic_len);
} }
struct eapol_key *eapol_create_ptk_4_of_4( struct eapol_key *eapol_create_ptk_4_of_4(
enum eapol_protocol_version protocol, enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version, enum eapol_key_descriptor_version version,
uint64_t key_replay_counter, uint64_t key_replay_counter,
bool is_wpa) bool is_wpa,
size_t mic_len)
{ {
uint8_t snonce[32]; uint8_t snonce[32];
@ -604,14 +626,14 @@ struct eapol_key *eapol_create_ptk_4_of_4(
return eapol_create_common(protocol, version, return eapol_create_common(protocol, version,
is_wpa ? false : true, is_wpa ? false : true,
key_replay_counter, snonce, 0, NULL, key_replay_counter, snonce, 0, NULL,
1, is_wpa); 1, is_wpa, mic_len);
} }
struct eapol_key *eapol_create_gtk_2_of_2( struct eapol_key *eapol_create_gtk_2_of_2(
enum eapol_protocol_version protocol, enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version, enum eapol_key_descriptor_version version,
uint64_t key_replay_counter, 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]; uint8_t snonce[32];
struct eapol_key *step2; struct eapol_key *step2;
@ -619,7 +641,7 @@ struct eapol_key *eapol_create_gtk_2_of_2(
memset(snonce, 0, sizeof(snonce)); memset(snonce, 0, sizeof(snonce));
step2 = eapol_create_common(protocol, version, true, step2 = eapol_create_common(protocol, version, true,
key_replay_counter, snonce, 0, NULL, key_replay_counter, snonce, 0, NULL,
0, is_wpa); 0, is_wpa, mic_len);
if (!step2) if (!step2)
return step2; return step2;
@ -694,6 +716,7 @@ struct eapol_sm {
uint8_t installed_gtk[CRYPTO_MAX_GTK_LEN]; uint8_t installed_gtk[CRYPTO_MAX_GTK_LEN];
uint8_t installed_igtk_len; uint8_t installed_igtk_len;
uint8_t installed_igtk[CRYPTO_MAX_IGTK_LEN]; uint8_t installed_igtk[CRYPTO_MAX_IGTK_LEN];
unsigned int mic_len;
}; };
static void eapol_sm_destroy(void *value) 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++; 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.protocol_version = sm->protocol_version;
ek->header.packet_type = 0x3; ek->header.packet_type = 0x3;
ek->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211; 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 */ /* Write the PMKID KDE into Key Data field unencrypted */
crypto_derive_pmkid(sm->handshake->pmk, sm->handshake->spa, aa, crypto_derive_pmkid(sm->handshake->pmk, sm->handshake->spa, aa,
pmkid, false); pmkid, false);
eapol_key_data_append(ek, HANDSHAKE_KDE_PMKID, pmkid, 16);
ek->header.packet_len = L_CPU_TO_BE16(sizeof(struct eapol_key) + eapol_key_data_append(ek, sm->mic_len, HANDSHAKE_KDE_PMKID, pmkid, 16);
L_BE16_TO_CPU(ek->key_data_len) - 4);
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), l_debug("STA: "MAC" retries=%u", MAC_STR(sm->handshake->spa),
sm->frame_retry); sm->frame_retry);
@ -938,7 +962,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
{ {
const struct crypto_ptk *ptk; const struct crypto_ptk *ptk;
struct eapol_key *step2; struct eapol_key *step2;
uint8_t mic[16]; uint8_t mic[MIC_MAXLEN];
uint8_t *ies; uint8_t *ies;
size_t ies_len; size_t ies_len;
const uint8_t *own_ie = sm->handshake->supplicant_ie; 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); 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; goto error_unspecified;
pmkid = handshake_util_find_pmkid_kde(ek->key_data, pmkid = handshake_util_find_pmkid_kde(EAPOL_KEY_DATA(ek, sm->mic_len),
L_BE16_TO_CPU(ek->key_data_len)); EAPOL_KEY_DATA_LEN(ek, sm->mic_len));
ie_parse_rsne_from_data(own_ie, own_ie[1] + 2, &rsn_info); 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, ek->key_descriptor_version,
L_BE64_TO_CPU(ek->key_replay_counter), L_BE64_TO_CPU(ek->key_replay_counter),
sm->handshake->snonce, ies_len, ies, sm->handshake->snonce, ies_len, ies,
sm->handshake->wpa_ie); sm->handshake->wpa_ie, sm->mic_len);
ptk = handshake_state_get_ptk(sm->handshake); ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck, if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step2, mic)) { step2, mic, sm->mic_len)) {
l_info("MIC calculation failed. " l_info("MIC calculation failed. "
"Ensure Kernel Crypto is available."); "Ensure Kernel Crypto is available.");
l_free(step2); l_free(step2);
@ -1072,7 +1096,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
return; 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); eapol_sm_write(sm, (struct eapol_frame *) step2, false);
l_free(step2); l_free(step2);
@ -1105,7 +1129,7 @@ static void eapol_send_ptk_3_of_4(struct eapol_sm *sm)
sm->replay_counter++; 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.protocol_version = sm->protocol_version;
ek->header.packet_type = 0x3; ek->header.packet_type = 0x3;
ek->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211; 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, if (!eapol_encrypt_key_data(ptk->kek, key_data_buf,
key_data_len, ek)) key_data_len, ek, sm->mic_len))
return; return;
key_data_len = L_BE16_TO_CPU(ek->key_data_len); key_data_len = EAPOL_KEY_DATA_LEN(ek, sm->mic_len);
ek->header.packet_len = L_CPU_TO_BE16(sizeof(struct eapol_key) +
key_data_len - 4); 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, if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck, ek,
ek->key_mic_data)) EAPOL_KEY_MIC(ek), sm->mic_len))
return; return;
l_debug("STA: "MAC" retries=%u", MAC_STR(sm->handshake->spa), 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)) ek->key_nonce, ptk, ptk_size, false))
return; 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; return;
/* /*
* 12.7.6.3 b) 2) "the Authenticator checks that the RSNE bitwise * 12.7.6.3 b) 2) "the Authenticator checks that the RSNE bitwise
* matches that from the (Re)Association Request frame. * matches that from the (Re)Association Request frame.
*/ */
rsne = eapol_find_rsne(ek->key_data, rsne = eapol_find_rsne(EAPOL_KEY_DATA(ek, sm->mic_len),
L_BE16_TO_CPU(ek->key_data_len), NULL); EAPOL_KEY_DATA_LEN(ek, sm->mic_len), NULL);
if (!rsne || rsne[1] != sm->handshake->supplicant_ie[1] || if (!rsne || rsne[1] != sm->handshake->supplicant_ie[1] ||
memcmp(rsne + 2, sm->handshake->supplicant_ie + 2, memcmp(rsne + 2, sm->handshake->supplicant_ie + 2,
rsne[1])) { rsne[1])) {
@ -1292,7 +1318,7 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
{ {
const struct crypto_ptk *ptk; const struct crypto_ptk *ptk;
struct eapol_key *step4; struct eapol_key *step4;
uint8_t mic[16]; uint8_t mic[MIC_MAXLEN];
const uint8_t *gtk = NULL; const uint8_t *gtk = NULL;
size_t gtk_len; size_t gtk_len;
const uint8_t *igtk = NULL; const uint8_t *igtk = NULL;
@ -1488,18 +1514,18 @@ retransmit:
step4 = eapol_create_ptk_4_of_4(sm->protocol_version, step4 = eapol_create_ptk_4_of_4(sm->protocol_version,
ek->key_descriptor_version, ek->key_descriptor_version,
sm->replay_counter, sm->replay_counter,
sm->handshake->wpa_ie); sm->handshake->wpa_ie, sm->mic_len);
ptk = handshake_state_get_ptk(sm->handshake); ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck, if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step4, mic)) { step4, mic, sm->mic_len)) {
l_free(step4); l_free(step4);
handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED); handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED);
return; 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); eapol_sm_write(sm, (struct eapol_frame *) step4, false);
l_free(step4); 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) if (L_BE64_TO_CPU(ek->key_replay_counter) != sm->replay_counter)
return; 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; return;
l_timeout_remove(sm->timeout); 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; const struct crypto_ptk *ptk;
struct eapol_key *step2; struct eapol_key *step2;
uint8_t mic[16]; uint8_t mic[MIC_MAXLEN];
const uint8_t *gtk; const uint8_t *gtk;
size_t gtk_len; size_t gtk_len;
uint8_t gtk_key_index; 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, step2 = eapol_create_gtk_2_of_2(sm->protocol_version,
ek->key_descriptor_version, ek->key_descriptor_version,
sm->replay_counter, 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); ptk = handshake_state_get_ptk(sm->handshake);
if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck, if (!eapol_calculate_mic(sm->handshake->akm_suite, ptk->kck,
step2, mic)) { step2, mic, sm->mic_len)) {
l_free(step2); l_free(step2);
handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED); handshake_failed(sm, MMPDU_REASON_CODE_UNSPECIFIED);
return; 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); eapol_sm_write(sm, (struct eapol_frame *) step2, false);
l_free(step2); l_free(step2);
@ -1687,7 +1715,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
ek = eapol_key_validate((const uint8_t *) frame, ek = eapol_key_validate((const uint8_t *) frame,
sizeof(struct eapol_header) + 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) if (!ek)
return; return;
@ -1739,7 +1768,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
if (!sm->handshake->have_snonce) if (!sm->handshake->have_snonce)
return; 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; return;
} }
@ -1751,11 +1781,11 @@ static void eapol_key_handle(struct eapol_sm *sm,
decrypted_key_data = eapol_decrypt_key_data( decrypted_key_data = eapol_decrypt_key_data(
sm->handshake->akm_suite, ptk->kek, sm->handshake->akm_suite, ptk->kek,
ek, &key_data_len); ek, &key_data_len, sm->mic_len);
if (!decrypted_key_data) if (!decrypted_key_data)
return; return;
} else } 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) { if (ek->key_type == 0) {
/* GTK handshake allowed only after PTK handshake complete */ /* GTK handshake allowed only after PTK handshake complete */
@ -1782,7 +1812,8 @@ static void eapol_key_handle(struct eapol_sm *sm,
goto done; goto done;
eapol_handle_ptk_3_of_4(sm, ek, 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); 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)) if (msk_len > sizeof(sm->handshake->pmk))
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); handshake_state_set_pmk(sm->handshake, msk_data, msk_len);
return; 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); size_t frame_len = 4 + L_BE16_TO_CPU(frame->header.packet_len);
const struct eapol_key *ek = eapol_key_validate((const void *) frame, const struct eapol_key *ek = eapol_key_validate((const void *) frame,
frame_len); frame_len, sm->mic_len);
if (!ek) if (!ek)
return; return;
@ -2069,6 +2115,8 @@ void eapol_register(struct eapol_sm *sm)
eapol_rx_auth_packet, sm); eapol_rx_auth_packet, sm);
sm->started = true; sm->started = true;
/* Since AP/AdHoc only support AKM PSK we can hard code this */
sm->mic_len = 16;
/* kick off handshake */ /* kick off handshake */
eapol_ptk_1_of_4_retry(NULL, sm); 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); 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 */ /* Process any frames received early due to scheduling */
if (sm->early_frame) { if (sm->early_frame) {
eapol_rx_packet(ETH_P_PAE, sm->handshake->aa, 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); void *user_data);
bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck, 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, 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, uint8_t *eapol_decrypt_key_data(enum ie_rsn_akm_suite akm, const uint8_t *kek,
const struct eapol_key *frame, 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_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_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); 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[], const uint8_t snonce[],
size_t extra_len, size_t extra_len,
const uint8_t *extra_data, const uint8_t *extra_data,
bool is_wpa); bool is_wpa,
size_t mic_len);
struct eapol_key *eapol_create_ptk_4_of_4( struct eapol_key *eapol_create_ptk_4_of_4(
enum eapol_protocol_version protocol, enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version, enum eapol_key_descriptor_version version,
uint64_t key_replay_counter, uint64_t key_replay_counter,
bool is_wpa); bool is_wpa,
size_t mic_len);
struct eapol_key *eapol_create_gtk_2_of_2( struct eapol_key *eapol_create_gtk_2_of_2(
enum eapol_protocol_version protocol, enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version, enum eapol_key_descriptor_version version,
uint64_t key_replay_counter, 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, void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto,
const uint8_t *frame, size_t len, bool noencrypt); const uint8_t *frame, size_t len, bool noencrypt);

View File

@ -29,16 +29,24 @@
#include "src/eapolutil.h" #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; 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; return NULL;
ek = (const struct eapol_key *) frame; 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) { switch (ek->header.protocol_version) {
case EAPOL_PROTOCOL_VERSION_2001: case EAPOL_PROTOCOL_VERSION_2001:
case EAPOL_PROTOCOL_VERSION_2004: 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; 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; return ek;
} }

View File

@ -59,6 +59,18 @@ struct eapol_frame {
uint8_t data[0]; uint8_t data[0];
} __attribute__ ((packed)); } __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_key {
struct eapol_header header; struct eapol_header header;
uint8_t descriptor_type; uint8_t descriptor_type;
@ -98,9 +110,8 @@ struct eapol_key {
uint8_t eapol_key_iv[16]; uint8_t eapol_key_iv[16];
uint8_t key_rsc[8]; uint8_t key_rsc[8];
uint8_t reserved[8]; uint8_t reserved[8];
uint8_t key_mic_data[16];
__be16 key_data_len;
uint8_t key_data[0]; uint8_t key_data[0];
} __attribute__ ((packed)); } __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);