diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libcharon/plugins/eap_ttls/Makefile.am | 7 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls.c | 12 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls.h | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_avp.c | 105 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_avp.h | 68 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 100 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_server.c | 273 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_server.h | 47 |
8 files changed, 537 insertions, 79 deletions
diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am index 47be97908..94ce5cc1e 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.am +++ b/src/libcharon/plugins/eap_ttls/Makefile.am @@ -12,7 +12,10 @@ libstrongswan_eap_ttls_la_LIBADD = $(top_builddir)/src/libtls/libtls.la endif libstrongswan_eap_ttls_la_SOURCES = \ - eap_ttls_plugin.h eap_ttls_plugin.c eap_ttls.h eap_ttls.c \ - eap_ttls_peer.h eap_ttls_peer.c + eap_ttls_plugin.h eap_ttls_plugin.c \ + eap_ttls_avp.h eap_ttls_avp.c \ + eap_ttls.h eap_ttls.c \ + eap_ttls_peer.h eap_ttls_peer.c \ + eap_ttls_server.h eap_ttls_server.c libstrongswan_eap_ttls_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.c b/src/libcharon/plugins/eap_ttls/eap_ttls.c index dd24f401a..ad3360dee 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c @@ -15,6 +15,7 @@ #include "eap_ttls.h" #include "eap_ttls_peer.h" +#include "eap_ttls_server.h" #include <tls.h> @@ -424,8 +425,8 @@ METHOD(eap_method_t, destroy, void, * Generic private constructor */ static eap_ttls_t *eap_ttls_create(identification_t *server, - identification_t *peer, bool is_server, - tls_application_t *application) + identification_t *peer, bool is_server, + tls_application_t *application) { private_eap_ttls_t *this; @@ -447,13 +448,14 @@ static eap_ttls_t *eap_ttls_create(identification_t *server, } eap_ttls_t *eap_ttls_create_server(identification_t *server, - identification_t *peer) + identification_t *peer) { - return eap_ttls_create(server, peer, TRUE, NULL); + return eap_ttls_create(server, peer, TRUE, + &eap_ttls_server_create(server, peer)->application); } eap_ttls_t *eap_ttls_create_peer(identification_t *server, - identification_t *peer) + identification_t *peer) { return eap_ttls_create(server, peer, FALSE, &eap_ttls_peer_create(server, peer)->application); diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.h b/src/libcharon/plugins/eap_ttls/eap_ttls.h index 74cc83684..6e3bf2ceb 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.h +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.h @@ -44,7 +44,7 @@ struct eap_ttls_t { * @return eap_ttls_t object */ eap_ttls_t *eap_ttls_create_server(identification_t *server, - identification_t *peer); + identification_t *peer); /** * Creates the EAP method EAP-TTLS acting as peer. @@ -54,6 +54,6 @@ eap_ttls_t *eap_ttls_create_server(identification_t *server, * @return eap_ttls_t object */ eap_ttls_t *eap_ttls_create_peer(identification_t *server, - identification_t *peer); + identification_t *peer); #endif /** EAP_TTLS_H_ @}*/ diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c new file mode 100644 index 000000000..2c840dd72 --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include "eap_ttls_avp.h" + +#include <debug.h> + +#define AVP_EAP_MESSAGE 79 + +typedef struct private_eap_ttls_avp_t private_eap_ttls_avp_t; + +/** + * Private data of an eap_ttls_avp_t object. + */ +struct private_eap_ttls_avp_t { + + /** + * Public eap_ttls_avp_t interface. + */ + eap_ttls_avp_t public; +}; + +METHOD(eap_ttls_avp_t, build, void, + private_eap_ttls_avp_t *this, tls_writer_t *writer, chunk_t data) +{ + char zero_padding[] = { 0x00, 0x00, 0x00 }; + chunk_t avp_padding; + u_int8_t avp_flags; + u_int32_t avp_len; + + avp_flags = 0x40; + avp_len = 8 + data.len; + avp_padding = chunk_create(zero_padding, (4 - data.len) % 4); + + writer->write_uint32(writer, AVP_EAP_MESSAGE); + writer->write_uint8(writer, avp_flags); + writer->write_uint24(writer, avp_len); + writer->write_data(writer, data); + writer->write_data(writer, avp_padding); +} + +METHOD(eap_ttls_avp_t, process, status_t, + private_eap_ttls_avp_t* this, tls_reader_t *reader, chunk_t *data) +{ + u_int32_t avp_code; + u_int8_t avp_flags; + u_int32_t avp_len, data_len; + + if (!reader->read_uint32(reader, &avp_code) || + !reader->read_uint8(reader, &avp_flags) || + !reader->read_uint24(reader, &avp_len)) + { + DBG1(DBG_IKE, "received invalid AVP"); + return FAILED; + } + if (avp_code != AVP_EAP_MESSAGE) + { + DBG1(DBG_IKE, "expected AVP_EAP_MESSAGE but received %u", avp_code); + return FAILED; + } + data_len = avp_len - 8; + if (!reader->read_data(reader, data_len + (4 - avp_len) % 4, data)) + { + DBG1(DBG_IKE, "received insufficient AVP data"); + return FAILED; + } + data->len = data_len; + return SUCCESS; +} + +METHOD(eap_ttls_avp_t, destroy, void, + private_eap_ttls_avp_t *this) +{ + free(this); +} + +/** + * See header + */ +eap_ttls_avp_t *eap_ttls_avp_create(void) +{ + private_eap_ttls_avp_t *this; + + INIT(this, + .public= { + .process = _process, + .build = _build, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_avp.h b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.h new file mode 100644 index 000000000..cad1d9c56 --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_avp.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup eap_ttls_avp eap_ttls_avp + * @{ @ingroup eap_ttls + */ + +#ifndef EAP_TTLS_AVP_H_ +#define EAP_TTLS_AVP_H_ + +typedef struct eap_ttls_avp_t eap_ttls_avp_t; + +#include <library.h> + +#include <tls_reader.h> +#include <tls_writer.h> + +/** + * EAP-TTLS Attribute-Value Pair (AVP) handler. + */ +struct eap_ttls_avp_t { + + /** + * Process received EAP-TTLS EAP Message AVP. + * + * @param reader TLS data buffer + * @param data received EAP Message + * @return + * - SUCCESS if AVP processing succeeded + * - FAILED if AVP processing failed + * - NEED_MORE if another invocation of process/build needed + */ + status_t (*process)(eap_ttls_avp_t *this, tls_reader_t *reader, + chunk_t *data); + + /** + * Build EAP-TTLS EAP Message AVP to send out. + * + * @param writer TLS data buffer to write to + * @param data EAP Message to send + */ + void (*build)(eap_ttls_avp_t *this, tls_writer_t *writer, chunk_t data); + + /** + * Destroy a eap_ttls_application_t. + */ + void (*destroy)(eap_ttls_avp_t *this); +}; + +/** + * Create an eap_ttls_avp instance. + */ +eap_ttls_avp_t *eap_ttls_avp_create(void); + +#endif /** EAP_TTLS_AVP_H_ @}*/ diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index 566a75d8c..b47ed938d 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -14,14 +14,13 @@ */ #include "eap_ttls_peer.h" +#include "eap_ttls_avp.h" #include <debug.h> #include <daemon.h> #include <sa/authenticators/eap/eap_method.h> -#define AVP_EAP_MESSAGE 79 - typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; /** @@ -58,59 +57,12 @@ struct private_eap_ttls_peer_t { * Pending outbound EAP message */ eap_payload_t *out; -}; - -/** - * Send an EAP-Message Attribute-Value Pair - */ -static void send_avp_eap_message(tls_writer_t *writer, chunk_t data) -{ - char zero_padding[] = { 0x00, 0x00, 0x00 }; - chunk_t avp_padding; - u_int8_t avp_flags; - u_int32_t avp_len; - - avp_flags = 0x40; - avp_len = 8 + data.len; - avp_padding = chunk_create(zero_padding, (4 - data.len) % 4); - - writer->write_uint32(writer, AVP_EAP_MESSAGE); - writer->write_uint8(writer, avp_flags); - writer->write_uint24(writer, avp_len); - writer->write_data(writer, data); - writer->write_data(writer, avp_padding); -} -/** - * Process an EAP-Message Attribute-Value Pair - */ -static status_t process_avp_eap_message(tls_reader_t *reader, chunk_t *data) -{ - u_int32_t avp_code; - u_int8_t avp_flags; - u_int32_t avp_len, data_len; - - if (!reader->read_uint32(reader, &avp_code) || - !reader->read_uint8(reader, &avp_flags) || - !reader->read_uint24(reader, &avp_len)) - { - DBG1(DBG_IKE, "received invalid AVP"); - return FAILED; - } - if (avp_code != AVP_EAP_MESSAGE) - { - DBG1(DBG_IKE, "expected AVP_EAP_MESSAGE but received %u", avp_code); - return FAILED; - } - data_len = avp_len - 8; - if (!reader->read_data(reader, data_len + (4 - avp_len) % 4, data)) - { - DBG1(DBG_IKE, "received insufficient AVP data"); - return FAILED; - } - data->len = data_len; - return SUCCESS; -} + /** + * AVP handler + */ + eap_ttls_avp_t *avp; +}; METHOD(tls_application_t, process, status_t, private_eap_ttls_peer_t *this, tls_reader_t *reader) @@ -120,10 +72,10 @@ METHOD(tls_application_t, process, status_t, payload_t *payload; eap_payload_t *in; eap_code_t code; - eap_type_t type; - u_int32_t vendor; + eap_type_t type, received_type; + u_int32_t vendor, received_vendor; - status = process_avp_eap_message(reader, &data); + status = this->avp->process(this->avp, reader, &data); if (status == FAILED) { return FAILED; @@ -137,37 +89,36 @@ METHOD(tls_application_t, process, status_t, return FAILED; } code = in->get_code(in); - type = in->get_type(in, &vendor); + received_type = in->get_type(in, &received_vendor); DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP [EAP/%N/%N]", - eap_code_short_names, code, eap_type_short_names, type); - + eap_code_short_names, code, + eap_type_short_names, received_type); if (code != EAP_REQUEST) { + DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_REQUEST); in->destroy(in); return FAILED; } if (this->method == NULL) { - if (vendor) + if (received_vendor) { DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d", - type, vendor); + received_type, received_vendor); } else { DBG1(DBG_IKE, "server requested %N authentication", - eap_type_names, type); + eap_type_names, received_type); } - this->method = charon->eap->create_instance(charon->eap, type, vendor, + this->method = charon->eap->create_instance(charon->eap, + received_type, received_vendor, EAP_PEER, this->server, this->peer); if (!this->method) { - u_int8_t identifier = in->get_identifier(in); - - DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); - in->destroy(in); - this->out = eap_payload_create_nak(identifier); + DBG1(DBG_IKE, "EAP method not supported"); + this->out = eap_payload_create_nak(in->get_identifier(in)); in->destroy(in); return NEED_MORE; } @@ -175,6 +126,13 @@ METHOD(tls_application_t, process, status_t, type = this->method->get_type(this->method, &vendor); + if (type != received_type || vendor != received_vendor) + { + DBG1(DBG_IKE, "received invalid EAP request"); + in->destroy(in); + return FAILED; + } + if (this->method->process(this->method, in, &this->out) == NEED_MORE) { in->destroy(in); @@ -226,7 +184,7 @@ METHOD(tls_application_t, build, status_t, /* get the raw EAP message data */ data = this->out->get_data(this->out); - send_avp_eap_message(writer, data); + this->avp->build(this->avp, writer, data); this->out->destroy(this->out); this->out = NULL; @@ -241,6 +199,7 @@ METHOD(tls_application_t, destroy, void, this->peer->destroy(this->peer); DESTROY_IF(this->method); DESTROY_IF(this->out); + this->avp->destroy(this->avp); free(this); } @@ -263,6 +222,7 @@ eap_ttls_peer_t *eap_ttls_peer_create(identification_t *server, .start_phase2 = TRUE, .method = NULL, .out = NULL, + .avp = eap_ttls_avp_create(), ); return &this->public; diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c new file mode 100644 index 000000000..45fc79460 --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include "eap_ttls_server.h" +#include "eap_ttls_avp.h" + +#include <debug.h> +#include <daemon.h> + +#include <sa/authenticators/eap/eap_method.h> + +typedef struct private_eap_ttls_server_t private_eap_ttls_server_t; + +/** + * Private data of an eap_ttls_server_t object. + */ +struct private_eap_ttls_server_t { + + /** + * Public eap_ttls_server_t interface. + */ + eap_ttls_server_t public; + + /** + * Server identity + */ + identification_t *server; + + /** + * Peer identity + */ + identification_t *peer; + + /** + * Current EAP-TTLS state + */ + bool start_phase2; + + /** + * Current phase 2 EAP method + */ + eap_method_t *method; + + /** + * Pending outbound EAP message + */ + eap_payload_t *out; + + /** + * AVP handler + */ + eap_ttls_avp_t *avp; +}; + +METHOD(tls_application_t, process, status_t, + private_eap_ttls_server_t *this, tls_reader_t *reader) +{ + chunk_t data; + status_t status; + payload_t *payload; + eap_payload_t *in; + eap_code_t code; + eap_type_t type, received_type; + u_int32_t vendor, received_vendor; + + status = this->avp->process(this->avp, reader, &data); + if (status == FAILED) + { + return FAILED; + } + in = eap_payload_create_data(data); + payload = (payload_t*)in; + + if (payload->verify(payload) != SUCCESS) + { + in->destroy(in); + return FAILED; + } + code = in->get_code(in); + received_type = in->get_type(in, &received_vendor); + DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP [EAP/%N/%N]", + eap_code_short_names, code, + eap_type_short_names, received_type); + if (code != EAP_RESPONSE) + { + DBG1(DBG_IKE, "%N expected", eap_code_names, EAP_RESPONSE); + in->destroy(in); + return FAILED; + } + + if (this->method) + { + type = this->method->get_type(this->method, &vendor); + + if (type != received_type || vendor != received_vendor) + { + if (received_vendor == 0 && received_type == EAP_NAK) + { + DBG1(DBG_IKE, "peer does not support %N", eap_type_names, type); + } + else + { + DBG1(DBG_IKE, "received invalid EAP response"); + } + in->destroy(in); + return FAILED; + } + } + + if (!received_vendor && received_type == EAP_IDENTITY) + { + chunk_t eap_id; + char * eap_type_str; + + if (this->method == NULL) + { + /* Received an EAP Identity response without a matching request */ + this->method = charon->eap->create_instance(charon->eap, + EAP_IDENTITY, 0, EAP_SERVER, + this->server, this->peer); + if (this->method == NULL) + { + DBG1(DBG_IKE, "%N method not available", + eap_type_names, EAP_IDENTITY); + return FAILED; + } + } + + if (this->method->process(this->method, in, &this->out) != SUCCESS) + { + + DBG1(DBG_IKE, "%N method failed", eap_type_names, EAP_IDENTITY); + return FAILED; + } + + if (this->method->get_msk(this->method, &eap_id) == SUCCESS) + { + this->peer->destroy(this->peer); + this->peer = identification_create_from_data(eap_id); + DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer); + } + + in->destroy(in); + this->method->destroy(this->method); + this->method = NULL; + + /* Start Phase 2 of EAP-TTLS authentication */ + eap_type_str = lib->settings->get_str(lib->settings, + "charon.plugins.eap-ttls.phase2_method", "md5"); + type = eap_type_from_string(eap_type_str); + if (type == 0) + { + DBG1(DBG_IKE, "unrecognized phase2 method \"%s\"", eap_type_str); + return FAILED; + } + DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, type); + + this->method = charon->eap->create_instance(charon->eap, type, 0, + EAP_SERVER, this->server, this->peer); + if (this->method == NULL) + { + DBG1(DBG_IKE, "%N method not available", eap_type_names, type); + return FAILED; + } + if (this->method->initiate(this->method, &this->out) == NEED_MORE) + { + return NEED_MORE; + } + else + { + DBG1(DBG_IKE, "%N method failed", eap_type_names, type); + return FAILED; + } + } + + if (this->method == 0) + { + DBG1(DBG_IKE, "no %N phase2 method installed", eap_type_names, EAP_TTLS); + in->destroy(in); + return FAILED; + } + + status = this->method->process(this->method, in, &this->out); + in->destroy(in); + + switch (status) + { + case SUCCESS: + DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful", + eap_type_names, EAP_TTLS, this->peer, + eap_type_names, type); + break; + case NEED_MORE: + break; + case FAILED: + default: + DBG1(DBG_IKE, "%N method failed", eap_type_names, type); + } + return status; +} + +METHOD(tls_application_t, build, status_t, + private_eap_ttls_server_t *this, tls_writer_t *writer) +{ + chunk_t data; + eap_code_t code; + eap_type_t type; + u_int32_t vendor; + + if (this->out) + { + code = this->out->get_code(this->out); + type = this->out->get_type(this->out, &vendor); + DBG1(DBG_IKE, "sending tunneled EAP-TTLS AVP [EAP/%N/%N]", + eap_code_short_names, code, eap_type_short_names, type); + + /* get the raw EAP message data */ + data = this->out->get_data(this->out); + this->avp->build(this->avp, writer, data); + + this->out->destroy(this->out); + this->out = NULL; + } + return INVALID_STATE; +} + +METHOD(tls_application_t, destroy, void, + private_eap_ttls_server_t *this) +{ + this->server->destroy(this->server); + this->peer->destroy(this->peer); + DESTROY_IF(this->method); + DESTROY_IF(this->out); + this->avp->destroy(this->avp); + free(this); +} + +/** + * See header + */ +eap_ttls_server_t *eap_ttls_server_create(identification_t *server, + identification_t *peer) +{ + private_eap_ttls_server_t *this; + + INIT(this, + .public.application = { + .process = _process, + .build = _build, + .destroy = _destroy, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + .start_phase2 = TRUE, + .method = NULL, + .out = NULL, + .avp = eap_ttls_avp_create(), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.h b/src/libcharon/plugins/eap_ttls/eap_ttls_server.h new file mode 100644 index 000000000..a66a813ec --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +/** + * @defgroup eap_ttls_server eap_ttls_server + * @{ @ingroup eap_ttls + */ + +#ifndef EAP_TTLS_SERVER_H_ +#define EAP_TTLS_SERVER_H_ + +typedef struct eap_ttls_server_t eap_ttls_server_t; + +#include "tls_application.h" + +#include <library.h> + +/** + * TLS application data handler as server. + */ +struct eap_ttls_server_t { + + /** + * Implements the TLS application data handler. + */ + tls_application_t application; +}; + +/** + * Create an eap_ttls_server instance. + */ +eap_ttls_server_t *eap_ttls_server_create(identification_t *server, + identification_t *peer); + +#endif /** EAP_TTLS_SERVER_H_ @}*/ |