diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2010-08-12 23:56:44 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2010-08-12 23:58:54 +0200 |
commit | 1327839da8e92c101dbe160d6e82d83b5ed6e788 (patch) | |
tree | 87136a6eae9a99ae5b58eb8f8fac3297ccc3a7ee | |
parent | 123a84d3dba9c5e88f101aab222db44e25db5a4a (diff) | |
download | strongswan-1327839da8e92c101dbe160d6e82d83b5ed6e788.tar.bz2 strongswan-1327839da8e92c101dbe160d6e82d83b5ed6e788.tar.xz |
added generic TLS application data handler and specific EAP-TTLS instantiation
-rw-r--r-- | src/libcharon/plugins/eap_tls/eap_tls.c | 3 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/Makefile.am | 3 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls.c | 13 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 96 | ||||
-rw-r--r-- | src/libcharon/plugins/eap_ttls/eap_ttls_peer.h | 46 | ||||
-rw-r--r-- | src/libtls/Makefile.am | 2 | ||||
-rw-r--r-- | src/libtls/tls.c | 13 | ||||
-rw-r--r-- | src/libtls/tls.h | 6 | ||||
-rw-r--r-- | src/libtls/tls_application.h | 64 | ||||
-rw-r--r-- | src/libtls/tls_fragmentation.c | 96 | ||||
-rw-r--r-- | src/libtls/tls_fragmentation.h | 5 | ||||
-rw-r--r-- | src/libtls/tls_handshake.h | 7 | ||||
-rw-r--r-- | src/libtls/tls_peer.c | 7 | ||||
-rw-r--r-- | src/libtls/tls_server.c | 7 |
14 files changed, 335 insertions, 33 deletions
diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c index a2407e51d..e4f12d7f6 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.c +++ b/src/libcharon/plugins/eap_tls/eap_tls.c @@ -433,7 +433,8 @@ static eap_tls_t *eap_tls_create(identification_t *server, .is_server = is_server, ); /* MSK PRF ASCII constant label according to EAP-TLS RFC 5216 */ - this->tls = tls_create(is_server, server, peer, "client EAP encryption"); + this->tls = tls_create(is_server, server, peer, "client EAP encryption", + NULL); return &this->public; } diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am index fdd4606d0..47be97908 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.am +++ b/src/libcharon/plugins/eap_ttls/Makefile.am @@ -12,6 +12,7 @@ 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_plugin.h eap_ttls_plugin.c eap_ttls.h eap_ttls.c \ + eap_ttls_peer.h eap_ttls_peer.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 1139a3f3d..04ae13854 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c @@ -14,6 +14,7 @@ */ #include "eap_ttls.h" +#include "eap_ttls_peer.h" #include <tls.h> @@ -423,7 +424,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) + identification_t *peer, bool is_server, + tls_application_t *application) { private_eap_ttls_t *this; @@ -439,19 +441,20 @@ static eap_ttls_t *eap_ttls_create(identification_t *server, .is_server = is_server, ); /* MSK PRF ASCII constant label according to EAP-TTLS RFC 5281 */ - this->tls = tls_create(is_server, server, peer, "ttls keying material"); - + this->tls = tls_create(is_server, server, peer, "ttls keying material", + application); return &this->public; } eap_ttls_t *eap_ttls_create_server(identification_t *server, identification_t *peer) { - return eap_ttls_create(server, peer, TRUE); + return eap_ttls_create(server, peer, TRUE, NULL); } eap_ttls_t *eap_ttls_create_peer(identification_t *server, identification_t *peer) { - return eap_ttls_create(server, peer, FALSE); + return eap_ttls_create(server, peer, FALSE, + &eap_ttls_peer_create(peer)->application); } diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c new file mode 100644 index 000000000..0e4d70fa8 --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -0,0 +1,96 @@ +/* + * 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_peer.h" + +#include <debug.h> + +#define AVP_EAP_MESSAGE 79 + +typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; + +/** + * Private data of an eap_ttls_peer_t object. + */ +struct private_eap_ttls_peer_t { + + /** + * Public eap_ttls_peer_t interface. + */ + eap_ttls_peer_t public; + + /** + * Peer identity + */ + identification_t *peer; + + /** + * EAP-TTLS state information + */ + bool start_phase2; +}; + + +METHOD(tls_application_t, process, status_t, + private_eap_ttls_peer_t *this, tls_reader_t *reader) +{ + return NEED_MORE; +} + +METHOD(tls_application_t, build, status_t, + private_eap_ttls_peer_t *this, tls_writer_t *writer) +{ + if (this->start_phase2) + { + chunk_t data = chunk_from_chars( + 0x02, 0x00, 0x00, 10, 0x01, 'c', 'a', 'r', 'o', 'l', 0x00, 0x00); + u_int8_t avp_flags = 0x40; + u_int32_t avp_len; + + avp_len = 8 + data.len - 2; + writer->write_uint32(writer, AVP_EAP_MESSAGE); + writer->write_uint8(writer, avp_flags); + writer->write_uint24(writer, avp_len); + writer->write_data(writer, data); + this->start_phase2 = FALSE; + } + return INVALID_STATE; +} + +METHOD(tls_application_t, destroy, void, + private_eap_ttls_peer_t *this) +{ + free(this); +} + +/** + * See header + */ +eap_ttls_peer_t *eap_ttls_peer_create(identification_t *peer) +{ + private_eap_ttls_peer_t *this; + + INIT(this, + .public.application = { + .process = _process, + .build = _build, + .destroy = _destroy, + }, + .peer = peer, + .start_phase2 = TRUE, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h new file mode 100644 index 000000000..0338f2631 --- /dev/null +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h @@ -0,0 +1,46 @@ +/* + * 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 tls_peer tls_peer + * @{ @ingroup libtls + */ + +#ifndef EAP_TTLS_PEER_H_ +#define EAP_TTLS_PEER_H_ + +typedef struct eap_ttls_peer_t eap_ttls_peer_t; + +#include "tls_application.h" + +#include <library.h> + +/** + * TLS application data handler as peer. + */ +struct eap_ttls_peer_t { + + /** + * Implements the TLS application data handler. + */ + tls_application_t application; +}; + +/** + * Create an eap_ttls_peer instance. + */ +eap_ttls_peer_t *eap_ttls_peer_create(identification_t *peer); + +#endif /** EAP_TTLS_PEER_H_ @}*/ diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am index d61cd8477..5e112f601 100644 --- a/src/libtls/Makefile.am +++ b/src/libtls/Makefile.am @@ -12,4 +12,4 @@ libtls_la_SOURCES = \ tls_writer.h tls_writer.c \ tls_peer.h tls_peer.c \ tls_server.h tls_server.c \ - tls_handshake.h tls.h tls.c + tls_handshake.h tls_application.h tls.h tls.c diff --git a/src/libtls/tls.c b/src/libtls/tls.c index f8f7e848e..24f442ca9 100644 --- a/src/libtls/tls.c +++ b/src/libtls/tls.c @@ -110,6 +110,11 @@ struct private_tls_t { * TLS handshake protocol handler */ tls_handshake_t *handshake; + + /** + * TLS application data handler + */ + tls_application_t *application; }; METHOD(tls_t, process, status_t, @@ -164,6 +169,7 @@ METHOD(tls_t, destroy, void, this->handshake->destroy(this->handshake); this->peer->destroy(this->peer); this->server->destroy(this->server); + DESTROY_IF(this->application); free(this); } @@ -172,7 +178,8 @@ METHOD(tls_t, destroy, void, * See header */ tls_t *tls_create(bool is_server, identification_t *server, - identification_t *peer, char *msk_label) + identification_t *peer, char *msk_label, + tls_application_t *application) { private_tls_t *this; @@ -191,6 +198,7 @@ tls_t *tls_create(bool is_server, identification_t *server, .version = TLS_1_2, .server = server->clone(server), .peer = peer->clone(peer), + .application = application, ); this->crypto = tls_crypto_create(&this->public, msk_label); @@ -204,7 +212,8 @@ tls_t *tls_create(bool is_server, identification_t *server, this->handshake = &tls_peer_create(&this->public, this->crypto, this->peer, this->server)->handshake; } - this->fragmentation = tls_fragmentation_create(this->handshake); + this->fragmentation = tls_fragmentation_create(this->handshake, + this->application); this->compression = tls_compression_create(this->fragmentation); this->protection = tls_protection_create(&this->public, this->compression); this->crypto->set_protection(this->crypto, this->protection); diff --git a/src/libtls/tls.h b/src/libtls/tls.h index 923c87ae1..ea66b7661 100644 --- a/src/libtls/tls.h +++ b/src/libtls/tls.h @@ -33,6 +33,8 @@ typedef struct tls_t tls_t; #include <library.h> +#include "tls_application.h" + /** * TLS/SSL version numbers */ @@ -163,9 +165,11 @@ struct tls_t { * @param server server identity * @param peer peer identity * @param msk_label ASCII string constant used as seed for MSK PRF + * @param application higher layer application or NULL if none * @return TLS stack */ tls_t *tls_create(bool is_server, identification_t *server, - identification_t *peer, char *msk_label); + identification_t *peer, char *msk_label, + tls_application_t *application); #endif /** TLS_H_ @}*/ diff --git a/src/libtls/tls_application.h b/src/libtls/tls_application.h new file mode 100644 index 000000000..dacd10ef7 --- /dev/null +++ b/src/libtls/tls_application.h @@ -0,0 +1,64 @@ +/* + * 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 tls_handshake tls_handshake + * @{ @ingroup libtls + */ + +#ifndef TLS_APPLICATION_H_ +#define TLS_APPLICATION_H_ + +typedef struct tls_application_t tls_application_t; + +#include "tls.h" +#include "tls_reader.h" +#include "tls_writer.h" + +/** + * TLS application data interface. + */ +struct tls_application_t { + + /** + * Process received TLS application data. + * + * @param reader TLS data buffer + * @return + * - SUCCESS if application completed + * - FAILED if application data processing failed + * - NEED_MORE if another invocation of process/build needed + */ + status_t (*process)(tls_application_t *this, tls_reader_t *reader); + + /** + * Build TLS application data to send out. + * + * @param writer TLS data buffer to write to + * @return + * - SUCCESS if application completed + * - FAILED if application data build failed + * - NEED_MORE if more data ready for delivery + * - INVALID_STATE if more input to process() required + */ + status_t (*build)(tls_application_t *this, tls_writer_t *writer); + + /** + * Destroy a tls_application_t. + */ + void (*destroy)(tls_application_t *this); +}; + +#endif /** TLS_APPLICATION_H_ @}*/ diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c index f95fe4f2e..835a3c9f5 100644 --- a/src/libtls/tls_fragmentation.c +++ b/src/libtls/tls_fragmentation.c @@ -55,6 +55,11 @@ struct private_tls_fragmentation_t { * Handshake output buffer */ chunk_t output; + + /** + * Upper layer application data protocol + */ + tls_application_t *application; }; /** @@ -133,6 +138,33 @@ static status_t process_handshake(private_tls_fragmentation_t *this, return NEED_MORE; } +/** + * Process TLS application data + */ +static status_t process_application(private_tls_fragmentation_t *this, + tls_reader_t *reader) +{ + while (reader->remaining(reader)) + { + u_int32_t len; + chunk_t data; + + if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN) + { + DBG1(DBG_IKE, "TLS fragment has invalid length"); + return FAILED; + } + + len = reader->remaining(reader); + if (!reader->read_data(reader, len, &data)) + { + return FAILED; + } + DBG1(DBG_IKE, "received TLS application data: %B", &data); + } + return NEED_MORE; +} + METHOD(tls_fragmentation_t, process, status_t, private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data) { @@ -158,8 +190,7 @@ METHOD(tls_fragmentation_t, process, status_t, status = process_handshake(this, reader); break; case TLS_APPLICATION_DATA: - /* skip application data */ - status = NEED_MORE; + status = process_application(this, reader); break; default: DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type); @@ -175,7 +206,7 @@ METHOD(tls_fragmentation_t, build, status_t, { tls_handshake_type_t hs_type; tls_writer_t *writer, *msg; - status_t status; + status_t status = INVALID_STATE; if (this->handshake->cipherspec_changed(this->handshake)) { @@ -187,27 +218,47 @@ METHOD(tls_fragmentation_t, build, status_t, if (!this->output.len) { msg = tls_writer_create(64); - do + + if (this->handshake->finished(this->handshake)) { - writer = tls_writer_create(64); - status = this->handshake->build(this->handshake, &hs_type, writer); - switch (status) + if (this->application) { - case NEED_MORE: - DBG2(DBG_IKE, "sending TLS %N message", - tls_handshake_type_names, hs_type); - msg->write_uint8(msg, hs_type); - msg->write_data24(msg, writer->get_buf(writer)); - break; - case INVALID_STATE: + status = this->application->build(this->application, msg); + if (status == INVALID_STATE) + { this->output = chunk_clone(msg->get_buf(msg)); - break; - default: - break; + if (this->output.len) + { + DBG2(DBG_IKE, "sending TLS application data: %B", + &this->output); + } + } + } + } + else + { + do + { + writer = tls_writer_create(64); + status = this->handshake->build(this->handshake, &hs_type, writer); + switch (status) + { + case NEED_MORE: + DBG2(DBG_IKE, "sending TLS %N message", + tls_handshake_type_names, hs_type); + msg->write_uint8(msg, hs_type); + msg->write_data24(msg, writer->get_buf(writer)); + break; + case INVALID_STATE: + this->output = chunk_clone(msg->get_buf(msg)); + break; + default: + break; + } + writer->destroy(writer); } - writer->destroy(writer); + while (status == NEED_MORE); } - while (status == NEED_MORE); msg->destroy(msg); if (status != INVALID_STATE) @@ -218,7 +269,8 @@ METHOD(tls_fragmentation_t, build, status_t, if (this->output.len) { - *type = TLS_HANDSHAKE; + *type = this->handshake->finished(this->handshake) ? + TLS_APPLICATION_DATA : TLS_HANDSHAKE; if (this->output.len <= MAX_TLS_FRAGMENT_LEN) { *data = this->output; @@ -243,7 +295,8 @@ METHOD(tls_fragmentation_t, destroy, void, /** * See header */ -tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake) +tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake, + tls_application_t *application) { private_tls_fragmentation_t *this; @@ -254,6 +307,7 @@ tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake) .destroy = _destroy, }, .handshake = handshake, + .application = application, ); return &this->public; diff --git a/src/libtls/tls_fragmentation.h b/src/libtls/tls_fragmentation.h index e141a334b..6adbc36d0 100644 --- a/src/libtls/tls_fragmentation.h +++ b/src/libtls/tls_fragmentation.h @@ -27,6 +27,7 @@ typedef struct tls_fragmentation_t tls_fragmentation_t; #include "tls.h" #include "tls_handshake.h" +#include "tls_handshake.h" /** * TLS record protocol fragmentation layer. @@ -70,8 +71,10 @@ struct tls_fragmentation_t { * Create a tls_fragmentation instance. * * @param handshake upper layer handshake protocol + * @param application upper layer application data or NULL * @return TLS fragmentation layer. */ -tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake); +tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake, + tls_application_t *application); #endif /** TLS_FRAGMENTATION_H_ @}*/ diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h index c0798625e..3aab3c527 100644 --- a/src/libtls/tls_handshake.h +++ b/src/libtls/tls_handshake.h @@ -74,6 +74,13 @@ struct tls_handshake_t { bool (*change_cipherspec)(tls_handshake_t *this); /** + * Check if the finished message was decoded successfully. + * + * @return TRUE if finished message was decoded successfully + */ + bool (*finished)(tls_handshake_t *this); + + /** * Destroy a tls_handshake_t. */ void (*destroy)(tls_handshake_t *this); diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c index 221b629a5..79f97ae40 100644 --- a/src/libtls/tls_peer.c +++ b/src/libtls/tls_peer.c @@ -621,6 +621,12 @@ METHOD(tls_handshake_t, change_cipherspec, bool, return FALSE; } +METHOD(tls_handshake_t, finished, bool, + private_tls_peer_t *this) +{ + return this->state == STATE_COMPLETE; +} + METHOD(tls_handshake_t, destroy, void, private_tls_peer_t *this) { @@ -644,6 +650,7 @@ tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto, .build = _build, .cipherspec_changed = _cipherspec_changed, .change_cipherspec = _change_cipherspec, + .finished = _finished, .destroy = _destroy, }, .state = STATE_INIT, diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index 8d2c961ea..673b20145 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -583,6 +583,12 @@ METHOD(tls_handshake_t, change_cipherspec, bool, return FALSE; } +METHOD(tls_handshake_t, finished, bool, + private_tls_server_t *this) +{ + return this->state == STATE_FINISHED_SENT; +} + METHOD(tls_handshake_t, destroy, void, private_tls_server_t *this) { @@ -606,6 +612,7 @@ tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto, .build = _build, .cipherspec_changed = _cipherspec_changed, .change_cipherspec = _change_cipherspec, + .finished = _finished, .destroy = _destroy, }, .tls = tls, |