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:
parent
80d4e9b572
commit
374b367ba4
@ -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,
|
||||
|
216
src/eapol.c
216
src/eapol.c
@ -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 = 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,
|
||||
|
18
src/eapol.h
18
src/eapol.h
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user