iwd/src/eapol.c

911 lines
20 KiB
C
Raw Normal View History

/*
*
* Wireless daemon for Linux
*
* Copyright (C) 2013-2014 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>
#include <ell/ell.h>
2014-12-28 05:37:39 +01:00
#include "sha1.h"
2015-02-19 03:51:54 +01:00
#include "crypto.h"
#include "eapol.h"
2015-02-25 00:11:56 +01:00
#include "ie.h"
struct l_queue *state_machines;
2015-02-24 18:10:42 +01:00
eapol_tx_packet_func_t tx_packet = NULL;
2015-02-24 18:09:42 +01:00
eapol_get_nonce_func_t get_nonce = NULL;
2015-02-24 18:08:03 +01:00
enum eapol_protocol_version protocol_version = EAPOL_PROTOCOL_VERSION_2004;
2014-12-28 05:31:03 +01:00
#define VERIFY_IS_ZERO(field) \
do { \
unsigned int i; \
for (i = 0; i < sizeof(field); i++) \
if ((field)[i] != 0) \
return false; \
} while (false) \
2014-12-28 05:37:39 +01:00
/*
* 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(const uint8_t *kck, const struct eapol_key *frame,
uint8_t *mic)
{
size_t frame_len = sizeof(struct eapol_key);
frame_len += L_BE16_TO_CPU(frame->key_data_len);
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
2015-02-13 21:31:23 +01:00
return hmac_md5(kck, 16, frame, frame_len, mic, 16);
2014-12-28 05:37:39 +01:00
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
2015-02-13 21:31:23 +01:00
return hmac_sha1(kck, 16, frame, frame_len, mic, 16);
2014-12-28 05:37:39 +01:00
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
return cmac_aes(kck, 16, frame, frame_len, mic, 16);
2014-12-28 05:37:39 +01:00
default:
return false;
}
}
2015-02-19 04:13:09 +01:00
bool eapol_verify_mic(const uint8_t *kck, const struct eapol_key *frame)
{
size_t frame_len = sizeof(struct eapol_key);
uint8_t mic[16];
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);
memset(mic, 0, sizeof(mic));
iov[1].iov_base = mic;
iov[1].iov_len = sizeof(mic);
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) +
2015-02-19 04:13:09 +01:00
L_BE16_TO_CPU(frame->key_data_len);
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
checksum = l_checksum_new_hmac(L_CHECKSUM_MD5, kck, 16);
break;
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
checksum = l_checksum_new_hmac(L_CHECKSUM_SHA1, kck, 16);
break;
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
checksum = l_checksum_new_cmac_aes(kck, 16);
break;
default:
return false;
}
if (checksum == NULL)
return false;
l_checksum_updatev(checksum, iov, 3);
l_checksum_get_digest(checksum, mic, 16);
l_free(checksum);
if (!memcmp(frame->key_mic_data, mic, 16))
return true;
return false;
}
2015-02-14 03:37:17 +01:00
uint8_t *eapol_decrypt_key_data(const uint8_t *kek,
const struct eapol_key *frame,
size_t *decrypted_size)
2015-02-14 03:37:17 +01:00
{
size_t key_data_len = L_BE16_TO_CPU(frame->key_data_len);
const uint8_t *key_data = frame->key_data;
size_t expected_len;
2015-02-14 03:37:17 +01:00
uint8_t *buf;
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
expected_len = key_data_len;
2015-02-14 03:37:17 +01:00
break;
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
expected_len = key_data_len - 8;
2015-02-14 03:37:17 +01:00
break;
default:
return NULL;
};
buf = l_new(uint8_t, expected_len);
2015-02-14 03:37:17 +01:00
switch (frame->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
{
uint8_t key[32];
bool ret;
memcpy(key, frame->eapol_key_iv, 16);
memcpy(key + 16, kek, 16);
ret = arc4_skip(key, 32, 256, key_data, key_data_len, buf);
memset(key, 0, sizeof(key));
if (!ret)
goto error;
break;
}
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
if (key_data_len < 8 || key_data_len % 8)
goto error;
if (!aes_unwrap(kek, key_data, key_data_len, buf))
goto error;
break;
2015-02-14 03:37:17 +01:00
}
if (decrypted_size)
*decrypted_size = expected_len;
2015-02-14 03:37:17 +01:00
return buf;
error:
l_free(buf);
return NULL;
2015-02-14 03:37:17 +01:00
}
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
2014-12-24 20:43:59 +01:00
{
const struct eapol_key *ek;
2014-12-24 20:43:59 +01:00
uint16_t key_data_len;
if (len < sizeof(struct eapol_key))
return NULL;
2014-12-24 20:43:59 +01:00
ek = (const struct eapol_key *) frame;
2014-12-24 20:43:59 +01:00
if (ek->protocol_version != EAPOL_PROTOCOL_VERSION_2001 &&
ek->protocol_version != EAPOL_PROTOCOL_VERSION_2004)
return NULL;
2014-12-24 20:43:59 +01:00
if (ek->packet_type != 3)
return NULL;
2014-12-24 20:43:59 +01:00
switch (ek->descriptor_type) {
case EAPOL_DESCRIPTOR_TYPE_RC4:
case EAPOL_DESCRIPTOR_TYPE_80211:
case EAPOL_DESCRIPTOR_TYPE_WPA:
break;
default:
return NULL;
2014-12-24 20:43:59 +01:00
}
2014-12-24 22:04:22 +01:00
switch (ek->key_descriptor_version) {
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4:
case EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES:
case EAPOL_KEY_DESCRIPTOR_VERSION_AES_128_CMAC_AES:
break;
default:
return NULL;
2014-12-24 22:04:22 +01:00
}
2014-12-24 20:43:59 +01:00
key_data_len = L_BE16_TO_CPU(ek->key_data_len);
if (len < sizeof(struct eapol_key) + key_data_len)
return NULL;
2014-12-24 20:43:59 +01:00
return ek;
2014-12-24 20:43:59 +01:00
}
2014-12-28 05:31:03 +01:00
#define VERIFY_PTK_COMMON(ek) \
if (!ek->key_type) \
return false; \
if (ek->smk_message) \
return false; \
if (ek->request) \
return false; \
if (ek->error) \
return false \
bool eapol_verify_ptk_1_of_4(const struct eapol_key *ek)
2014-12-28 05:31:03 +01:00
{
/* Verify according to 802.11, Section 11.6.6.2 */
VERIFY_PTK_COMMON(ek);
2014-12-28 05:31:03 +01:00
if (ek->install)
return false;
2014-12-28 05:31:03 +01:00
if (!ek->key_ack)
return false;
2014-12-28 05:31:03 +01:00
if (ek->key_mic)
return false;
2014-12-28 05:31:03 +01:00
if (ek->secure)
return false;
2014-12-28 05:31:03 +01:00
if (ek->encrypted_key_data)
return false;
2014-12-28 05:31:03 +01:00
VERIFY_IS_ZERO(ek->eapol_key_iv);
VERIFY_IS_ZERO(ek->key_rsc);
VERIFY_IS_ZERO(ek->reserved);
VERIFY_IS_ZERO(ek->key_mic_data);
return ek;
2014-12-28 05:31:03 +01:00
}
2014-12-28 05:32:07 +01:00
bool eapol_verify_ptk_2_of_4(const struct eapol_key *ek)
2014-12-28 05:32:07 +01:00
{
uint16_t key_len;
2015-02-13 23:12:43 +01:00
/* Verify according to 802.11, Section 11.6.6.3 */
VERIFY_PTK_COMMON(ek);
2014-12-28 05:32:07 +01:00
if (ek->install)
return false;
2014-12-28 05:32:07 +01:00
if (ek->key_ack)
return false;
2014-12-28 05:32:07 +01:00
if (!ek->key_mic)
return false;
2014-12-28 05:32:07 +01:00
if (ek->secure)
return false;
2014-12-28 05:32:07 +01:00
if (ek->encrypted_key_data)
return false;
2014-12-28 05:32:07 +01:00
key_len = L_BE16_TO_CPU(ek->key_length);
if (key_len != 0)
return false;
2014-12-28 05:32:07 +01:00
VERIFY_IS_ZERO(ek->eapol_key_iv);
VERIFY_IS_ZERO(ek->key_rsc);
VERIFY_IS_ZERO(ek->reserved);
return true;
2014-12-28 05:32:07 +01:00
}
2014-12-28 05:33:46 +01:00
bool eapol_verify_ptk_3_of_4(const struct eapol_key *ek)
2015-02-13 23:36:52 +01:00
{
uint16_t key_len;
/* Verify according to 802.11, Section 11.6.6.4 */
VERIFY_PTK_COMMON(ek);
2015-02-13 23:36:52 +01:00
if (!ek->key_ack)
return false;
2015-02-13 23:36:52 +01:00
if (!ek->key_mic)
return false;
2015-02-13 23:36:52 +01:00
if (!ek->secure)
return false;
2015-02-13 23:36:52 +01:00
if (!ek->encrypted_key_data)
return false;
2015-02-13 23:36:52 +01:00
key_len = L_BE16_TO_CPU(ek->key_length);
if (key_len != 16)
return false;
2015-02-13 23:36:52 +01:00
VERIFY_IS_ZERO(ek->reserved);
/* 0 (Version 2) or random (Version 1) */
if (ek->key_descriptor_version ==
EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_MD5_ARC4)
VERIFY_IS_ZERO(ek->eapol_key_iv);
return true;
2015-02-13 23:36:52 +01:00
}
bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek)
2015-02-14 01:38:10 +01:00
{
uint16_t key_len;
/* Verify according to 802.11, Section 11.6.6.5 */
VERIFY_PTK_COMMON(ek);
2015-02-14 01:38:10 +01:00
if (ek->key_ack)
return false;
2015-02-14 01:38:10 +01:00
if (!ek->key_mic)
return false;
2015-02-14 01:38:10 +01:00
if (!ek->secure)
return false;
2015-02-14 01:38:10 +01:00
if (ek->encrypted_key_data)
return false;
2015-02-14 01:38:10 +01:00
key_len = L_BE16_TO_CPU(ek->key_length);
if (key_len != 0)
return false;
2015-02-14 01:38:10 +01:00
VERIFY_IS_ZERO(ek->key_nonce);
VERIFY_IS_ZERO(ek->eapol_key_iv);
VERIFY_IS_ZERO(ek->key_rsc);
VERIFY_IS_ZERO(ek->reserved);
return true;
2015-02-14 01:38:10 +01:00
}
2015-02-13 21:10:28 +01:00
static struct eapol_key *eapol_create_common(
2014-12-28 05:33:46 +01:00
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
2015-02-13 21:10:28 +01:00
bool secure,
uint64_t key_replay_counter,
2014-12-28 05:33:46 +01:00
const uint8_t snonce[],
size_t extra_len,
const uint8_t *extra_data)
{
size_t to_alloc = sizeof(struct eapol_key);
struct eapol_key *out_frame = l_malloc(to_alloc + extra_len);
memset(out_frame, 0, to_alloc + extra_len);
out_frame->protocol_version = protocol;
out_frame->packet_type = 0x3;
out_frame->packet_len = L_CPU_TO_BE16(to_alloc + extra_len - 4);
out_frame->descriptor_type = EAPOL_DESCRIPTOR_TYPE_80211;
out_frame->key_descriptor_version = version;
out_frame->key_type = true;
out_frame->install = false;
out_frame->key_ack = false;
out_frame->key_mic = true;
2015-02-13 21:10:28 +01:00
out_frame->secure = secure;
2014-12-28 05:33:46 +01:00
out_frame->error = false;
out_frame->request = false;
out_frame->encrypted_key_data = false;
out_frame->smk_message = false;
out_frame->key_length = 0;
out_frame->key_replay_counter = L_CPU_TO_BE64(key_replay_counter);
2014-12-28 05:33:46 +01:00
memcpy(out_frame->key_nonce, snonce, sizeof(out_frame->key_nonce));
out_frame->key_data_len = L_CPU_TO_BE16(extra_len);
memcpy(out_frame->key_data, extra_data, extra_len);
return out_frame;
}
2015-02-13 21:10:28 +01:00
struct eapol_key *eapol_create_ptk_2_of_4(
enum eapol_protocol_version protocol,
enum eapol_key_descriptor_version version,
uint64_t key_replay_counter,
const uint8_t snonce[],
size_t extra_len,
const uint8_t *extra_data)
{
return eapol_create_common(protocol, version, false, key_replay_counter,
snonce, extra_len, extra_data);
}
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)
2015-02-13 21:10:28 +01:00
{
uint8_t snonce[32];
memset(snonce, 0, sizeof(snonce));
2015-02-13 21:10:28 +01:00
return eapol_create_common(protocol, version, true, key_replay_counter,
snonce, 0, NULL);
}
2015-02-24 17:54:23 +01:00
struct eapol_sm {
uint32_t ifindex;
uint8_t sta_addr[6];
uint8_t aa_addr[6];
uint8_t *ap_rsn;
uint8_t *own_rsn;
2015-02-24 17:54:23 +01:00
uint8_t pmk[32];
uint64_t replay_counter;
uint8_t snonce[32];
uint8_t anonce[32];
uint8_t ptk[64];
bool have_snonce:1;
bool have_replay:1;
};
static void eapol_sm_destroy(void *value)
{
struct eapol_sm *sm = value;
l_free(sm->ap_rsn);
l_free(sm->own_rsn);
l_free(sm);
}
struct eapol_sm *eapol_sm_new()
{
struct eapol_sm *sm;
sm = l_new(struct eapol_sm, 1);
return sm;
}
void eapol_sm_free(struct eapol_sm *sm)
{
eapol_sm_destroy(sm);
}
2015-02-24 17:55:50 +01:00
void eapol_sm_set_sta_address(struct eapol_sm *sm, const uint8_t *sta_addr)
{
memcpy(sm->sta_addr, sta_addr, sizeof(sm->sta_addr));
}
2015-02-24 17:56:39 +01:00
void eapol_sm_set_aa_address(struct eapol_sm *sm, const uint8_t *aa_addr)
{
memcpy(sm->aa_addr, aa_addr, sizeof(sm->aa_addr));
}
2015-02-24 17:57:25 +01:00
void eapol_sm_set_pmk(struct eapol_sm *sm, const uint8_t *pmk)
{
memcpy(sm->pmk, pmk, sizeof(sm->pmk));
}
2015-02-24 17:58:03 +01:00
void eapol_sm_set_ap_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
size_t len)
{
if (rsn_ie[1] + 2u != len)
return;
2015-02-24 17:58:03 +01:00
l_free(sm->ap_rsn);
sm->ap_rsn = l_memdup(rsn_ie, len);
}
2015-02-24 17:58:43 +01:00
void eapol_sm_set_own_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
size_t len)
{
if (rsn_ie[1] + 2u != len)
return;
2015-02-24 17:58:43 +01:00
l_free(sm->own_rsn);
sm->own_rsn = l_memdup(rsn_ie, len);
}
2015-02-24 18:08:03 +01:00
void eapol_start(uint32_t ifindex, struct eapol_sm *sm)
2015-02-24 18:12:22 +01:00
{
sm->ifindex = ifindex;
l_queue_push_head(state_machines, sm);
2015-02-24 18:12:22 +01:00
}
static void eapol_handle_ptk_1_of_4(uint32_t ifindex, struct eapol_sm *sm,
const struct eapol_key *ek)
{
struct crypto_ptk *ptk = (struct crypto_ptk *) sm->ptk;
struct eapol_key *step2;
uint8_t mic[16];
if (!eapol_verify_ptk_1_of_4(ek))
return;
if (!sm->have_snonce) {
if (!get_nonce(sm->snonce))
return;
sm->have_snonce = true;
}
memcpy(sm->anonce, ek->key_nonce, sizeof(ek->key_nonce));
crypto_derive_pairwise_ptk(sm->pmk, sm->sta_addr, sm->aa_addr,
sm->anonce, sm->snonce,
ptk, sizeof(sm->ptk));
step2 = eapol_create_ptk_2_of_4(protocol_version,
ek->key_descriptor_version,
sm->replay_counter,
sm->snonce,
sm->own_rsn[1] + 2, sm->own_rsn);
if (!eapol_calculate_mic(ptk->kck, step2, mic))
goto fail;
memcpy(step2->key_mic_data, mic, sizeof(mic));
tx_packet(ifindex, sm->aa_addr, sm->sta_addr, step2);
fail:
l_free(step2);
}
2015-02-25 00:11:56 +01:00
static const uint8_t *eapol_find_gtk_kde(const uint8_t *data, size_t data_len,
size_t *out_gtk_len)
{
static const unsigned char gtk_oui[] = { 0x00, 0x0f, 0xac, 0x01 };
struct ie_tlv_iter iter;
const uint8_t *gtk;
unsigned int len;
ie_tlv_iter_init(&iter, data, data_len);
while (ie_tlv_iter_next(&iter)) {
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_VENDOR_SPECIFIC)
continue;
len = ie_tlv_iter_get_length(&iter);
if (len < 4) /* Take care of padding */
return NULL;
/* Check OUI */
gtk = ie_tlv_iter_get_data(&iter);
if (memcmp(gtk, gtk_oui, 4))
continue;
if (out_gtk_len)
*out_gtk_len = len - 4;
return gtk + 4;
}
return NULL;
}
static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len)
{
struct ie_tlv_iter iter;
ie_tlv_iter_init(&iter, data, data_len);
while (ie_tlv_iter_next(&iter)) {
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_RSN)
continue;
return ie_tlv_iter_get_data(&iter) - 2;
}
return NULL;
}
/*
* This function performs a match of the RSN IE obtained from the scan
* results vs the RSN IE obtained as part of the 4-way handshake. If they
* don't match, the EAPoL packet must be silently discarded.
*/
static bool eapol_ap_rsne_matches(const uint8_t *eapol_rsne,
const uint8_t *scan_rsne)
{
struct ie_rsn_info eapol_info;
struct ie_rsn_info scan_info;
/*
* First check that the sizes match, if they do, run a bitwise
* comparison.
*/
if (eapol_rsne[1] == scan_rsne[1] &&
!memcmp(eapol_rsne + 2, scan_rsne + 2, eapol_rsne[1]))
return true;
/*
* Otherwise we have to parse the RSN IEs and compare the individual
* fields
*/
if (ie_parse_rsne_from_data(eapol_rsne, eapol_rsne[1] + 2,
&eapol_info) < 0)
return false;
if (ie_parse_rsne_from_data(scan_rsne, scan_rsne[1] + 2,
&scan_info) < 0)
return false;
if (eapol_info.group_cipher != scan_info.group_cipher)
return false;
if (eapol_info.pairwise_ciphers != scan_info.pairwise_ciphers)
return false;
if (eapol_info.akm_suites != scan_info.akm_suites)
return false;
if (eapol_info.preauthentication != scan_info.preauthentication)
return false;
if (eapol_info.no_pairwise != scan_info.no_pairwise)
return false;
if (eapol_info.ptksa_replay_counter != scan_info.ptksa_replay_counter)
return false;
if (eapol_info.gtksa_replay_counter != scan_info.gtksa_replay_counter)
return false;
if (eapol_info.mfpr != scan_info.mfpr)
return false;
if (eapol_info.mfpc != scan_info.mfpc)
return false;
if (eapol_info.peerkey_enabled != scan_info.peerkey_enabled)
return false;
if (eapol_info.spp_a_msdu_capable != scan_info.spp_a_msdu_capable)
return false;
if (eapol_info.spp_a_msdu_required != scan_info.spp_a_msdu_required)
return false;
if (eapol_info.pbac != scan_info.pbac)
return false;
if (eapol_info.extended_key_id != scan_info.extended_key_id)
return false;
/* We don't check the PMKIDs since these might actually be different */
if (eapol_info.group_management_cipher !=
scan_info.group_management_cipher)
return false;
return true;
}
static void eapol_handle_ptk_3_of_4(uint32_t ifindex,
struct eapol_sm *sm,
const struct eapol_key *ek,
const uint8_t *decrypted_key_data,
size_t decrypted_key_data_size)
{
struct crypto_ptk *ptk = (struct crypto_ptk *) sm->ptk;
struct eapol_key *step4;
uint8_t mic[16];
2015-02-25 00:11:56 +01:00
const uint8_t *gtk;
size_t gtk_len;
const uint8_t *rsne;
if (!eapol_verify_ptk_3_of_4(ek))
return;
/*
* 11.6.6.4: "On reception of Message 3, the Supplicant silently
* discards the message if ... or if the ANonce value in Message 3
* differs from the ANonce value in Message 1"
*/
if (memcmp(sm->anonce, ek->key_nonce, sizeof(ek->key_nonce)))
return;
/*
* 11.6.6.4: "Verifies the RSNE. If it is part of a Fast BSS Transition
* Initial Mobility Domain Association, see 12.4.2. Otherwise, if it is
* not identical to that the STA received in the Beacon or Probe
* Response frame, the STA shall disassociate.
*/
rsne = eapol_find_rsne(decrypted_key_data, decrypted_key_data_size);
if (!rsne)
return;
if (!eapol_ap_rsne_matches(rsne, sm->ap_rsn))
return;
/*
* TODO: Parse second RSNE
* 11.6.6.4: "If a second RSNE is provided in the message, the
* Supplicant uses the pairwise cipher suite specified in the second
* RSNE or deauthenticates."
*/
2015-02-25 00:11:56 +01:00
/*
* TODO: If group_cipher was negotiated, find the GTK and install it
*/
gtk = eapol_find_gtk_kde(decrypted_key_data, decrypted_key_data_size,
&gtk_len);
if (!gtk)
return;
step4 = eapol_create_ptk_4_of_4(protocol_version,
ek->key_descriptor_version,
sm->replay_counter);
if (!eapol_calculate_mic(ptk->kck, step4, mic))
goto fail;
memcpy(step4->key_mic_data, mic, sizeof(mic));
tx_packet(ifindex, sm->aa_addr, sm->sta_addr, step4);
fail:
l_free(step4);
}
static struct eapol_sm *eapol_find_sm(uint32_t ifindex,
const uint8_t *sta_addr,
const uint8_t *aa_addr)
{
const struct l_queue_entry *entry;
struct eapol_sm *sm;
for (entry = l_queue_get_entries(state_machines); entry;
entry = entry->next) {
sm = entry->data;
if (sm->ifindex != ifindex)
continue;
if (memcmp(sm->sta_addr, sta_addr, 6))
continue;
if (memcmp(sm->aa_addr, aa_addr, 6))
continue;
return sm;
}
return NULL;
}
void __eapol_rx_packet(uint32_t ifindex,
const uint8_t *sta_addr, const uint8_t *aa_addr,
const uint8_t *frame, size_t len)
2015-02-24 18:13:19 +01:00
{
const struct eapol_key *ek;
struct eapol_sm *sm;
struct crypto_ptk *ptk;
uint8_t *decrypted_key_data = NULL;
size_t decrypted_key_data_len;
2015-02-24 18:13:19 +01:00
uint64_t replay_counter;
ek = eapol_key_validate(frame, len);
if (!ek)
return;
sm = eapol_find_sm(ifindex, sta_addr, aa_addr);
2015-02-24 18:13:19 +01:00
/* Wrong direction */
if (!ek->key_ack)
return;
replay_counter = L_BE64_TO_CPU(ek->key_replay_counter);
/*
* 11.6.6.2: "If the Key Replay Counter field value is less than or
* equal to the current local value, the Supplicant discards the
* message.
*
* 11.6.6.4: "On reception of Message 3, the Supplicant silently
* discards the message if the Key Replay Counter field value has
* already been used...
*/
if (sm->have_replay && sm->replay_counter >= replay_counter)
return;
sm->replay_counter = replay_counter;
sm->have_replay = true;
ptk = (struct crypto_ptk *) sm->ptk;
if (ek->key_mic) {
/* Haven't received step 1 yet, so no ptk */
if (!sm->have_snonce)
return;
if (!eapol_verify_mic(ptk->kck, ek))
return;
}
if (ek->encrypted_key_data) {
/* Haven't received step 1 yet, so no ptk */
if (!sm->have_snonce)
return;
decrypted_key_data = eapol_decrypt_key_data(ptk->kek, ek,
&decrypted_key_data_len);
2015-02-24 18:13:19 +01:00
if (!decrypted_key_data)
return;
}
/* TODO: Handle Group Key Handshake */
if (ek->key_type == 0)
goto done;
/* If no MIC, then assume packet 1, otherwise packet 3 */
if (!ek->key_mic)
eapol_handle_ptk_1_of_4(ifindex, sm, ek);
else
eapol_handle_ptk_3_of_4(ifindex, sm, ek, decrypted_key_data,
decrypted_key_data_len);
2015-02-24 18:13:19 +01:00
done:
l_free(decrypted_key_data);
}
2015-02-24 18:10:42 +01:00
void __eapol_set_tx_packet_func(eapol_tx_packet_func_t func)
{
tx_packet = func;
}
2015-02-24 18:09:42 +01:00
void __eapol_set_get_nonce_func(eapol_get_nonce_func_t func)
{
get_nonce = func;
}
void __eapol_set_protocol_version(enum eapol_protocol_version version)
{
protocol_version = version;
}
struct l_io *eapol_open_pae(uint32_t index)
{
struct l_io *io;
struct sockaddr_ll sll;
int fd;
fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0);
if (fd < 0) {
l_error("Failed to create PAE socket %s (%d)",
strerror(errno), errno);
return NULL;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(ETH_P_PAE);
sll.sll_ifindex = index;
if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) {
l_error("Failed to bind PAE socket %s (%d)",
strerror(errno), errno);
close(fd);
return NULL;
}
io = l_io_new(fd);
if (!io) {
l_error("Failed to create IO handling for PAE socket ");
close(fd);
return NULL;
}
l_io_set_close_on_destroy(io, true);
return io;
}
2015-02-24 18:08:03 +01:00
bool eapol_init()
{
state_machines = l_queue_new();
2015-02-24 18:08:03 +01:00
protocol_version = EAPOL_PROTOCOL_VERSION_2004;
return true;
}
bool eapol_exit()
{
l_queue_destroy(state_machines, eapol_sm_destroy);
2015-02-24 18:09:42 +01:00
get_nonce = NULL;
2015-02-24 18:10:42 +01:00
tx_packet = NULL;
2015-02-24 18:08:03 +01:00
return true;
}