2014-12-19 01:10:10 +01:00
|
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
* 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>
|
2015-02-26 14:31:26 +01:00
|
|
|
|
#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>
|
2014-12-19 01:10:10 +01:00
|
|
|
|
#include <ell/ell.h>
|
|
|
|
|
|
2015-02-19 03:51:54 +01:00
|
|
|
|
#include "crypto.h"
|
2014-12-19 01:10:10 +01:00
|
|
|
|
#include "eapol.h"
|
2015-02-25 00:11:56 +01:00
|
|
|
|
#include "ie.h"
|
2015-03-26 05:26:31 +01:00
|
|
|
|
#include "util.h"
|
2015-03-30 04:00:00 +02:00
|
|
|
|
#include "mpdu.h"
|
2015-10-30 11:12:20 +01:00
|
|
|
|
#include "eap.h"
|
2014-12-19 01:10:10 +01:00
|
|
|
|
|
2015-03-20 02:55:25 +01:00
|
|
|
|
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-03-26 04:35:12 +01:00
|
|
|
|
eapol_install_tk_func_t install_tk = NULL;
|
2015-03-26 05:26:31 +01:00
|
|
|
|
eapol_install_gtk_func_t install_gtk = NULL;
|
2015-03-30 03:30:14 +02:00
|
|
|
|
eapol_deauthenticate_func_t deauthenticate = NULL;
|
2016-06-23 00:49:15 +02:00
|
|
|
|
eapol_rekey_offload_func_t rekey_offload = NULL;
|
2015-02-24 18:08:03 +01:00
|
|
|
|
|
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:
|
2015-02-13 21:52:48 +01:00
|
|
|
|
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);
|
2015-02-24 17:42:20 +01:00
|
|
|
|
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,
|
2015-02-24 22:59:36 +01:00
|
|
|
|
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);
|
2015-02-18 00:39:23 +01:00
|
|
|
|
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:
|
2015-02-18 00:39:23 +01:00
|
|
|
|
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:
|
2015-02-18 00:39:23 +01:00
|
|
|
|
expected_len = key_data_len - 8;
|
2015-02-14 03:37:17 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return NULL;
|
|
|
|
|
};
|
|
|
|
|
|
2015-02-18 00:39:23 +01:00
|
|
|
|
buf = l_new(uint8_t, expected_len);
|
2015-02-14 03:37:17 +01:00
|
|
|
|
|
2015-02-18 00:39:23 +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
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 22:59:36 +01:00
|
|
|
|
if (decrypted_size)
|
|
|
|
|
*decrypted_size = expected_len;
|
|
|
|
|
|
2015-02-14 03:37:17 +01:00
|
|
|
|
return buf;
|
2015-02-18 00:39:23 +01:00
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
l_free(buf);
|
|
|
|
|
return NULL;
|
2015-02-14 03:37:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-22 16:58:23 +01:00
|
|
|
|
const struct eapol_key *eapol_key_validate(const uint8_t *frame, size_t len)
|
2014-12-24 20:43:59 +01:00
|
|
|
|
{
|
2015-01-22 16:58:23 +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))
|
2015-01-22 16:58:23 +01:00
|
|
|
|
return NULL;
|
2014-12-24 20:43:59 +01:00
|
|
|
|
|
2015-01-22 16:58:23 +01:00
|
|
|
|
ek = (const struct eapol_key *) frame;
|
2014-12-24 20:43:59 +01:00
|
|
|
|
|
2015-10-30 11:12:18 +01:00
|
|
|
|
if (ek->header.protocol_version != EAPOL_PROTOCOL_VERSION_2001 &&
|
|
|
|
|
ek->header.protocol_version !=
|
|
|
|
|
EAPOL_PROTOCOL_VERSION_2004)
|
2015-01-22 16:58:23 +01:00
|
|
|
|
return NULL;
|
2014-12-24 20:43:59 +01:00
|
|
|
|
|
2015-10-30 11:12:18 +01:00
|
|
|
|
if (ek->header.packet_type != 3)
|
2015-01-22 16:58:23 +01:00
|
|
|
|
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:
|
2015-01-22 16:58:23 +01:00
|
|
|
|
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:
|
2015-01-22 16:58:23 +01:00
|
|
|
|
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)
|
2015-01-22 16:58:23 +01:00
|
|
|
|
return NULL;
|
2014-12-24 20:43:59 +01:00
|
|
|
|
|
2015-01-22 16:58:23 +01:00
|
|
|
|
return ek;
|
2014-12-24 20:43:59 +01:00
|
|
|
|
}
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
2015-02-23 22:39:26 +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 */
|
2015-02-23 22:39:26 +01:00
|
|
|
|
VERIFY_PTK_COMMON(ek);
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
|
|
|
|
if (ek->install)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
|
|
|
|
if (!ek->key_ack)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
|
|
|
|
if (ek->key_mic)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
|
|
|
|
if (ek->secure)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
|
|
|
|
if (ek->encrypted_key_data)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
|
2015-05-06 05:26:11 +02:00
|
|
|
|
if (ek->wpa_key_id)
|
|
|
|
|
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);
|
|
|
|
|
|
2015-03-23 12:17:44 +01:00
|
|
|
|
return true;
|
2014-12-28 05:31:03 +01:00
|
|
|
|
}
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
2015-02-23 22:39:26 +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 */
|
2015-02-23 22:39:26 +01:00
|
|
|
|
VERIFY_PTK_COMMON(ek);
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
|
|
|
|
if (ek->install)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
|
|
|
|
if (ek->key_ack)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
|
|
|
|
if (!ek->key_mic)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
|
|
|
|
if (ek->secure)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
|
|
|
|
if (ek->encrypted_key_data)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
2015-05-06 05:26:11 +02:00
|
|
|
|
if (ek->wpa_key_id)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-12-28 05:32:07 +01:00
|
|
|
|
key_len = L_BE16_TO_CPU(ek->key_length);
|
|
|
|
|
if (key_len != 0)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
|
2015-02-13 23:36:24 +01:00
|
|
|
|
VERIFY_IS_ZERO(ek->eapol_key_iv);
|
|
|
|
|
VERIFY_IS_ZERO(ek->key_rsc);
|
|
|
|
|
VERIFY_IS_ZERO(ek->reserved);
|
|
|
|
|
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return true;
|
2014-12-28 05:32:07 +01:00
|
|
|
|
}
|
2014-12-28 05:33:46 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
bool eapol_verify_ptk_3_of_4(const struct eapol_key *ek, bool is_wpa)
|
2015-02-13 23:36:52 +01:00
|
|
|
|
{
|
|
|
|
|
uint16_t key_len;
|
|
|
|
|
|
|
|
|
|
/* Verify according to 802.11, Section 11.6.6.4 */
|
2015-02-23 22:39:26 +01:00
|
|
|
|
VERIFY_PTK_COMMON(ek);
|
2015-02-13 23:36:52 +01:00
|
|
|
|
|
2015-05-06 04:50:35 +02:00
|
|
|
|
/*
|
|
|
|
|
* TODO: Handle cases where install might be 0:
|
|
|
|
|
* For PTK generation, 0 only if the AP does not support key mapping
|
|
|
|
|
* keys, or if the STA has the No Pairwise bit (in the RSN Capabilities
|
|
|
|
|
* field) equal to 1 and only the group key is used.
|
|
|
|
|
*/
|
|
|
|
|
if (!ek->install)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-02-13 23:36:52 +01:00
|
|
|
|
if (!ek->key_ack)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-13 23:36:52 +01:00
|
|
|
|
|
|
|
|
|
if (!ek->key_mic)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-13 23:36:52 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (ek->secure != !is_wpa)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-13 23:36:52 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
/* Must be encrypted when GTK is present but reserved in WPA */
|
|
|
|
|
if (!ek->encrypted_key_data && !is_wpa)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-13 23:36:52 +01:00
|
|
|
|
|
2015-05-06 05:26:11 +02:00
|
|
|
|
if (ek->wpa_key_id)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-02-13 23:36:52 +01:00
|
|
|
|
key_len = L_BE16_TO_CPU(ek->key_length);
|
2015-05-18 13:31:39 +02:00
|
|
|
|
if (key_len != 16 && key_len != 32)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
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 ==
|
2015-04-29 01:00:22 +02:00
|
|
|
|
EAPOL_KEY_DESCRIPTOR_VERSION_HMAC_SHA1_AES)
|
2015-02-13 23:36:52 +01:00
|
|
|
|
VERIFY_IS_ZERO(ek->eapol_key_iv);
|
|
|
|
|
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return true;
|
2015-02-13 23:36:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
bool eapol_verify_ptk_4_of_4(const struct eapol_key *ek, bool is_wpa)
|
2015-02-14 01:38:10 +01:00
|
|
|
|
{
|
|
|
|
|
uint16_t key_len;
|
|
|
|
|
|
|
|
|
|
/* Verify according to 802.11, Section 11.6.6.5 */
|
2015-02-23 22:39:26 +01:00
|
|
|
|
VERIFY_PTK_COMMON(ek);
|
2015-02-14 01:38:10 +01:00
|
|
|
|
|
2015-05-06 04:50:35 +02:00
|
|
|
|
if (ek->install)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-02-14 01:38:10 +01:00
|
|
|
|
if (ek->key_ack)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-14 01:38:10 +01:00
|
|
|
|
|
|
|
|
|
if (!ek->key_mic)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-14 01:38:10 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (ek->secure != !is_wpa)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-14 01:38:10 +01:00
|
|
|
|
|
2015-05-06 05:01:53 +02:00
|
|
|
|
if (ek->encrypted_key_data)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return false;
|
2015-02-14 01:38:10 +01:00
|
|
|
|
|
2015-05-06 05:26:11 +02:00
|
|
|
|
if (ek->wpa_key_id)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-02-14 01:38:10 +01:00
|
|
|
|
key_len = L_BE16_TO_CPU(ek->key_length);
|
|
|
|
|
if (key_len != 0)
|
2015-02-23 22:39:26 +01:00
|
|
|
|
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);
|
|
|
|
|
|
2015-02-23 22:39:26 +01:00
|
|
|
|
return true;
|
2015-02-14 01:38:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 05:04:21 +02:00
|
|
|
|
#define VERIFY_GTK_COMMON(ek) \
|
|
|
|
|
if (ek->key_type) \
|
|
|
|
|
return false; \
|
|
|
|
|
if (ek->smk_message) \
|
|
|
|
|
return false; \
|
|
|
|
|
if (ek->request) \
|
|
|
|
|
return false; \
|
|
|
|
|
if (ek->error) \
|
|
|
|
|
return false; \
|
|
|
|
|
if (ek->install) \
|
|
|
|
|
return false \
|
|
|
|
|
|
2015-05-06 01:48:34 +02:00
|
|
|
|
bool eapol_verify_gtk_1_of_2(const struct eapol_key *ek, bool is_wpa)
|
|
|
|
|
{
|
|
|
|
|
uint16_t key_len;
|
|
|
|
|
|
2015-05-06 05:04:21 +02:00
|
|
|
|
VERIFY_GTK_COMMON(ek);
|
2015-05-06 04:50:35 +02:00
|
|
|
|
|
2015-05-06 01:48:34 +02:00
|
|
|
|
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);
|
|
|
|
|
|
2015-05-06 05:26:11 +02:00
|
|
|
|
/*
|
|
|
|
|
* WPA_80211_v3_1, Section 2.2.4:
|
|
|
|
|
* "Key Index (bits 4 and 5): specifies the key id of the temporal
|
|
|
|
|
* key of the key derived from the message. The value of this shall be
|
|
|
|
|
* zero (0) if the value of Key Type (bit 4) is Pairwise (1). The Key
|
|
|
|
|
* Type and Key Index shall not both be 0 in the same message.
|
|
|
|
|
*
|
|
|
|
|
* Group keys shall not use key id 0. This means that key ids 1 to 3
|
|
|
|
|
* are available to be used to identify Group keys. This document
|
|
|
|
|
* recommends that implementations reserve key ids 1 and 2 for Group
|
|
|
|
|
* Keys, and that key id 3 is not used.
|
|
|
|
|
*/
|
2015-05-06 01:48:34 +02:00
|
|
|
|
if (is_wpa && !ek->wpa_key_id)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 05:04:21 +02:00
|
|
|
|
bool eapol_verify_gtk_2_of_2(const struct eapol_key *ek, bool is_wpa)
|
|
|
|
|
{
|
|
|
|
|
uint16_t key_len;
|
|
|
|
|
|
|
|
|
|
/* Verify according to 802.11, Section 11.6.7.3 */
|
|
|
|
|
VERIFY_GTK_COMMON(ek);
|
|
|
|
|
|
|
|
|
|
if (ek->key_ack)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!ek->key_mic)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-05-18 13:31:41 +02:00
|
|
|
|
if (!ek->secure)
|
2015-05-06 05:04:21 +02:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ek->encrypted_key_data)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
key_len = L_BE16_TO_CPU(ek->key_length);
|
|
|
|
|
if (key_len != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
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-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,
|
2015-02-13 20:54:50 +01:00
|
|
|
|
uint64_t key_replay_counter,
|
2014-12-28 05:33:46 +01:00
|
|
|
|
const uint8_t snonce[],
|
|
|
|
|
size_t extra_len,
|
2015-05-06 01:48:34 +02:00
|
|
|
|
const uint8_t *extra_data,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
int key_type,
|
|
|
|
|
bool is_wpa)
|
2014-12-28 05:33:46 +01:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2015-10-30 11:12:18 +01:00
|
|
|
|
out_frame->header.protocol_version = protocol;
|
|
|
|
|
out_frame->header.packet_type = 0x3;
|
|
|
|
|
out_frame->header.packet_len = L_CPU_TO_BE16(to_alloc + extra_len - 4);
|
2015-05-06 01:48:35 +02:00
|
|
|
|
out_frame->descriptor_type = is_wpa ? EAPOL_DESCRIPTOR_TYPE_WPA :
|
|
|
|
|
EAPOL_DESCRIPTOR_TYPE_80211;
|
2014-12-28 05:33:46 +01:00
|
|
|
|
out_frame->key_descriptor_version = version;
|
2015-05-06 01:48:34 +02:00
|
|
|
|
out_frame->key_type = key_type;
|
2014-12-28 05:33:46 +01:00
|
|
|
|
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;
|
2015-02-13 20:54:50 +01:00
|
|
|
|
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,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
const uint8_t *extra_data,
|
|
|
|
|
bool is_wpa)
|
2015-02-13 21:10:28 +01:00
|
|
|
|
{
|
|
|
|
|
return eapol_create_common(protocol, version, false, key_replay_counter,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
snonce, extra_len, extra_data, 1,
|
|
|
|
|
is_wpa);
|
2015-02-13 21:10:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct eapol_key *eapol_create_ptk_4_of_4(
|
|
|
|
|
enum eapol_protocol_version protocol,
|
|
|
|
|
enum eapol_key_descriptor_version version,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
uint64_t key_replay_counter,
|
|
|
|
|
bool is_wpa)
|
2015-02-13 21:10:28 +01:00
|
|
|
|
{
|
2015-02-24 17:52:12 +01:00
|
|
|
|
uint8_t snonce[32];
|
|
|
|
|
|
|
|
|
|
memset(snonce, 0, sizeof(snonce));
|
2015-05-06 01:48:35 +02:00
|
|
|
|
return eapol_create_common(protocol, version,
|
|
|
|
|
is_wpa ? false : true,
|
|
|
|
|
key_replay_counter, snonce, 0, NULL,
|
|
|
|
|
1, is_wpa);
|
2015-05-06 01:48:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
struct eapol_key *eapol_create_gtk_2_of_2(
|
2015-05-06 01:48:34 +02:00
|
|
|
|
enum eapol_protocol_version protocol,
|
|
|
|
|
enum eapol_key_descriptor_version version,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
uint64_t key_replay_counter,
|
2015-05-18 21:31:11 +02:00
|
|
|
|
bool is_wpa, uint8_t wpa_key_id)
|
2015-05-06 01:48:34 +02:00
|
|
|
|
{
|
|
|
|
|
uint8_t snonce[32];
|
2015-05-18 21:31:11 +02:00
|
|
|
|
struct eapol_key *step2;
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
|
|
|
|
memset(snonce, 0, sizeof(snonce));
|
2015-05-18 21:31:11 +02:00
|
|
|
|
step2 = eapol_create_common(protocol, version, true,
|
2015-05-06 01:48:34 +02:00
|
|
|
|
key_replay_counter, snonce, 0, NULL,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
0, is_wpa);
|
2015-05-18 21:31:11 +02:00
|
|
|
|
|
|
|
|
|
if (!step2)
|
|
|
|
|
return step2;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WPA_80211_v3_1, Section 2.2.4:
|
|
|
|
|
* "The Key Type and Key Index shall not both be 0 in the same message"
|
|
|
|
|
*
|
|
|
|
|
* The above means that even though sending the key index back to the
|
|
|
|
|
* AP has no practical value, we must still do so.
|
|
|
|
|
*/
|
|
|
|
|
if (is_wpa)
|
|
|
|
|
step2->wpa_key_id = wpa_key_id;
|
|
|
|
|
|
|
|
|
|
return step2;
|
2015-02-13 21:10:28 +01:00
|
|
|
|
}
|
2015-02-24 17:54:23 +01:00
|
|
|
|
|
|
|
|
|
struct eapol_sm {
|
2016-08-10 23:32:45 +02:00
|
|
|
|
enum eapol_protocol_version protocol_version;
|
2015-03-20 02:55:25 +01:00
|
|
|
|
uint32_t ifindex;
|
2015-03-20 03:09:36 +01:00
|
|
|
|
uint8_t spa[6];
|
2015-03-20 03:13:24 +01:00
|
|
|
|
uint8_t aa[6];
|
2015-04-11 06:46:58 +02:00
|
|
|
|
uint8_t *ap_ie;
|
|
|
|
|
uint8_t *own_ie;
|
2015-05-19 07:05:53 +02:00
|
|
|
|
enum ie_rsn_cipher_suite pairwise_cipher;
|
|
|
|
|
enum ie_rsn_cipher_suite group_cipher;
|
2016-02-11 02:18:56 +01:00
|
|
|
|
enum ie_rsn_akm_suite akm_suite;
|
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];
|
2015-03-26 04:34:05 +01:00
|
|
|
|
void *user_data;
|
2015-10-30 11:12:19 +01:00
|
|
|
|
void *tx_user_data;
|
2015-03-30 05:44:08 +02:00
|
|
|
|
struct l_timeout *timeout;
|
2016-06-28 23:58:17 +02:00
|
|
|
|
struct l_io *io;
|
2015-02-24 17:54:23 +01:00
|
|
|
|
bool have_snonce:1;
|
|
|
|
|
bool have_replay:1;
|
2015-05-06 01:48:35 +02:00
|
|
|
|
bool ptk_complete:1;
|
2015-04-11 06:46:58 +02:00
|
|
|
|
bool wpa_ie:1;
|
2015-10-30 11:12:20 +01:00
|
|
|
|
bool have_pmk:1;
|
|
|
|
|
struct eap_state *eap;
|
2015-02-24 17:54:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void eapol_sm_destroy(void *value)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = value;
|
|
|
|
|
|
2015-04-11 06:46:58 +02:00
|
|
|
|
l_free(sm->ap_ie);
|
|
|
|
|
l_free(sm->own_ie);
|
2015-03-30 05:44:08 +02:00
|
|
|
|
|
|
|
|
|
l_timeout_remove(sm->timeout);
|
2016-06-28 23:58:17 +02:00
|
|
|
|
l_io_destroy(sm->io);
|
2015-03-30 05:44:08 +02:00
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
if (sm->eap)
|
|
|
|
|
eap_free(sm->eap);
|
|
|
|
|
|
2015-02-24 17:54:23 +01:00
|
|
|
|
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
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
void eapol_sm_set_protocol_version(struct eapol_sm *sm,
|
|
|
|
|
enum eapol_protocol_version protocol_version)
|
|
|
|
|
{
|
|
|
|
|
sm->protocol_version = protocol_version;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 03:09:36 +01:00
|
|
|
|
void eapol_sm_set_supplicant_address(struct eapol_sm *sm, const uint8_t *spa)
|
2015-02-24 17:55:50 +01:00
|
|
|
|
{
|
2015-03-20 03:09:36 +01:00
|
|
|
|
memcpy(sm->spa, spa, sizeof(sm->spa));
|
2015-02-24 17:55:50 +01:00
|
|
|
|
}
|
2015-02-24 17:56:39 +01:00
|
|
|
|
|
2015-03-20 03:13:24 +01:00
|
|
|
|
void eapol_sm_set_authenticator_address(struct eapol_sm *sm, const uint8_t *aa)
|
2015-02-24 17:56:39 +01:00
|
|
|
|
{
|
2015-03-20 03:13:24 +01:00
|
|
|
|
memcpy(sm->aa, aa, sizeof(sm->aa));
|
2015-02-24 17:56:39 +01:00
|
|
|
|
}
|
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-10-30 11:12:20 +01:00
|
|
|
|
sm->have_pmk = true;
|
2015-02-24 17:57:25 +01:00
|
|
|
|
}
|
2015-02-24 17:58:03 +01:00
|
|
|
|
|
2015-04-11 06:46:58 +02:00
|
|
|
|
static void eapol_sm_set_ap_ie(struct eapol_sm *sm, const uint8_t *ie,
|
|
|
|
|
size_t len, bool is_wpa)
|
|
|
|
|
{
|
|
|
|
|
if (ie[1] + 2u != len)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
l_free(sm->ap_ie);
|
|
|
|
|
sm->ap_ie = l_memdup(ie, len);
|
|
|
|
|
sm->wpa_ie = is_wpa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void eapol_sm_set_own_ie(struct eapol_sm *sm, const uint8_t *ie,
|
|
|
|
|
size_t len, bool is_wpa)
|
2015-02-24 17:58:03 +01:00
|
|
|
|
{
|
2015-04-11 06:46:58 +02:00
|
|
|
|
if (ie[1] + 2u != len)
|
2015-02-25 06:15:20 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2015-04-11 06:46:58 +02:00
|
|
|
|
l_free(sm->own_ie);
|
|
|
|
|
sm->own_ie = l_memdup(ie, len);
|
|
|
|
|
sm->wpa_ie = is_wpa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void eapol_sm_set_ap_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie, size_t len)
|
|
|
|
|
{
|
|
|
|
|
eapol_sm_set_ap_ie(sm, rsn_ie, len, false);
|
2015-02-24 17:58:03 +01:00
|
|
|
|
}
|
2015-02-24 17:58:43 +01:00
|
|
|
|
|
2015-05-19 07:05:53 +02:00
|
|
|
|
static bool eapol_sm_setup_own_ciphers(struct eapol_sm *sm,
|
|
|
|
|
const struct ie_rsn_info *info)
|
|
|
|
|
{
|
|
|
|
|
if (__builtin_popcount(info->pairwise_ciphers) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (__builtin_popcount(info->akm_suites) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-02-11 02:18:56 +01:00
|
|
|
|
sm->akm_suite = info->akm_suites;
|
2015-05-19 07:05:53 +02:00
|
|
|
|
sm->pairwise_cipher = info->pairwise_ciphers;
|
|
|
|
|
sm->group_cipher = info->group_cipher;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool eapol_sm_set_own_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
|
2015-02-24 17:58:43 +01:00
|
|
|
|
size_t len)
|
|
|
|
|
{
|
2015-05-19 07:05:53 +02:00
|
|
|
|
struct ie_rsn_info info;
|
|
|
|
|
|
2015-04-11 06:46:58 +02:00
|
|
|
|
eapol_sm_set_own_ie(sm, rsn_ie, len, false);
|
2015-05-19 07:05:53 +02:00
|
|
|
|
|
|
|
|
|
if (ie_parse_rsne_from_data(rsn_ie, rsn_ie[1] + 2, &info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return eapol_sm_setup_own_ciphers(sm, &info);
|
2015-04-11 06:46:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void eapol_sm_set_ap_wpa(struct eapol_sm *sm, const uint8_t *wpa_ie, size_t len)
|
|
|
|
|
{
|
|
|
|
|
eapol_sm_set_ap_ie(sm, wpa_ie, len, true);
|
|
|
|
|
}
|
2015-02-25 06:15:20 +01:00
|
|
|
|
|
2015-05-19 07:05:53 +02:00
|
|
|
|
bool eapol_sm_set_own_wpa(struct eapol_sm *sm, const uint8_t *wpa_ie,
|
2015-04-11 06:46:58 +02:00
|
|
|
|
size_t len)
|
|
|
|
|
{
|
2015-05-19 07:05:53 +02:00
|
|
|
|
struct ie_rsn_info info;
|
|
|
|
|
|
2015-04-11 06:46:58 +02:00
|
|
|
|
eapol_sm_set_own_ie(sm, wpa_ie, len, true);
|
2015-05-19 07:05:53 +02:00
|
|
|
|
|
|
|
|
|
if (ie_parse_wpa_from_data(wpa_ie, wpa_ie[1] + 2, &info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return eapol_sm_setup_own_ciphers(sm, &info);
|
2015-02-24 17:58:43 +01:00
|
|
|
|
}
|
2015-02-24 18:08:03 +01:00
|
|
|
|
|
2015-03-26 04:34:05 +01:00
|
|
|
|
void eapol_sm_set_user_data(struct eapol_sm *sm, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
sm->user_data = user_data;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-30 11:12:19 +01:00
|
|
|
|
void eapol_sm_set_tx_user_data(struct eapol_sm *sm, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
sm->tx_user_data = user_data;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 00:16:04 +02:00
|
|
|
|
uint32_t eapol_sm_get_pairwise_cipher(struct eapol_sm *sm)
|
|
|
|
|
{
|
|
|
|
|
return sm->pairwise_cipher;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 00:16:31 +02:00
|
|
|
|
uint32_t eapol_sm_get_group_cipher(struct eapol_sm *sm)
|
|
|
|
|
{
|
|
|
|
|
return sm->group_cipher;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-15 02:42:48 +02:00
|
|
|
|
const uint8_t *eapol_sm_get_own_ie(struct eapol_sm *sm, size_t *out_ie_len)
|
|
|
|
|
{
|
|
|
|
|
if (!sm->own_ie)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
*out_ie_len = sm->own_ie[1] + 2;
|
|
|
|
|
return sm->own_ie;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 03:58:40 +02:00
|
|
|
|
static bool eapol_sm_ifindex_match(void *data, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = data;
|
|
|
|
|
uint32_t ifindex = L_PTR_TO_UINT(user_data);
|
|
|
|
|
|
|
|
|
|
if (sm->ifindex != ifindex)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
eapol_sm_free(sm);
|
|
|
|
|
|
2015-04-17 17:17:48 +02:00
|
|
|
|
return true;
|
2015-03-30 03:58:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 04:00:00 +02:00
|
|
|
|
static inline void handshake_failed(uint32_t ifindex, struct eapol_sm *sm,
|
|
|
|
|
uint16_t reason_code)
|
|
|
|
|
{
|
2015-04-29 01:00:21 +02:00
|
|
|
|
if (deauthenticate)
|
|
|
|
|
deauthenticate(ifindex, sm->aa, sm->spa, reason_code,
|
|
|
|
|
sm->user_data);
|
2015-03-30 04:00:00 +02:00
|
|
|
|
|
|
|
|
|
l_queue_remove(state_machines, sm);
|
|
|
|
|
eapol_sm_free(sm);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 05:44:08 +02:00
|
|
|
|
static void eapol_timeout(struct l_timeout *timeout, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = user_data;
|
|
|
|
|
|
|
|
|
|
handshake_failed(sm->ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_4WAY_HANDSHAKE_TIMEOUT);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-29 01:45:49 +02:00
|
|
|
|
static void eapol_tx_packet(struct eapol_sm *sm, const struct eapol_frame *ef)
|
|
|
|
|
{
|
|
|
|
|
size_t frame_size;
|
|
|
|
|
struct sockaddr_ll sll;
|
|
|
|
|
ssize_t r;
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
if (!sm->io) {
|
|
|
|
|
tx_packet(sm->ifindex, sm->aa, sm->spa, ef, sm->tx_user_data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fd = l_io_get_fd(sm->io);
|
|
|
|
|
|
|
|
|
|
memset(&sll, 0, sizeof(sll));
|
|
|
|
|
sll.sll_family = AF_PACKET;
|
|
|
|
|
sll.sll_ifindex = sm->ifindex;
|
|
|
|
|
sll.sll_protocol = htons(ETH_P_PAE);
|
|
|
|
|
sll.sll_halen = ETH_ALEN;
|
|
|
|
|
memcpy(sll.sll_addr, sm->aa, ETH_ALEN);
|
|
|
|
|
|
|
|
|
|
frame_size = sizeof(struct eapol_header) +
|
|
|
|
|
L_BE16_TO_CPU(ef->header.packet_len);
|
|
|
|
|
|
|
|
|
|
r = sendto(fd, ef, frame_size, 0,
|
|
|
|
|
(struct sockaddr *) &sll, sizeof(sll));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
l_error("EAPoL write socket: %s", strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 14:21:23 +01:00
|
|
|
|
static void eapol_handle_ptk_1_of_4(uint32_t ifindex, struct eapol_sm *sm,
|
2015-10-30 11:12:19 +01:00
|
|
|
|
const struct eapol_key *ek)
|
2015-02-24 18:13:57 +01:00
|
|
|
|
{
|
|
|
|
|
struct crypto_ptk *ptk = (struct crypto_ptk *) sm->ptk;
|
|
|
|
|
struct eapol_key *step2;
|
|
|
|
|
uint8_t mic[16];
|
2016-02-11 02:18:56 +01:00
|
|
|
|
bool use_sha256;
|
2015-02-24 18:13:57 +01:00
|
|
|
|
|
2015-03-30 04:00:00 +02:00
|
|
|
|
if (!eapol_verify_ptk_1_of_4(ek)) {
|
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_UNSPECIFIED);
|
2015-02-24 18:13:57 +01:00
|
|
|
|
return;
|
2015-03-30 04:00:00 +02:00
|
|
|
|
}
|
2015-02-24 18:13:57 +01:00
|
|
|
|
|
2015-05-06 01:48:37 +02:00
|
|
|
|
if (!get_nonce(sm->snonce)) {
|
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_UNSPECIFIED);
|
|
|
|
|
return;
|
2015-02-24 18:13:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:37 +02:00
|
|
|
|
sm->have_snonce = true;
|
|
|
|
|
sm->ptk_complete = false;
|
|
|
|
|
|
2015-02-24 18:13:57 +01:00
|
|
|
|
memcpy(sm->anonce, ek->key_nonce, sizeof(ek->key_nonce));
|
|
|
|
|
|
2016-02-11 02:18:56 +01:00
|
|
|
|
if (sm->akm_suite == IE_RSN_AKM_SUITE_8021X_SHA256 ||
|
|
|
|
|
sm->akm_suite == IE_RSN_AKM_SUITE_PSK_SHA256)
|
|
|
|
|
use_sha256 = true;
|
|
|
|
|
else
|
|
|
|
|
use_sha256 = false;
|
|
|
|
|
|
2015-03-20 03:13:24 +01:00
|
|
|
|
crypto_derive_pairwise_ptk(sm->pmk, sm->spa, sm->aa,
|
2015-02-24 18:13:57 +01:00
|
|
|
|
sm->anonce, sm->snonce,
|
2016-02-10 23:55:15 +01:00
|
|
|
|
ptk, sizeof(sm->ptk),
|
2016-02-11 02:18:56 +01:00
|
|
|
|
use_sha256);
|
2015-02-24 18:13:57 +01:00
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
step2 = eapol_create_ptk_2_of_4(sm->protocol_version,
|
2015-02-24 18:13:57 +01:00
|
|
|
|
ek->key_descriptor_version,
|
|
|
|
|
sm->replay_counter,
|
|
|
|
|
sm->snonce,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
sm->own_ie[1] + 2, sm->own_ie,
|
|
|
|
|
sm->wpa_ie);
|
2015-02-24 18:13:57 +01:00
|
|
|
|
|
2015-03-20 20:52:49 +01:00
|
|
|
|
if (!eapol_calculate_mic(ptk->kck, step2, mic)) {
|
|
|
|
|
l_info("MIC calculation failed. "
|
|
|
|
|
"Ensure Kernel Crypto is available.");
|
2015-03-30 04:00:00 +02:00
|
|
|
|
l_free(step2);
|
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_UNSPECIFIED);
|
|
|
|
|
|
|
|
|
|
return;
|
2015-03-20 20:52:49 +01:00
|
|
|
|
}
|
2015-02-24 18:13:57 +01:00
|
|
|
|
|
|
|
|
|
memcpy(step2->key_mic_data, mic, sizeof(mic));
|
2016-06-29 01:45:49 +02:00
|
|
|
|
eapol_tx_packet(sm, (struct eapol_frame *) step2);
|
2015-02-24 18:13:57 +01:00
|
|
|
|
l_free(step2);
|
2015-03-30 05:44:08 +02:00
|
|
|
|
|
|
|
|
|
l_timeout_remove(sm->timeout);
|
|
|
|
|
sm->timeout = NULL;
|
2015-02-24 18:13:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-19 04:52:53 +02:00
|
|
|
|
static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len,
|
|
|
|
|
const uint8_t **optional)
|
2015-02-25 05:09:10 +01:00
|
|
|
|
{
|
|
|
|
|
struct ie_tlv_iter iter;
|
2015-05-19 04:52:53 +02:00
|
|
|
|
const uint8_t *first = NULL;
|
2015-02-25 05:09:10 +01:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2015-05-19 04:52:53 +02:00
|
|
|
|
if (!first) {
|
|
|
|
|
first = ie_tlv_iter_get_data(&iter) - 2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (optional)
|
|
|
|
|
*optional = ie_tlv_iter_get_data(&iter) - 2;
|
|
|
|
|
|
|
|
|
|
return first;
|
2015-02-25 05:09:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-19 04:52:53 +02:00
|
|
|
|
return first;
|
2015-02-25 05:09:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
static const uint8_t *eapol_find_wpa_ie(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_VENDOR_SPECIFIC)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (is_ie_wpa_ie(ie_tlv_iter_get_data(&iter),
|
|
|
|
|
ie_tlv_iter_get_length(&iter)))
|
|
|
|
|
return ie_tlv_iter_get_data(&iter) - 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-25 05:09:10 +01:00
|
|
|
|
/*
|
2015-05-06 01:48:35 +02:00
|
|
|
|
* This function performs a match of the RSN/WPA IE obtained from the scan
|
|
|
|
|
* results vs the RSN/WPA IE obtained as part of the 4-way handshake. If they
|
2015-02-25 05:09:10 +01:00
|
|
|
|
* don't match, the EAPoL packet must be silently discarded.
|
|
|
|
|
*/
|
2015-05-06 01:48:35 +02:00
|
|
|
|
static bool eapol_ap_ie_matches(const uint8_t *eapol_ie,
|
|
|
|
|
const uint8_t *scan_ie, bool is_wpa)
|
2015-02-25 05:09:10 +01:00
|
|
|
|
{
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (eapol_ie[1] == scan_ie[1] &&
|
|
|
|
|
!memcmp(eapol_ie + 2, scan_ie + 2, eapol_ie[1]))
|
2015-02-25 05:09:10 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/*
|
2015-05-06 01:48:35 +02:00
|
|
|
|
* Otherwise we have to parse the IEs and compare the individual
|
2015-02-25 05:09:10 +01:00
|
|
|
|
* fields
|
|
|
|
|
*/
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!is_wpa) {
|
|
|
|
|
if (ie_parse_rsne_from_data(eapol_ie, eapol_ie[1] + 2,
|
|
|
|
|
&eapol_info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ie_parse_rsne_from_data(scan_ie, scan_ie[1] + 2,
|
|
|
|
|
&scan_info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
if (ie_parse_wpa_from_data(eapol_ie, eapol_ie[1] + 2,
|
|
|
|
|
&eapol_info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ie_parse_wpa_from_data(scan_ie, scan_ie[1] + 2,
|
|
|
|
|
&scan_info) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-02-25 05:09:10 +01:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 14:21:23 +01:00
|
|
|
|
static void eapol_handle_ptk_3_of_4(uint32_t ifindex,
|
|
|
|
|
struct eapol_sm *sm,
|
2015-02-24 18:14:11 +01:00
|
|
|
|
const struct eapol_key *ek,
|
2015-02-24 23:02:32 +01:00
|
|
|
|
const uint8_t *decrypted_key_data,
|
2015-10-30 11:12:19 +01:00
|
|
|
|
size_t decrypted_key_data_size)
|
2015-02-24 18:14:11 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
2015-02-25 05:09:10 +01:00
|
|
|
|
const uint8_t *rsne;
|
2015-05-19 04:52:53 +02:00
|
|
|
|
const uint8_t *optional_rsne = NULL;
|
2015-03-26 05:26:31 +01:00
|
|
|
|
uint8_t gtk_key_index;
|
2015-05-22 04:10:21 +02:00
|
|
|
|
enum ie_rsn_cipher_suite pairwise = sm->pairwise_cipher;
|
2015-02-24 18:14:11 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!eapol_verify_ptk_3_of_4(ek, sm->wpa_ie)) {
|
2015-03-30 04:00:00 +02:00
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_UNSPECIFIED);
|
2015-02-24 18:14:11 +01:00
|
|
|
|
return;
|
2015-03-30 04:00:00 +02:00
|
|
|
|
}
|
2015-02-24 18:14:11 +01:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!sm->wpa_ie)
|
|
|
|
|
rsne = eapol_find_rsne(decrypted_key_data,
|
2015-05-19 04:52:53 +02:00
|
|
|
|
decrypted_key_data_size,
|
|
|
|
|
&optional_rsne);
|
2015-05-06 01:48:35 +02:00
|
|
|
|
else
|
|
|
|
|
rsne = eapol_find_wpa_ie(decrypted_key_data,
|
|
|
|
|
decrypted_key_data_size);
|
2015-05-06 05:18:35 +02:00
|
|
|
|
|
2015-03-30 04:00:00 +02:00
|
|
|
|
if (!rsne) {
|
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_IE_DIFFERENT);
|
2015-02-25 05:09:10 +01:00
|
|
|
|
return;
|
2015-03-30 04:00:00 +02:00
|
|
|
|
}
|
2015-02-25 05:09:10 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!eapol_ap_ie_matches(rsne, sm->ap_ie, sm->wpa_ie)) {
|
2015-03-30 04:00:00 +02:00
|
|
|
|
handshake_failed(ifindex, sm, MPDU_REASON_CODE_IE_DIFFERENT);
|
2015-02-25 05:09:10 +01:00
|
|
|
|
return;
|
2015-03-30 04:00:00 +02:00
|
|
|
|
}
|
2015-02-24 18:14:11 +01:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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-05-19 04:52:53 +02:00
|
|
|
|
if (optional_rsne) {
|
|
|
|
|
struct ie_rsn_info info1;
|
|
|
|
|
struct ie_rsn_info info2;
|
|
|
|
|
uint16_t override;
|
|
|
|
|
|
|
|
|
|
if (ie_parse_rsne_from_data(rsne, rsne[1] + 2, &info1) < 0) {
|
|
|
|
|
handshake_failed(ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ie_parse_rsne_from_data(optional_rsne, optional_rsne[1] + 2,
|
|
|
|
|
&info2) < 0) {
|
|
|
|
|
handshake_failed(ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 11.6.2:
|
|
|
|
|
* It may happen, for example, that a Supplicant selects a
|
|
|
|
|
* pairwise cipher suite which is advertised by an AP, but
|
|
|
|
|
* which policy disallows for this particular STA. An
|
|
|
|
|
* Authenticator may, therefore, insert a second RSNE to
|
|
|
|
|
* overrule the STA’s selection. An Authenticator’s SME shall
|
|
|
|
|
* insert the second RSNE, after the first RSNE, only for this
|
|
|
|
|
* purpose. The pairwise cipher suite in the second RSNE
|
|
|
|
|
* included shall be one of the ciphers advertised by the
|
|
|
|
|
* Authenticator. All other fields in the second RSNE shall be
|
|
|
|
|
* identical to the first RSNE.
|
|
|
|
|
*
|
|
|
|
|
* - Check that akm_suites and group_cipher are the same
|
|
|
|
|
* between rsne1 and rsne2
|
|
|
|
|
* - Check that pairwise_ciphers is not the same between rsne1
|
|
|
|
|
* and rsne2
|
|
|
|
|
* - Check that rsne2 pairwise_ciphers is a subset of rsne
|
|
|
|
|
*/
|
|
|
|
|
if (info1.akm_suites != info2.akm_suites ||
|
|
|
|
|
info1.group_cipher != info2.group_cipher) {
|
|
|
|
|
handshake_failed(ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override = info2.pairwise_ciphers;
|
|
|
|
|
|
|
|
|
|
if (override == info1.pairwise_ciphers ||
|
|
|
|
|
!(info1.pairwise_ciphers & override) ||
|
|
|
|
|
__builtin_popcount(override) != 1) {
|
|
|
|
|
handshake_failed(ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_INVALID_PAIRWISE_CIPHER);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-05-22 04:10:21 +02:00
|
|
|
|
|
|
|
|
|
pairwise = override;
|
2015-05-19 04:52:53 +02:00
|
|
|
|
}
|
2015-02-25 00:11:56 +01:00
|
|
|
|
|
|
|
|
|
/*
|
2015-05-06 05:18:43 +02:00
|
|
|
|
* TODO: Handle IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC case
|
2015-02-25 00:11:56 +01:00
|
|
|
|
*/
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!sm->wpa_ie) {
|
|
|
|
|
gtk = eapol_find_gtk_kde(decrypted_key_data,
|
|
|
|
|
decrypted_key_data_size,
|
|
|
|
|
>k_len);
|
|
|
|
|
if (!gtk || gtk_len < 8) {
|
|
|
|
|
handshake_failed(ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_UNSPECIFIED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-03-26 05:26:31 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
/* TODO: Handle tx bit */
|
2015-03-26 05:26:31 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
gtk_key_index = util_bit_field(gtk[0], 0, 2);
|
|
|
|
|
gtk += 2;
|
|
|
|
|
gtk_len -= 2;
|
|
|
|
|
} else
|
|
|
|
|
gtk = NULL;
|
2015-03-26 05:26:31 +01:00
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
step4 = eapol_create_ptk_4_of_4(sm->protocol_version,
|
2015-02-24 18:14:11 +01:00
|
|
|
|
ek->key_descriptor_version,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
sm->replay_counter, sm->wpa_ie);
|
2015-02-24 18:14:11 +01:00
|
|
|
|
|
2015-03-30 03:57:58 +02:00
|
|
|
|
/*
|
|
|
|
|
* 802.11-2012, Section 11.6.6.4, step b):
|
|
|
|
|
* Verifies the Message 3 MIC. If the calculated MIC does not match
|
|
|
|
|
* the MIC that the Authenticator included in the EAPOL-Key frame,
|
|
|
|
|
* the Supplicant silently discards Message 3.
|
|
|
|
|
*/
|
2015-02-24 18:14:11 +01:00
|
|
|
|
if (!eapol_calculate_mic(ptk->kck, step4, mic))
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
memcpy(step4->key_mic_data, mic, sizeof(mic));
|
2016-06-29 01:45:49 +02:00
|
|
|
|
eapol_tx_packet(sm, (struct eapol_frame *) step4);
|
2015-02-24 18:14:11 +01:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
sm->ptk_complete = true;
|
|
|
|
|
|
2015-05-22 04:10:21 +02:00
|
|
|
|
if (install_tk) {
|
|
|
|
|
uint32_t cipher = ie_rsn_cipher_suite_to_cipher(pairwise);
|
|
|
|
|
|
|
|
|
|
install_tk(sm->ifindex, sm->aa, ptk->tk, cipher, sm->user_data);
|
|
|
|
|
}
|
2015-03-26 04:35:12 +01:00
|
|
|
|
|
2015-05-22 04:08:47 +02:00
|
|
|
|
if (gtk && install_gtk) {
|
|
|
|
|
uint32_t cipher =
|
|
|
|
|
ie_rsn_cipher_suite_to_cipher(sm->group_cipher);
|
|
|
|
|
|
2015-03-26 05:26:31 +01:00
|
|
|
|
install_gtk(sm->ifindex, gtk_key_index, gtk, gtk_len,
|
2015-05-22 04:08:47 +02:00
|
|
|
|
ek->key_rsc, 6, cipher, sm->user_data);
|
|
|
|
|
}
|
2015-03-26 05:26:31 +01:00
|
|
|
|
|
2016-06-23 00:49:15 +02:00
|
|
|
|
if (rekey_offload)
|
|
|
|
|
rekey_offload(sm->ifindex, ptk->kek, ptk->kck,
|
|
|
|
|
sm->replay_counter, sm->user_data);
|
|
|
|
|
|
2015-02-24 18:14:11 +01:00
|
|
|
|
fail:
|
|
|
|
|
l_free(step4);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:34 +02:00
|
|
|
|
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,
|
2015-10-30 11:12:19 +01:00
|
|
|
|
size_t decrypted_key_data_size)
|
2015-05-06 01:48:34 +02:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!sm->wpa_ie) {
|
|
|
|
|
gtk = eapol_find_gtk_kde(decrypted_key_data,
|
|
|
|
|
decrypted_key_data_size,
|
|
|
|
|
>k_len);
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!gtk || gtk_len < 8)
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
gtk = decrypted_key_data;
|
|
|
|
|
gtk_len = decrypted_key_data_size;
|
|
|
|
|
|
|
|
|
|
if (!gtk || gtk_len < 6)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if (!sm->wpa_ie) {
|
|
|
|
|
gtk_key_index = util_bit_field(gtk[0], 0, 2);
|
|
|
|
|
gtk += 2;
|
|
|
|
|
gtk_len -= 2;
|
|
|
|
|
} else
|
|
|
|
|
gtk_key_index = ek->wpa_key_id;
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
step2 = eapol_create_gtk_2_of_2(sm->protocol_version,
|
2015-05-06 01:48:34 +02:00
|
|
|
|
ek->key_descriptor_version,
|
2015-05-18 21:31:11 +02:00
|
|
|
|
sm->replay_counter, sm->wpa_ie,
|
|
|
|
|
ek->wpa_key_id);
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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));
|
2016-06-29 01:45:49 +02:00
|
|
|
|
eapol_tx_packet(sm, (struct eapol_frame *) step2);
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
2015-05-22 04:08:47 +02:00
|
|
|
|
if (install_gtk) {
|
|
|
|
|
uint32_t cipher =
|
|
|
|
|
ie_rsn_cipher_suite_to_cipher(sm->group_cipher);
|
|
|
|
|
|
2015-05-06 01:48:34 +02:00
|
|
|
|
install_gtk(sm->ifindex, gtk_key_index, gtk, gtk_len,
|
2015-05-22 04:08:47 +02:00
|
|
|
|
ek->key_rsc, 6, cipher, sm->user_data);
|
|
|
|
|
}
|
2015-05-06 01:48:34 +02:00
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
l_free(step2);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 02:55:25 +01:00
|
|
|
|
static struct eapol_sm *eapol_find_sm(uint32_t ifindex,
|
2015-03-20 03:09:36 +01:00
|
|
|
|
const uint8_t *spa,
|
2015-03-20 03:13:24 +01:00
|
|
|
|
const uint8_t *aa)
|
2015-03-20 02:55:25 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2015-03-20 03:09:36 +01:00
|
|
|
|
if (memcmp(sm->spa, spa, 6))
|
2015-03-20 02:55:25 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
2015-03-20 03:13:24 +01:00
|
|
|
|
if (memcmp(sm->aa, aa, 6))
|
2015-03-20 02:55:25 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return sm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
static void eapol_key_handle(struct eapol_sm *sm, uint32_t ifindex,
|
|
|
|
|
const uint8_t *frame, size_t len)
|
2015-02-24 18:13:19 +01:00
|
|
|
|
{
|
|
|
|
|
const struct eapol_key *ek;
|
|
|
|
|
struct crypto_ptk *ptk;
|
|
|
|
|
uint8_t *decrypted_key_data = NULL;
|
2015-05-06 01:48:35 +02:00
|
|
|
|
size_t key_data_len = 0;
|
2015-02-24 18:13:19 +01:00
|
|
|
|
uint64_t replay_counter;
|
|
|
|
|
|
|
|
|
|
ek = eapol_key_validate(frame, len);
|
|
|
|
|
if (!ek)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Wrong direction */
|
|
|
|
|
if (!ek->key_ack)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
/* Further Descriptor Type check */
|
|
|
|
|
if (!sm->wpa_ie && ek->descriptor_type != EAPOL_DESCRIPTOR_TYPE_80211)
|
|
|
|
|
return;
|
|
|
|
|
else if (sm->wpa_ie && ek->descriptor_type != EAPOL_DESCRIPTOR_TYPE_WPA)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-24 18:13:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
if ((ek->encrypted_key_data && !sm->wpa_ie) ||
|
|
|
|
|
(ek->key_type == 0 && sm->wpa_ie)) {
|
2015-02-24 18:13:19 +01:00
|
|
|
|
/* Haven't received step 1 yet, so no ptk */
|
|
|
|
|
if (!sm->have_snonce)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-24 22:59:36 +01:00
|
|
|
|
decrypted_key_data = eapol_decrypt_key_data(ptk->kek, ek,
|
2015-05-06 01:48:35 +02:00
|
|
|
|
&key_data_len);
|
2015-02-24 18:13:19 +01:00
|
|
|
|
if (!decrypted_key_data)
|
|
|
|
|
return;
|
2015-05-06 01:48:35 +02:00
|
|
|
|
} else
|
|
|
|
|
key_data_len = L_BE16_TO_CPU(ek->key_data_len);
|
2015-02-24 18:13:19 +01:00
|
|
|
|
|
2015-05-06 01:48:34 +02:00
|
|
|
|
if (ek->key_type == 0) {
|
2015-05-06 01:48:35 +02:00
|
|
|
|
/* Only GTK handshake allowed after PTK handshake complete */
|
|
|
|
|
if (!sm->ptk_complete)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
if (!decrypted_key_data)
|
2015-05-06 01:48:34 +02:00
|
|
|
|
goto done;
|
|
|
|
|
|
2015-05-06 01:48:35 +02:00
|
|
|
|
eapol_handle_gtk_1_of_2(ifindex, sm, ek,
|
|
|
|
|
decrypted_key_data,
|
2015-10-30 11:12:19 +01:00
|
|
|
|
key_data_len);
|
2015-02-24 18:13:19 +01:00
|
|
|
|
goto done;
|
2015-05-06 01:48:34 +02:00
|
|
|
|
}
|
2015-02-24 18:13:19 +01:00
|
|
|
|
|
|
|
|
|
/* If no MIC, then assume packet 1, otherwise packet 3 */
|
|
|
|
|
if (!ek->key_mic)
|
2015-10-30 11:12:19 +01:00
|
|
|
|
eapol_handle_ptk_1_of_4(ifindex, sm, ek);
|
2015-05-06 01:48:35 +02:00
|
|
|
|
else {
|
|
|
|
|
if (sm->ptk_complete)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
if (!key_data_len)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
eapol_handle_ptk_3_of_4(ifindex, sm, ek,
|
|
|
|
|
decrypted_key_data ?: ek->key_data,
|
2015-10-30 11:12:19 +01:00
|
|
|
|
key_data_len);
|
2015-05-06 01:48:35 +02:00
|
|
|
|
}
|
2015-02-24 18:13:19 +01:00
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
l_free(decrypted_key_data);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
/* This respresentes the eapMsg message in 802.1X Figure 8-1 */
|
|
|
|
|
static void eapol_eap_msg_cb(const uint8_t *eap_data, size_t len,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = user_data;
|
|
|
|
|
uint8_t buf[sizeof(struct eapol_frame) + len];
|
|
|
|
|
struct eapol_frame *frame = (struct eapol_frame *) buf;
|
|
|
|
|
|
|
|
|
|
frame->header.protocol_version = EAPOL_PROTOCOL_VERSION_2004;
|
|
|
|
|
frame->header.packet_type = 0;
|
|
|
|
|
l_put_be16(len, &frame->header.packet_len);
|
|
|
|
|
|
|
|
|
|
memcpy(frame->data, eap_data, len);
|
|
|
|
|
|
2016-06-29 01:45:49 +02:00
|
|
|
|
eapol_tx_packet(sm, frame);
|
2015-10-30 11:12:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This respresentes the eapTimout, eapFail and eapSuccess messages */
|
|
|
|
|
static void eapol_eap_complete_cb(enum eap_result result, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = user_data;
|
|
|
|
|
|
|
|
|
|
l_info("EAP completed with %s", result == EAP_RESULT_SUCCESS ?
|
|
|
|
|
"eapSuccess" : (result == EAP_RESULT_FAIL ?
|
|
|
|
|
"eapFail" : "eapTimeout"));
|
|
|
|
|
|
|
|
|
|
eap_free(sm->eap);
|
|
|
|
|
sm->eap = NULL;
|
|
|
|
|
|
|
|
|
|
if (result != EAP_RESULT_SUCCESS)
|
|
|
|
|
handshake_failed(sm->ifindex, sm,
|
|
|
|
|
MPDU_REASON_CODE_IEEE8021X_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This respresentes the eapResults message */
|
|
|
|
|
static void eapol_eap_results_cb(const uint8_t *msk_data, size_t msk_len,
|
|
|
|
|
const uint8_t *emsk_data, size_t emsk_len,
|
|
|
|
|
const uint8_t *iv, size_t iv_len,
|
|
|
|
|
void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = user_data;
|
|
|
|
|
|
|
|
|
|
l_debug("EAP key material received");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 802.11i 8.5.1.2:
|
|
|
|
|
* "When not using a PSK, the PMK is derived from the AAA key.
|
|
|
|
|
* The PMK shall be computed as the first 256 bits (bits 0–255)
|
|
|
|
|
* of the AAA key: PMK ← L(PTK, 0, 256)."
|
|
|
|
|
* 802.11 11.6.1.3:
|
|
|
|
|
* "When not using a PSK, the PMK is derived from the MSK.
|
|
|
|
|
* The PMK shall be computed as the first 256 bits (bits 0–255)
|
|
|
|
|
* of the MSK: PMK ← L(MSK, 0, 256)."
|
|
|
|
|
* RFC5247 explains AAA-Key refers to the MSK and confirms the
|
|
|
|
|
* first 32 bytes of the MSK are used. MSK is at least 64 octets
|
|
|
|
|
* long per RFC3748. Note WEP derives the PTK from MSK differently.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
eapol_sm_set_pmk(sm, msk_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void eapol_sm_set_8021x_config(struct eapol_sm *sm, struct l_settings *settings)
|
|
|
|
|
{
|
|
|
|
|
sm->eap = eap_new(eapol_eap_msg_cb, eapol_eap_complete_cb, sm);
|
|
|
|
|
|
|
|
|
|
if (!sm->eap)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
eap_set_key_material_func(sm->eap, eapol_eap_results_cb);
|
|
|
|
|
|
|
|
|
|
eap_load_settings(sm->eap, settings, "EAP-");
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:58:17 +02:00
|
|
|
|
static void eapol_rx_packet(struct eapol_sm *sm,
|
|
|
|
|
const uint8_t *frame, size_t len)
|
2015-10-30 11:12:20 +01:00
|
|
|
|
{
|
|
|
|
|
const struct eapol_header *eh;
|
|
|
|
|
|
|
|
|
|
/* Validate Header */
|
|
|
|
|
if (len < sizeof(struct eapol_header))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
eh = (const struct eapol_header *) frame;
|
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
switch (eh->protocol_version) {
|
|
|
|
|
case EAPOL_PROTOCOL_VERSION_2001:
|
|
|
|
|
case EAPOL_PROTOCOL_VERSION_2004:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2015-10-30 11:12:20 +01:00
|
|
|
|
return;
|
2016-08-10 23:32:45 +02:00
|
|
|
|
}
|
2015-10-30 11:12:20 +01:00
|
|
|
|
|
|
|
|
|
if (len < (size_t) 4 + L_BE16_TO_CPU(eh->packet_len))
|
|
|
|
|
return;
|
|
|
|
|
|
2016-08-10 23:32:45 +02:00
|
|
|
|
if (!sm->protocol_version)
|
|
|
|
|
sm->protocol_version = eh->protocol_version;
|
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
switch (eh->packet_type) {
|
|
|
|
|
case 0: /* EAPOL-EAP */
|
|
|
|
|
if (!sm->eap) {
|
2015-11-03 23:26:34 +01:00
|
|
|
|
/* If we're not configured for EAP, send a NAK */
|
2015-10-30 11:12:20 +01:00
|
|
|
|
sm->eap = eap_new(eapol_eap_msg_cb,
|
|
|
|
|
eapol_eap_complete_cb, sm);
|
|
|
|
|
|
|
|
|
|
if (!sm->eap)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
eap_set_key_material_func(sm->eap,
|
|
|
|
|
eapol_eap_results_cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eap_rx_packet(sm->eap, frame + 4,
|
|
|
|
|
L_BE16_TO_CPU(eh->packet_len));
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: /* EAPOL-Key */
|
|
|
|
|
if (sm->eap) /* An EAP negotiation in progress? */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!sm->have_pmk)
|
|
|
|
|
return;
|
|
|
|
|
|
2016-06-28 23:58:17 +02:00
|
|
|
|
eapol_key_handle(sm, sm->ifindex, frame, len);
|
2015-10-30 11:12:20 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:58:17 +02:00
|
|
|
|
void __eapol_rx_packet(uint32_t ifindex, const uint8_t *spa, const uint8_t *aa,
|
|
|
|
|
const uint8_t *frame, size_t len)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = eapol_find_sm(ifindex, spa, aa);
|
|
|
|
|
|
|
|
|
|
if (!sm)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
eapol_rx_packet(sm, frame, len);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-23 00:49:15 +02:00
|
|
|
|
void __eapol_update_replay_counter(uint32_t ifindex, const uint8_t *spa,
|
|
|
|
|
const uint8_t *aa, uint64_t replay_counter)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm;
|
|
|
|
|
|
|
|
|
|
sm = eapol_find_sm(ifindex, spa, aa);
|
|
|
|
|
|
|
|
|
|
if (!sm)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (sm->replay_counter >= replay_counter)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
sm->replay_counter = replay_counter;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 04:35:12 +01:00
|
|
|
|
void __eapol_set_install_tk_func(eapol_install_tk_func_t func)
|
|
|
|
|
{
|
|
|
|
|
install_tk = func;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 05:26:31 +01:00
|
|
|
|
void __eapol_set_install_gtk_func(eapol_install_gtk_func_t func)
|
|
|
|
|
{
|
|
|
|
|
install_gtk = func;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-30 03:30:14 +02:00
|
|
|
|
void __eapol_set_deauthenticate_func(eapol_deauthenticate_func_t func)
|
|
|
|
|
{
|
|
|
|
|
deauthenticate = func;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-23 00:49:15 +02:00
|
|
|
|
void __eapol_set_rekey_offload_func(eapol_rekey_offload_func_t func)
|
|
|
|
|
{
|
|
|
|
|
rekey_offload = func;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 14:31:26 +01:00
|
|
|
|
struct l_io *eapol_open_pae(uint32_t index)
|
|
|
|
|
{
|
|
|
|
|
struct l_io *io;
|
|
|
|
|
struct sockaddr_ll sll;
|
|
|
|
|
int fd;
|
|
|
|
|
|
2015-03-20 03:54:53 +01:00
|
|
|
|
fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_PAE));
|
2015-02-26 14:31:26 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:58:17 +02:00
|
|
|
|
static bool eapol_read(struct l_io *io, void *user_data)
|
|
|
|
|
{
|
|
|
|
|
struct eapol_sm *sm = user_data;
|
|
|
|
|
int fd = l_io_get_fd(io);
|
|
|
|
|
struct sockaddr_ll sll;
|
|
|
|
|
socklen_t sll_len;
|
|
|
|
|
ssize_t bytes;
|
|
|
|
|
uint8_t frame[2304]; /* IEEE Std 802.11 ch. 8.2.3 */
|
|
|
|
|
|
|
|
|
|
memset(&sll, 0, sizeof(sll));
|
|
|
|
|
sll_len = sizeof(sll);
|
|
|
|
|
|
|
|
|
|
bytes = recvfrom(fd, frame, sizeof(frame), 0,
|
|
|
|
|
(struct sockaddr *) &sll, &sll_len);
|
|
|
|
|
if (bytes <= 0) {
|
|
|
|
|
l_error("EAPoL read socket: %s", strerror(errno));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (memcmp(sm->aa, sll.sll_addr, 6))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
eapol_rx_packet(sm, frame, bytes);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 18:31:14 +01:00
|
|
|
|
static bool eapol_get_nonce(uint8_t nonce[])
|
|
|
|
|
{
|
|
|
|
|
return l_getrandom(nonce, 32);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:56:56 +02:00
|
|
|
|
void eapol_start(uint32_t ifindex, struct l_io *io, struct eapol_sm *sm)
|
|
|
|
|
{
|
|
|
|
|
sm->ifindex = ifindex;
|
|
|
|
|
sm->timeout = l_timeout_create(2, eapol_timeout, sm, NULL);
|
2016-06-28 23:58:17 +02:00
|
|
|
|
|
|
|
|
|
if (io) {
|
|
|
|
|
sm->io = io;
|
|
|
|
|
l_io_set_read_handler(io, eapol_read, sm, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:56:56 +02:00
|
|
|
|
l_queue_push_head(state_machines, sm);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-28 23:56:13 +02:00
|
|
|
|
void eapol_cancel(uint32_t ifindex)
|
|
|
|
|
{
|
|
|
|
|
l_queue_foreach_remove(state_machines, eapol_sm_ifindex_match,
|
|
|
|
|
L_UINT_TO_PTR(ifindex));
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 18:08:03 +01:00
|
|
|
|
bool eapol_init()
|
|
|
|
|
{
|
2015-03-20 02:55:25 +01:00
|
|
|
|
state_machines = l_queue_new();
|
2015-03-20 18:31:14 +01:00
|
|
|
|
get_nonce = eapol_get_nonce;
|
2015-02-24 18:08:03 +01:00
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
eap_init();
|
|
|
|
|
|
2015-02-24 18:08:03 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool eapol_exit()
|
|
|
|
|
{
|
2016-07-20 22:34:21 +02:00
|
|
|
|
if (!l_queue_isempty(state_machines))
|
|
|
|
|
l_warn("stale eapol state machines found");
|
|
|
|
|
|
2015-03-20 02:55:25 +01:00
|
|
|
|
l_queue_destroy(state_machines, eapol_sm_destroy);
|
2015-02-24 18:09:42 +01:00
|
|
|
|
get_nonce = NULL;
|
2015-02-24 18:08:03 +01:00
|
|
|
|
|
2015-10-30 11:12:20 +01:00
|
|
|
|
eap_exit();
|
|
|
|
|
|
2015-02-24 18:08:03 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|