3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-26 18:59:22 +01:00

ttls: introduce phase2_method structure

The struct allows to support multiple types of the tunneled methods.
Previously, EAP-TTLS was supporting only the eap based ones.
This patch is also starts to move some of the phase 2 EAP
functionality into the new structure.
This commit is contained in:
Tim Kourt 2018-09-21 13:17:56 -07:00 committed by Denis Kenzior
parent a7f5d1da21
commit 71ba8ac765

View File

@ -33,6 +33,23 @@
#include "eap.h" #include "eap.h"
#include "eap-private.h" #include "eap-private.h"
enum radius_attr {
RADIUS_ATTR_EAP_MESSAGE = 79,
};
struct phase2_method {
void *state;
bool (*init)(struct eap_state *eap);
bool (*handle_avp)(struct eap_state *eap, enum radius_attr type,
uint32_t vendor_id, const uint8_t *data,
size_t len);
bool (*load_settings)(struct eap_state *eap,
struct l_settings *settings,
const char *prefix);
void (*destroy)(struct eap_state *eap);
bool (*reset)(struct eap_state *eap);
};
struct eap_ttls_state { struct eap_ttls_state {
char *ca_cert; char *ca_cert;
char *client_cert; char *client_cert;
@ -49,6 +66,8 @@ struct eap_ttls_state {
bool completed; bool completed;
struct eap_state *phase2_eap; struct eap_state *phase2_eap;
uint8_t negotiated_version; uint8_t negotiated_version;
struct phase2_method *phase2;
}; };
static void __eap_ttls_reset_state(struct eap_ttls_state *ttls) static void __eap_ttls_reset_state(struct eap_ttls_state *ttls)
@ -81,13 +100,11 @@ static bool eap_ttls_reset_state(struct eap_state *eap)
{ {
struct eap_ttls_state *ttls = eap_get_data(eap); struct eap_ttls_state *ttls = eap_get_data(eap);
if (!ttls->phase2_eap) if (ttls->phase2->reset)
return false; ttls->phase2->reset(eap);
if (!eap_reset(ttls->phase2_eap))
return false;
__eap_ttls_reset_state(ttls); __eap_ttls_reset_state(ttls);
return true; return true;
} }
@ -97,6 +114,9 @@ static void eap_ttls_free(struct eap_state *eap)
__eap_ttls_reset_state(ttls); __eap_ttls_reset_state(ttls);
if (ttls->phase2->destroy)
ttls->phase2->destroy(eap);
eap_set_data(eap, NULL); eap_set_data(eap, NULL);
l_free(ttls->ca_cert); l_free(ttls->ca_cert);
@ -108,11 +128,6 @@ static void eap_ttls_free(struct eap_state *eap)
l_free(ttls->passphrase); l_free(ttls->passphrase);
} }
if (ttls->phase2_eap) {
eap_free(ttls->phase2_eap);
ttls->phase2_eap = NULL;
}
l_free(ttls); l_free(ttls);
} }
@ -124,6 +139,98 @@ static void eap_ttls_free(struct eap_state *eap)
#define EAP_TTLS_FLAG_MASK \ #define EAP_TTLS_FLAG_MASK \
(EAP_TTLS_FLAG_L | EAP_TTLS_FLAG_M | EAP_TTLS_FLAG_S) (EAP_TTLS_FLAG_L | EAP_TTLS_FLAG_M | EAP_TTLS_FLAG_S)
static void eap_ttls_phase2_eap_send_response(const uint8_t *data, size_t len,
void *user_data)
{
}
static void eap_ttls_phase2_eap_complete(enum eap_result result,
void *user_data)
{
struct eap_state *eap = user_data;
struct eap_ttls_state *ttls = eap_get_data(eap);
ttls->completed = true;
}
static bool eap_ttls_phase2_eap_load_settings(struct eap_state *eap,
struct l_settings *settings,
const char *prefix)
{
struct eap_ttls_state *ttls = eap_get_data(eap);
ttls->phase2->state = eap_new(eap_ttls_phase2_eap_send_response,
eap_ttls_phase2_eap_complete,
eap);
if (!ttls->phase2->state) {
l_error("Could not create the TTLS Phase 2 EAP instance");
return false;
}
if (!eap_load_settings(ttls->phase2->state, settings, prefix)) {
eap_free(ttls->phase2->state);
return false;
}
return true;
}
static bool eap_ttls_phase2_eap_init(struct eap_state *eap)
{
struct eap_ttls_state *ttls = eap_get_data(eap);
uint8_t packet[5] = { EAP_CODE_REQUEST, 0, 0, 5, EAP_TYPE_IDENTITY };
if (!ttls->phase2->state)
return false;
/*
* Consume a fake Request/Identity packet so that the EAP instance
* starts with its Response/Identity right away.
*/
eap_rx_packet(ttls->phase2->state, packet, sizeof(packet));
return true;
}
static bool eap_ttls_phase2_eap_handle_avp(struct eap_state *eap,
enum radius_attr type,
uint32_t vendor_id,
const uint8_t *data,
size_t len)
{
return true;
}
static void eap_ttls_phase2_eap_destroy(struct eap_state *eap)
{
struct eap_ttls_state *ttls = eap_get_data(eap);
if (!ttls->phase2->state)
return;
eap_reset(ttls->phase2->state);
eap_free(ttls->phase2->state);
ttls->phase2->state = NULL;
}
static bool eap_ttls_phase2_eap_reset(struct eap_state *eap)
{
struct eap_ttls_state *ttls = eap_get_data(eap);
if (!ttls->phase2->state)
return false;
return eap_reset(ttls->phase2->state);
}
static struct phase2_method phase2_eap = {
.load_settings = eap_ttls_phase2_eap_load_settings,
.init = eap_ttls_phase2_eap_init,
.handle_avp = eap_ttls_phase2_eap_handle_avp,
.destroy = eap_ttls_phase2_eap_destroy,
.reset = eap_ttls_phase2_eap_reset,
};
static uint8_t *eap_ttls_tx_buf_reserve(struct eap_ttls_state *ttls, static uint8_t *eap_ttls_tx_buf_reserve(struct eap_ttls_state *ttls,
size_t size) size_t size)
{ {
@ -294,50 +401,12 @@ static void eap_ttls_data_cb(const uint8_t *data, size_t len, void *user_data)
ttls->avp_received = len; ttls->avp_received = len;
} }
static void eap_ttls_eap_tx_packet(const uint8_t *eap_data, size_t len,
void *user_data)
{
struct eap_state *eap = user_data;
struct eap_ttls_state *ttls = eap_get_data(eap);
uint8_t buf[sizeof(struct eap_ttls_avp) + len + 3];
struct eap_ttls_avp *avp = (struct eap_ttls_avp *) buf;
size_t avp_len = sizeof(struct eap_ttls_avp) + len;
l_put_be32(RADIUS_AVP_EAP_MESSAGE, &avp->avp_code);
avp->avp_flags = EAP_TTLS_AVP_FLAG_M;
avp->avp_len[0] = avp_len >> 16;
avp->avp_len[1] = avp_len >> 8;
avp->avp_len[2] = avp_len >> 0;
memcpy(avp->data, eap_data, len);
if (avp_len & 3)
memset(avp->data + len, 0, 4 - (avp_len & 3));
l_tls_write(ttls->tls, buf, (avp_len + 3) & ~3);
}
static void eap_ttls_eap_complete(enum eap_result result, void *user_data)
{
struct eap_state *eap = user_data;
struct eap_ttls_state *ttls = eap_get_data(eap);
/*
* TODO: We currently do not implement chaining per Section 11.3,
* so simply set completed to true
*/
ttls->completed = true;
}
static void eap_ttls_ready_cb(const char *peer_identity, void *user_data) static void eap_ttls_ready_cb(const char *peer_identity, void *user_data)
{ {
struct eap_state *eap = user_data; struct eap_state *eap = user_data;
struct eap_ttls_state *ttls = eap_get_data(eap); struct eap_ttls_state *ttls = eap_get_data(eap);
uint8_t msk_emsk[128]; uint8_t msk_emsk[128];
uint8_t seed[64]; uint8_t seed[64];
uint8_t packet[5] = { EAP_CODE_REQUEST, 0, 0, 5, EAP_TYPE_IDENTITY };
/* TODO: if we have a CA certificate require non-NULL peer_identity */ /* TODO: if we have a CA certificate require non-NULL peer_identity */
@ -365,15 +434,11 @@ static void eap_ttls_ready_cb(const char *peer_identity, void *user_data)
eap_set_key_material(eap, msk_emsk + 0, 64, msk_emsk + 64, 64, eap_set_key_material(eap, msk_emsk + 0, 64, msk_emsk + 64, 64,
NULL, 0); NULL, 0);
/* Start the EAP negotiation */ if (!ttls->phase2->state)
if (!ttls->phase2_eap)
goto err; goto err;
/* if (ttls->phase2->init)
* Consume a fake Request/Identity packet so that the EAP instance ttls->phase2->init(eap);
* starts with its Response/Identity right away.
*/
eap_rx_packet(ttls->phase2_eap, packet, sizeof(packet));
return; return;
err: err:
@ -772,25 +837,19 @@ static bool eap_ttls_load_settings(struct eap_state *eap,
prefix); prefix);
ttls->passphrase = l_settings_get_string(settings, "Security", setting); ttls->passphrase = l_settings_get_string(settings, "Security", setting);
ttls->phase2_eap = eap_new(eap_ttls_eap_tx_packet, ttls->phase2 = &phase2_eap;
eap_ttls_eap_complete, eap);
if (!ttls->phase2_eap) {
l_error("Could not create the TTLS inner EAP instance");
goto err;
}
snprintf(setting, sizeof(setting), "%sTTLS-Phase2-", prefix);
if (!eap_load_settings(ttls->phase2_eap, settings, setting)) {
eap_free(ttls->phase2_eap);
goto err;
}
eap_set_data(eap, ttls); eap_set_data(eap, ttls);
snprintf(setting, sizeof(setting), "%sTTLS-Phase2-", prefix);
if (ttls->phase2->load_settings &&
!ttls->phase2->load_settings(eap, settings, setting))
goto err;
return true; return true;
err: err:
eap_set_data(eap, NULL);
l_free(ttls->ca_cert); l_free(ttls->ca_cert);
l_free(ttls->client_cert); l_free(ttls->client_cert);
l_free(ttls->client_key); l_free(ttls->client_key);