mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-22 23:09:34 +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:
parent
a7f5d1da21
commit
71ba8ac765
195
src/eap-ttls.c
195
src/eap-ttls.c
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user