eapol: Handle EAPoL-EAP packets
This commit is contained in:
parent
2bccb7e7dc
commit
14020b2aa6
150
src/eapol.c
150
src/eapol.c
|
@ -40,6 +40,7 @@
|
||||||
#include "ie.h"
|
#include "ie.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "mpdu.h"
|
#include "mpdu.h"
|
||||||
|
#include "eap.h"
|
||||||
|
|
||||||
struct l_queue *state_machines;
|
struct l_queue *state_machines;
|
||||||
eapol_tx_packet_func_t tx_packet = NULL;
|
eapol_tx_packet_func_t tx_packet = NULL;
|
||||||
|
@ -605,6 +606,8 @@ struct eapol_sm {
|
||||||
bool have_replay:1;
|
bool have_replay:1;
|
||||||
bool ptk_complete:1;
|
bool ptk_complete:1;
|
||||||
bool wpa_ie:1;
|
bool wpa_ie:1;
|
||||||
|
bool have_pmk:1;
|
||||||
|
struct eap_state *eap;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void eapol_sm_destroy(void *value)
|
static void eapol_sm_destroy(void *value)
|
||||||
|
@ -616,6 +619,9 @@ static void eapol_sm_destroy(void *value)
|
||||||
|
|
||||||
l_timeout_remove(sm->timeout);
|
l_timeout_remove(sm->timeout);
|
||||||
|
|
||||||
|
if (sm->eap)
|
||||||
|
eap_free(sm->eap);
|
||||||
|
|
||||||
l_free(sm);
|
l_free(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,6 +652,7 @@ void eapol_sm_set_authenticator_address(struct eapol_sm *sm, const uint8_t *aa)
|
||||||
void eapol_sm_set_pmk(struct eapol_sm *sm, const uint8_t *pmk)
|
void eapol_sm_set_pmk(struct eapol_sm *sm, const uint8_t *pmk)
|
||||||
{
|
{
|
||||||
memcpy(sm->pmk, pmk, sizeof(sm->pmk));
|
memcpy(sm->pmk, pmk, sizeof(sm->pmk));
|
||||||
|
sm->have_pmk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eapol_sm_set_ap_ie(struct eapol_sm *sm, const uint8_t *ie,
|
static void eapol_sm_set_ap_ie(struct eapol_sm *sm, const uint8_t *ie,
|
||||||
|
@ -1265,11 +1272,10 @@ static struct eapol_sm *eapol_find_sm(uint32_t ifindex,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __eapol_rx_packet(uint32_t ifindex, const uint8_t *spa, const uint8_t *aa,
|
static void eapol_key_handle(struct eapol_sm *sm, uint32_t ifindex,
|
||||||
const uint8_t *frame, size_t len)
|
const uint8_t *frame, size_t len)
|
||||||
{
|
{
|
||||||
const struct eapol_key *ek;
|
const struct eapol_key *ek;
|
||||||
struct eapol_sm *sm;
|
|
||||||
struct crypto_ptk *ptk;
|
struct crypto_ptk *ptk;
|
||||||
uint8_t *decrypted_key_data = NULL;
|
uint8_t *decrypted_key_data = NULL;
|
||||||
size_t key_data_len = 0;
|
size_t key_data_len = 0;
|
||||||
|
@ -1279,10 +1285,6 @@ void __eapol_rx_packet(uint32_t ifindex, const uint8_t *spa, const uint8_t *aa,
|
||||||
if (!ek)
|
if (!ek)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sm = eapol_find_sm(ifindex, spa, aa);
|
|
||||||
if (!sm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Wrong direction */
|
/* Wrong direction */
|
||||||
if (!ek->key_ack)
|
if (!ek->key_ack)
|
||||||
return;
|
return;
|
||||||
|
@ -1367,6 +1369,136 @@ done:
|
||||||
l_free(decrypted_key_data);
|
l_free(decrypted_key_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
tx_packet(sm->ifindex, sm->aa, sm->spa, frame, sm->tx_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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-");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __eapol_rx_packet(uint32_t ifindex, const uint8_t *spa, const uint8_t *aa,
|
||||||
|
const uint8_t *frame, size_t len)
|
||||||
|
{
|
||||||
|
const struct eapol_header *eh;
|
||||||
|
struct eapol_sm *sm;
|
||||||
|
|
||||||
|
/* Validate Header */
|
||||||
|
|
||||||
|
if (len < sizeof(struct eapol_header))
|
||||||
|
return;
|
||||||
|
|
||||||
|
eh = (const struct eapol_header *) frame;
|
||||||
|
|
||||||
|
if (eh->protocol_version != EAPOL_PROTOCOL_VERSION_2001 &&
|
||||||
|
eh->protocol_version != EAPOL_PROTOCOL_VERSION_2004)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (len < (size_t) 4 + L_BE16_TO_CPU(eh->packet_len))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sm = eapol_find_sm(ifindex, spa, aa);
|
||||||
|
if (!sm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (eh->packet_type) {
|
||||||
|
case 0: /* EAPOL-EAP */
|
||||||
|
if (!sm->eap) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
eapol_key_handle(sm, ifindex, frame, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void __eapol_set_tx_packet_func(eapol_tx_packet_func_t func)
|
void __eapol_set_tx_packet_func(eapol_tx_packet_func_t func)
|
||||||
{
|
{
|
||||||
tx_packet = func;
|
tx_packet = func;
|
||||||
|
@ -1478,6 +1610,8 @@ bool eapol_init()
|
||||||
get_nonce = eapol_get_nonce;
|
get_nonce = eapol_get_nonce;
|
||||||
tx_packet = eapol_write;
|
tx_packet = eapol_write;
|
||||||
|
|
||||||
|
eap_init();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,5 +1621,7 @@ bool eapol_exit()
|
||||||
get_nonce = NULL;
|
get_nonce = NULL;
|
||||||
tx_packet = NULL;
|
tx_packet = NULL;
|
||||||
|
|
||||||
|
eap_exit();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,6 +175,8 @@ void eapol_sm_free(struct eapol_sm *sm);
|
||||||
void eapol_sm_set_supplicant_address(struct eapol_sm *sm, const uint8_t *spa);
|
void eapol_sm_set_supplicant_address(struct eapol_sm *sm, const uint8_t *spa);
|
||||||
void eapol_sm_set_authenticator_address(struct eapol_sm *sm, const uint8_t *aa);
|
void eapol_sm_set_authenticator_address(struct eapol_sm *sm, const uint8_t *aa);
|
||||||
void eapol_sm_set_pmk(struct eapol_sm *sm, const uint8_t *pmk);
|
void eapol_sm_set_pmk(struct eapol_sm *sm, const uint8_t *pmk);
|
||||||
|
void eapol_sm_set_8021x_config(struct eapol_sm *sm,
|
||||||
|
struct l_settings *settings);
|
||||||
void eapol_sm_set_ap_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
|
void eapol_sm_set_ap_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
|
||||||
size_t len);
|
size_t len);
|
||||||
bool eapol_sm_set_own_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
|
bool eapol_sm_set_own_rsn(struct eapol_sm *sm, const uint8_t *rsn_ie,
|
||||||
|
|
Loading…
Reference in New Issue