From be751012c3d297716fdd9af70b2fa8c54bc28df6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 31 Aug 2010 09:12:20 +0200 Subject: [PATCH] Migrated EAP-TLS to the generic TLS helper --- src/libcharon/plugins/eap_tls/eap_tls.c | 291 ++---------------------- 1 file changed, 19 insertions(+), 272 deletions(-) diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c index 155038056..3332788eb 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.c +++ b/src/libcharon/plugins/eap_tls/eap_tls.c @@ -15,7 +15,7 @@ #include "eap_tls.h" -#include +#include #include #include @@ -38,294 +38,46 @@ struct private_eap_tls_t { int processed; /** - * Is this method instance acting as server? + * TLS stack, wrapped by EAP helper */ - bool is_server; - - /** - * TLS layers - */ - tls_t *tls; - - /** - * Allocated input buffer - */ - chunk_t input; - - /** - * Number of bytes read in input buffer - */ - size_t inpos; - - /** - * Allocated ouput buffer - */ - chunk_t output; - - /** - * Number of bytes sent from output buffer - */ - size_t outpos; + tls_eap_t *tls_eap; }; -/** Size limit for a single TLS message */ -#define MAX_TLS_MESSAGE_LEN 65536 -/** Size of a EAP-TLS fragment */ -#define EAP_TLS_FRAGMENT_LEN 1014 /** Maximum number of EAP-TLS messages/fragments allowed */ -#define MAX_EAP_TLS_MESSAGE_COUNT 32 - -/** - * Flags of an EAP-TLS message - */ -typedef enum { - EAP_TLS_LENGTH = (1<<7), - EAP_TLS_MORE_FRAGS = (1<<6), - EAP_TLS_START = (1<<5), -} eap_tls_flags_t; - -/** - * EAP-TLS packet format - */ -typedef struct __attribute__((packed)) { - u_int8_t code; - u_int8_t identifier; - u_int16_t length; - u_int8_t type; - u_int8_t flags; -} eap_tls_packet_t; +#define MAX_EAP_TLS_MESSAGE_COUNT 24 METHOD(eap_method_t, initiate, status_t, private_eap_tls_t *this, eap_payload_t **out) { - if (this->is_server) - { - eap_tls_packet_t pkt = { - .type = EAP_TLS, - .code = EAP_REQUEST, - .flags = EAP_TLS_START, - }; - htoun16(&pkt.length, sizeof(eap_tls_packet_t)); - /* start with non-zero random identifier */ - do { - pkt.identifier = random(); - } while (!pkt.identifier); - DBG2(DBG_IKE, "sending EAP-TLS start packet"); + chunk_t data; - *out = eap_payload_create_data(chunk_from_thing(pkt)); + if (this->tls_eap->initiate(this->tls_eap, &data) == NEED_MORE) + { + *out = eap_payload_create_data(data); + free(data.ptr); return NEED_MORE; } return FAILED; } -/** - * Write received TLS data to the input buffer - */ -static bool write_buf(private_eap_tls_t *this, eap_tls_packet_t *pkt) -{ - u_int32_t msg_len; - u_int16_t pkt_len; - chunk_t data; - - pkt_len = untoh16(&pkt->length); - - if (pkt->flags & EAP_TLS_LENGTH) - { - if (pkt_len < sizeof(eap_tls_packet_t) + sizeof(msg_len)) - { - DBG1(DBG_IKE, "EAP-TLS packet too short"); - return FALSE; - } - msg_len = untoh32(pkt + 1); - if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) || - msg_len > MAX_TLS_MESSAGE_LEN) - { - DBG1(DBG_IKE, "invalid EAP-TLS packet length"); - return FALSE; - } - if (this->input.ptr) - { - if (msg_len != this->input.len) - { - DBG1(DBG_IKE, "received unexpected TLS message length"); - return FALSE; - } - } - else - { - this->input = chunk_alloc(msg_len); - this->inpos = 0; - } - data = chunk_create((char*)(pkt + 1) + sizeof(msg_len), - pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len)); - } - else - { - data = chunk_create((char*)(pkt + 1), - pkt_len - sizeof(eap_tls_packet_t)); - } - DBG2(DBG_IKE, "received EAP-TLS %s (%u bytes)", - (pkt->flags & EAP_TLS_MORE_FRAGS) ? "fragment" : "packet", pkt_len); - - if (data.len > this->input.len - this->inpos) - { - DBG1(DBG_IKE, "EAP-TLS fragment exceeds TLS message length"); - return FALSE; - } - memcpy(this->input.ptr + this->inpos, data.ptr, data.len); - this->inpos += data.len; - return TRUE; -} - -/** - * Send an ack to request next fragment - */ -static eap_payload_t *create_ack(private_eap_tls_t *this, u_int8_t identifier) -{ - eap_tls_packet_t pkt = { - .code = this->is_server ? EAP_REQUEST : EAP_RESPONSE, - .identifier = this->is_server ? identifier + 1 : identifier, - .type = EAP_TLS, - }; - htoun16(&pkt.length, sizeof(pkt)); - DBG2(DBG_IKE, "sending EAP-TLS acknowledgement packet"); - - return eap_payload_create_data(chunk_from_thing(pkt)); -} - -/** - * Create a eap response from data in the TLS output buffer - */ -static eap_payload_t *read_buf(private_eap_tls_t *this, u_int8_t identifier) -{ - char buf[EAP_TLS_FRAGMENT_LEN + sizeof(eap_tls_packet_t) + 4], *start; - eap_tls_packet_t *pkt = (eap_tls_packet_t*)buf; - u_int16_t pkt_len = sizeof(eap_tls_packet_t); - - pkt->code = this->is_server ? EAP_REQUEST : EAP_RESPONSE; - pkt->identifier = this->is_server ? identifier + 1 : identifier; - pkt->type = EAP_TLS; - pkt->flags = 0; - - if (this->output.len) - { - start = (char*)(pkt + 1); - if (this->outpos == 0) - { /* first fragment */ - pkt->flags = EAP_TLS_LENGTH; - pkt_len += 4; - start += 4; - htoun32(pkt + 1, this->output.len); - } - - if (this->output.len - this->outpos > EAP_TLS_FRAGMENT_LEN) - { - pkt->flags |= EAP_TLS_MORE_FRAGS; - pkt_len += EAP_TLS_FRAGMENT_LEN; - memcpy(start, this->output.ptr + this->outpos, EAP_TLS_FRAGMENT_LEN); - this->outpos += EAP_TLS_FRAGMENT_LEN; - DBG2(DBG_IKE, "sending EAP-TLS fragment (%u bytes)", pkt_len); - } - else - { - pkt_len += this->output.len - this->outpos; - memcpy(start, this->output.ptr + this->outpos, - this->output.len - this->outpos); - chunk_free(&this->output); - this->outpos = 0; - DBG2(DBG_IKE, "sending EAP-TLS packet (%u bytes)", pkt_len); - } - } - else - { - DBG2(DBG_IKE, "sending EAP-TLS acknowledgement packet"); - } - htoun16(&pkt->length, pkt_len); - return eap_payload_create_data(chunk_create(buf, pkt_len)); -} - -/** - * Pass data in input buffer to upper layers, write result to output buffer - */ -static status_t process_buf(private_eap_tls_t *this) -{ - status_t status; - - status = this->tls->process(this->tls, this->input.ptr, this->input.len); - if (status != NEED_MORE) - { - return status; - } - chunk_free(&this->input); - this->inpos = 0; - - chunk_free(&this->output); - this->output = chunk_alloc(EAP_TLS_FRAGMENT_LEN); - return this->tls->build(this->tls, this->output.ptr, &this->output.len, NULL); -} - METHOD(eap_method_t, process, status_t, private_eap_tls_t *this, eap_payload_t *in, eap_payload_t **out) { - eap_tls_packet_t *pkt; - chunk_t data; status_t status; + chunk_t data; if (++this->processed > MAX_EAP_TLS_MESSAGE_COUNT) { - DBG1(DBG_IKE, "EAP-TLS packet count exceeded"); + DBG1(DBG_IKE, "EAP-TLS packet count exceeded (%d > %d)", + this->processed, MAX_EAP_TLS_MESSAGE_COUNT); return FAILED; } - data = in->get_data(in); - - pkt = (eap_tls_packet_t*)data.ptr; - if (data.len < sizeof(eap_tls_packet_t) || - untoh16(&pkt->length) != data.len) - { - DBG1(DBG_IKE, "invalid EAP-TLS packet length"); - return FAILED; - } - if (!(pkt->flags & EAP_TLS_START)) - { - if (data.len == sizeof(eap_tls_packet_t)) - { - if (this->output.len) - { /* ACK to our fragment, send next */ - *out = read_buf(this, pkt->identifier); - return NEED_MORE; - } - if (this->tls->is_complete(this->tls)) - { - return SUCCESS; - } - return FAILED; - } - if (!write_buf(this, pkt)) - { - return FAILED; - } - if (pkt->flags & EAP_TLS_MORE_FRAGS) - { /* more fragments follow */ - *out = create_ack(this, pkt->identifier); - return NEED_MORE; - } - else if (this->input.len != this->inpos) - { - DBG1(DBG_IKE, "defragmented TLS message has invalid length"); - return FAILED; - } - } - status = process_buf(this); + status = this->tls_eap->process(this->tls_eap, data, &data); if (status == NEED_MORE) { - *out = read_buf(this, pkt->identifier); - } - else if (status == FAILED && !this->is_server) - { /* client sends an empty TLS message, waits for a EAP-Failure */ - chunk_free(&this->output); - *out = read_buf(this, pkt->identifier); - return NEED_MORE; + *out = eap_payload_create_data(data); + free(data.ptr); } return status; } @@ -340,7 +92,7 @@ METHOD(eap_method_t, get_type, eap_type_t, METHOD(eap_method_t, get_msk, status_t, private_eap_tls_t *this, chunk_t *msk) { - *msk = this->tls->get_eap_msk(this->tls); + *msk = this->tls_eap->get_msk(this->tls_eap); if (msk->len) { return SUCCESS; @@ -357,11 +109,7 @@ METHOD(eap_method_t, is_mutual, bool, METHOD(eap_method_t, destroy, void, private_eap_tls_t *this) { - free(this->input.ptr); - free(this->output.ptr); - - this->tls->destroy(this->tls); - + this->tls_eap->destroy(this->tls_eap); free(this); } @@ -384,11 +132,10 @@ static eap_tls_t *eap_tls_create(identification_t *server, .destroy = _destroy, }, }, - .is_server = is_server, ); - this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL); - if (!this->tls) + this->tls_eap = tls_eap_create(EAP_TLS, is_server, server, peer, NULL); + if (!this->tls_eap) { free(this); return NULL;