mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-24 06:52:37 +01:00
eapol: Handle the Group Key Handshake
This commit is contained in:
parent
1795105c60
commit
a8c0f20510
131
src/eapol.c
131
src/eapol.c
@ -369,6 +369,50 @@ bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool eapol_verify_gtk_1_of_2(const struct eapol_key *ek, bool is_wpa)
|
||||||
|
{
|
||||||
|
uint16_t key_len;
|
||||||
|
|
||||||
|
if (ek->key_type)
|
||||||
|
return false;
|
||||||
|
if (ek->smk_message)
|
||||||
|
return false;
|
||||||
|
if (ek->request)
|
||||||
|
return false;
|
||||||
|
if (ek->error)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ek->key_ack)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ek->key_mic)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ek->secure)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Must be encrypted when GTK is present but reserved in WPA */
|
||||||
|
if (!ek->encrypted_key_data && !is_wpa)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
key_len = L_BE16_TO_CPU(ek->key_length);
|
||||||
|
if (key_len == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
VERIFY_IS_ZERO(ek->reserved);
|
||||||
|
|
||||||
|
/* 0 (Version 2) or random (Version 1) */
|
||||||
|
if (ek->key_descriptor_version ==
|
||||||
|
EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES)
|
||||||
|
VERIFY_IS_ZERO(ek->eapol_key_iv);
|
||||||
|
|
||||||
|
/* Key ID shall not be 0 */
|
||||||
|
if (is_wpa && !ek->wpa_key_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct eapol_key *eapol_create_common(
|
static struct eapol_key *eapol_create_common(
|
||||||
enum eapol_protocol_version protocol,
|
enum eapol_protocol_version protocol,
|
||||||
enum eapol_key_descriptor_version version,
|
enum eapol_key_descriptor_version version,
|
||||||
@ -376,7 +420,8 @@ static struct eapol_key *eapol_create_common(
|
|||||||
uint64_t key_replay_counter,
|
uint64_t key_replay_counter,
|
||||||
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,
|
||||||
|
int key_type)
|
||||||
{
|
{
|
||||||
size_t to_alloc = sizeof(struct eapol_key);
|
size_t to_alloc = sizeof(struct eapol_key);
|
||||||
struct eapol_key *out_frame = l_malloc(to_alloc + extra_len);
|
struct eapol_key *out_frame = l_malloc(to_alloc + extra_len);
|
||||||
@ -388,7 +433,7 @@ static struct eapol_key *eapol_create_common(
|
|||||||
out_frame->packet_len = L_CPU_TO_BE16(to_alloc + extra_len - 4);
|
out_frame->packet_len = L_CPU_TO_BE16(to_alloc + extra_len - 4);
|
||||||
out_frame->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211;
|
out_frame->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211;
|
||||||
out_frame->key_descriptor_version = version;
|
out_frame->key_descriptor_version = version;
|
||||||
out_frame->key_type = true;
|
out_frame->key_type = key_type;
|
||||||
out_frame->install = false;
|
out_frame->install = false;
|
||||||
out_frame->key_ack = false;
|
out_frame->key_ack = false;
|
||||||
out_frame->key_mic = true;
|
out_frame->key_mic = true;
|
||||||
@ -415,7 +460,7 @@ struct eapol_key *eapol_create_ptk_2_of_4(
|
|||||||
const uint8_t *extra_data)
|
const uint8_t *extra_data)
|
||||||
{
|
{
|
||||||
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);
|
snonce, extra_len, extra_data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct eapol_key *eapol_create_ptk_4_of_4(
|
struct eapol_key *eapol_create_ptk_4_of_4(
|
||||||
@ -427,7 +472,20 @@ struct eapol_key *eapol_create_ptk_4_of_4(
|
|||||||
|
|
||||||
memset(snonce, 0, sizeof(snonce));
|
memset(snonce, 0, sizeof(snonce));
|
||||||
return eapol_create_common(protocol, version, true, key_replay_counter,
|
return eapol_create_common(protocol, version, true, key_replay_counter,
|
||||||
snonce, 0, NULL);
|
snonce, 0, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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)
|
||||||
|
{
|
||||||
|
uint8_t snonce[32];
|
||||||
|
|
||||||
|
memset(snonce, 0, sizeof(snonce));
|
||||||
|
return eapol_create_common(protocol, version, true,
|
||||||
|
key_replay_counter, snonce, 0, NULL,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct eapol_sm {
|
struct eapol_sm {
|
||||||
@ -860,6 +918,61 @@ fail:
|
|||||||
l_free(step4);
|
l_free(step4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eapol_handle_gtk_1_of_2(uint32_t ifindex,
|
||||||
|
struct eapol_sm *sm,
|
||||||
|
const struct eapol_key *ek,
|
||||||
|
const uint8_t *decrypted_key_data,
|
||||||
|
size_t decrypted_key_data_size,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct crypto_ptk *ptk = (struct crypto_ptk *) sm->ptk;
|
||||||
|
struct eapol_key *step2;
|
||||||
|
uint8_t mic[16];
|
||||||
|
const uint8_t *gtk;
|
||||||
|
size_t gtk_len;
|
||||||
|
uint8_t gtk_key_index;
|
||||||
|
|
||||||
|
if (!eapol_verify_gtk_1_of_2(ek, sm->wpa_ie)) {
|
||||||
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk = eapol_find_gtk_kde(decrypted_key_data,
|
||||||
|
decrypted_key_data_size,
|
||||||
|
>k_len);
|
||||||
|
|
||||||
|
if (!gtk || gtk_len < 8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_key_index = util_bit_field(gtk[0], 0, 2);
|
||||||
|
gtk += 2;
|
||||||
|
gtk_len -= 2;
|
||||||
|
|
||||||
|
step2 = eapol_create_gtk_2_of_2(protocol_version,
|
||||||
|
ek->key_descriptor_version,
|
||||||
|
sm->replay_counter);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 802.11-2012, Section 11.6.7.3, step b):
|
||||||
|
* Verifies that the MIC is valid, i.e., it uses the KCK that is
|
||||||
|
* part of the PTK to verify that there is no data integrity error.
|
||||||
|
*/
|
||||||
|
ptk = (struct crypto_ptk *) sm->ptk;
|
||||||
|
|
||||||
|
if (!eapol_calculate_mic(ptk->kck, step2, mic))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
memcpy(step2->key_mic_data, mic, sizeof(mic));
|
||||||
|
tx_packet(ifindex, sm->aa, sm->spa, step2, user_data);
|
||||||
|
|
||||||
|
if (install_gtk)
|
||||||
|
install_gtk(sm->ifindex, gtk_key_index, gtk, gtk_len,
|
||||||
|
ek->key_rsc, 6, sm->ap_ie, sm->user_data);
|
||||||
|
|
||||||
|
done:
|
||||||
|
l_free(step2);
|
||||||
|
}
|
||||||
|
|
||||||
static struct eapol_sm *eapol_find_sm(uint32_t ifindex,
|
static struct eapol_sm *eapol_find_sm(uint32_t ifindex,
|
||||||
const uint8_t *spa,
|
const uint8_t *spa,
|
||||||
const uint8_t *aa)
|
const uint8_t *aa)
|
||||||
@ -947,9 +1060,15 @@ void __eapol_rx_packet(uint32_t ifindex, const uint8_t *spa, const uint8_t *aa,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Handle Group Key Handshake */
|
/* Check if this is the group key handshake */
|
||||||
if (ek->key_type == 0)
|
if (ek->key_type == 0) {
|
||||||
|
if (!ek->key_mic || !ek->secure)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
eapol_handle_gtk_1_of_2(ifindex, sm, ek, decrypted_key_data,
|
||||||
|
decrypted_key_data_len, user_data);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* If no MIC, then assume packet 1, otherwise packet 3 */
|
/* If no MIC, then assume packet 1, otherwise packet 3 */
|
||||||
if (!ek->key_mic)
|
if (!ek->key_mic)
|
||||||
|
@ -64,7 +64,7 @@ struct eapol_key {
|
|||||||
uint8_t reserved2:2;
|
uint8_t reserved2:2;
|
||||||
uint8_t key_descriptor_version:3;
|
uint8_t key_descriptor_version:3;
|
||||||
bool key_type:1;
|
bool key_type:1;
|
||||||
uint8_t reserved1:2;
|
uint8_t wpa_key_id:2; /* Bits 4-5 reserved in RSN, Key ID in WPA */
|
||||||
bool install:1;
|
bool install:1;
|
||||||
bool key_ack:1;
|
bool key_ack:1;
|
||||||
#elif defined (__BIG_ENDIAN_BITFIELD)
|
#elif defined (__BIG_ENDIAN_BITFIELD)
|
||||||
@ -77,7 +77,7 @@ struct eapol_key {
|
|||||||
bool key_mic:1;
|
bool key_mic:1;
|
||||||
bool key_ack:1;
|
bool key_ack:1;
|
||||||
bool install:1;
|
bool install:1;
|
||||||
uint8_t reserved1:2;
|
uint8_t wpa_key_id:2; /* Bits 4-5 reserved in RSN, Key ID in WPA */
|
||||||
bool key_type:1;
|
bool key_type:1;
|
||||||
uint8_t key_descriptor_version:3;
|
uint8_t key_descriptor_version:3;
|
||||||
#else
|
#else
|
||||||
@ -125,6 +125,7 @@ bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek);
|
|||||||
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 eapol_verify_ptk_3_of_4(const struct eapol_key *ek);
|
||||||
bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek);
|
bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek);
|
||||||
|
bool eapol_verify_gtk_1_of_2(const struct eapol_key *ek, bool is_wpa);
|
||||||
|
|
||||||
struct eapol_key *eapol_create_ptk_2_of_4(
|
struct eapol_key *eapol_create_ptk_2_of_4(
|
||||||
enum eapol_protocol_version protocol,
|
enum eapol_protocol_version protocol,
|
||||||
|
Loading…
Reference in New Issue
Block a user