diff options
-rw-r--r-- | src/charon/plugins/eap_tls/Makefile.am | 5 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls.c | 18 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_fragmentation.c | 134 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_fragmentation.h | 4 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_handshake.h | 66 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_peer.c | 69 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_peer.h | 44 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_server.c | 68 | ||||
-rw-r--r-- | src/charon/plugins/eap_tls/tls/tls_server.h | 44 |
9 files changed, 446 insertions, 6 deletions
diff --git a/src/charon/plugins/eap_tls/Makefile.am b/src/charon/plugins/eap_tls/Makefile.am index 25afad2e2..a69f8857c 100644 --- a/src/charon/plugins/eap_tls/Makefile.am +++ b/src/charon/plugins/eap_tls/Makefile.am @@ -9,5 +9,8 @@ libstrongswan_eap_tls_la_SOURCES = eap_tls_plugin.h eap_tls_plugin.c \ eap_tls.h eap_tls.c tls/tls.h tls/tls.c \ tls/tls_protection.h tls/tls_protection.c \ tls/tls_compression.h tls/tls_compression.c \ - tls/tls_fragmentation.h tls/tls_fragmentation.c + tls/tls_fragmentation.h tls/tls_fragmentation.c \ + tls/tls_peer.h tls/tls_peer.c \ + tls/tls_server.h tls/tls_server.c \ + tls/tls_handshake.h libstrongswan_eap_tls_la_LDFLAGS = -module -avoid-version diff --git a/src/charon/plugins/eap_tls/tls/tls.c b/src/charon/plugins/eap_tls/tls/tls.c index 5bba59792..9c11bc796 100644 --- a/src/charon/plugins/eap_tls/tls/tls.c +++ b/src/charon/plugins/eap_tls/tls/tls.c @@ -18,6 +18,8 @@ #include "tls_protection.h" #include "tls_compression.h" #include "tls_fragmentation.h" +#include "tls_server.h" +#include "tls_peer.h" #include <daemon.h> @@ -83,6 +85,11 @@ struct private_tls_t { * TLS record fragmentation layer */ tls_fragmentation_t *fragmentation; + + /** + * TLS handshake protocol handler + */ + tls_handshake_t *handshake; }; METHOD(tls_t, process, status_t, @@ -103,6 +110,7 @@ METHOD(tls_t, destroy, void, this->protection->destroy(this->protection); this->compression->destroy(this->compression); this->fragmentation->destroy(this->fragmentation); + this->handshake->destroy(this->handshake); free(this); } @@ -123,7 +131,15 @@ tls_t *tls_create(bool is_server) .is_server = is_server, ); - this->fragmentation = tls_fragmentation_create(); + if (is_server) + { + this->handshake = &tls_server_create()->handshake; + } + else + { + this->handshake = &tls_peer_create()->handshake; + } + this->fragmentation = tls_fragmentation_create(this->handshake); this->compression = tls_compression_create(this->fragmentation); this->protection = tls_protection_create(this->compression); diff --git a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c index c1cfa0559..0d38e4890 100644 --- a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c +++ b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c @@ -28,30 +28,157 @@ struct private_tls_fragmentation_t { * Public tls_fragmentation_t interface. */ tls_fragmentation_t public; + + /** + * Upper layer handshake protocol + */ + tls_handshake_t *handshake; + + /** + * Handshake input buffer + */ + chunk_t input; + + /** + * Position in input buffer + */ + size_t inpos; + + /** + * Currently processed handshake message type + */ + tls_handshake_type_t type; }; +/** + * Maximum size of a TLS fragment + */ +#define MAX_TLS_FRAGMENT_LEN 16384 + +/** + * Maximum size of a TLS handshake message we accept + */ +#define MAX_TLS_HANDSHAKE_LEN 65536 + +/** + * TLS handshake message header + */ +typedef union { + u_int8_t type; + /* 24bit length field */ + u_int32_t length; +} tls_handshake_header_t; + +/** + * Process TLS handshake protocol data + */ +static status_t process_handshake(private_tls_fragmentation_t *this, + chunk_t data) +{ + while (data.len) + { + u_int32_t len; + status_t status; + tls_handshake_header_t *hdr; + + if (data.len == 0 || data.len > MAX_TLS_FRAGMENT_LEN) + { + DBG1(DBG_IKE, "TLS fragment has invalid length"); + return FAILED; + } + + if (this->input.len == 0) + { /* new handshake message */ + if (data.len < sizeof(tls_handshake_header_t)) + { + DBG1(DBG_IKE, "initial TLS fragment too short %B", &data); + return FAILED; + } + hdr = (tls_handshake_header_t*)data.ptr; + len = untoh32(&hdr->length) & 0x00FFFFFF; + this->type = hdr->type; + if (len > MAX_TLS_HANDSHAKE_LEN) + { + DBG1(DBG_IKE, "TLS handshake message exceeds maximum length"); + return FAILED; + } + this->input = len ? chunk_alloc(len) : chunk_empty; + this->inpos = 0; + data = chunk_skip(data, sizeof(tls_handshake_header_t)); + } + + len = min(this->input.len - this->inpos, data.len); + memcpy(this->input.ptr + this->inpos, data.ptr, len); + this->inpos += len; + data = chunk_skip(data, len); + + if (this->input.len == this->inpos) + { /* message completely defragmented, process */ + status = this->handshake->process(this->handshake, + this->type, this->input); + chunk_free(&this->input); + if (status != NEED_MORE) + { + return status; + } + } + } + return NEED_MORE; +} + METHOD(tls_fragmentation_t, process, status_t, private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data) { - return NEED_MORE; + switch (type) + { + case TLS_CHANGE_CIPHER_SPEC: + /* TODO: handle ChangeCipherSpec */ + return FAILED; + case TLS_ALERT: + /* TODO: handle Alert */ + return FAILED; + case TLS_HANDSHAKE: + return process_handshake(this, data); + case TLS_APPLICATION_DATA: + /* skip application data */ + return NEED_MORE; + default: + DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type); + return NEED_MORE; + } } METHOD(tls_fragmentation_t, build, status_t, private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data) { - return INVALID_STATE; + tls_handshake_header_t header; + tls_handshake_type_t hs_type; + chunk_t hs_data; + status_t status; + + status = this->handshake->build(this->handshake, &hs_type, &hs_data); + if (status != NEED_MORE) + { + return status; + } + htoun32(&header.length, hs_data.len); + header.type |= hs_type; + *data = chunk_cat("cm", chunk_from_thing(header), hs_data); + *type = TLS_HANDSHAKE; + return NEED_MORE; } METHOD(tls_fragmentation_t, destroy, void, private_tls_fragmentation_t *this) { + free(this->input.ptr); free(this); } /** * See header */ -tls_fragmentation_t *tls_fragmentation_create() +tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake) { private_tls_fragmentation_t *this; @@ -61,6 +188,7 @@ tls_fragmentation_t *tls_fragmentation_create() .build = _build, .destroy = _destroy, }, + .handshake = handshake, ); return &this->public; diff --git a/src/charon/plugins/eap_tls/tls/tls_fragmentation.h b/src/charon/plugins/eap_tls/tls/tls_fragmentation.h index 866a9708b..61bf5488e 100644 --- a/src/charon/plugins/eap_tls/tls/tls_fragmentation.h +++ b/src/charon/plugins/eap_tls/tls/tls_fragmentation.h @@ -26,6 +26,7 @@ typedef struct tls_fragmentation_t tls_fragmentation_t; #include <library.h> #include "tls.h" +#include "tls_handshake.h" /** * TLS record protocol fragmentation layer. @@ -68,8 +69,9 @@ struct tls_fragmentation_t { /** * Create a tls_fragmentation instance. * + * @param handshake upper layer handshake protocol * @return TLS fragmentation layer. */ -tls_fragmentation_t *tls_fragmentation_create(); +tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake); #endif /** TLS_FRAGMENTATION_H_ @}*/ diff --git a/src/charon/plugins/eap_tls/tls/tls_handshake.h b/src/charon/plugins/eap_tls/tls/tls_handshake.h new file mode 100644 index 000000000..28174cf8a --- /dev/null +++ b/src/charon/plugins/eap_tls/tls/tls_handshake.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Martin Willi + * 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 tls + */ + +#ifndef TLS_HANDSHAKE_H_ +#define TLS_HANDSHAKE_H_ + +typedef struct tls_handshake_t tls_handshake_t; + +#include "tls.h" + +/** + * TLS handshake state machine interface. + */ +struct tls_handshake_t { + + /** + * Process received TLS handshake message. + * + * @param type TLS handshake message type + * @param data TLS handshake data + * @return + * - SUCCESS if handshake complete + * - FAILED if handshake failed + * - NEED_MORE if another invocation of process/build needed + */ + status_t (*process)(tls_handshake_t *this, + tls_handshake_type_t type, chunk_t data); + + /** + * Build TLS handshake messages to send out. + * + * @param type type of created handshake message + * @param data allocated TLS handshake message data + * @return + * - SUCCESS if handshake complete + * - FAILED if handshake failed + * - NEED_MORE if more messages ready for delivery + * - INVALID_STATE if more input to process() required + */ + status_t (*build)(tls_handshake_t *this, + tls_handshake_type_t *type, chunk_t *data); + + /** + * Destroy a tls_handshake_t. + */ + void (*destroy)(tls_handshake_t *this); +}; + +#endif /** TLS_HANDSHAKE_H_ @}*/ diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.c b/src/charon/plugins/eap_tls/tls/tls_peer.c new file mode 100644 index 000000000..3fc3d6a16 --- /dev/null +++ b/src/charon/plugins/eap_tls/tls/tls_peer.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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 "tls_peer.h" + +#include <daemon.h> + +#include <time.h> + +typedef struct private_tls_peer_t private_tls_peer_t; + +/** + * Private data of an tls_peer_t object. + */ +struct private_tls_peer_t { + + /** + * Public tls_peer_t interface. + */ + tls_peer_t public; +}; + +METHOD(tls_handshake_t, process, status_t, + private_tls_peer_t *this, tls_handshake_type_t type, chunk_t data) +{ + return NEED_MORE; +} + +METHOD(tls_handshake_t, build, status_t, + private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data) +{ + return INVALID_STATE; +} + +METHOD(tls_handshake_t, destroy, void, + private_tls_peer_t *this) +{ + free(this); +} + +/** + * See header + */ +tls_peer_t *tls_peer_create() +{ + private_tls_peer_t *this; + + INIT(this, + .public.handshake = { + .process = _process, + .build = _build, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.h b/src/charon/plugins/eap_tls/tls/tls_peer.h new file mode 100644 index 000000000..036e41894 --- /dev/null +++ b/src/charon/plugins/eap_tls/tls/tls_peer.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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 tls + */ + +#ifndef TLS_PEER_H_ +#define TLS_PEER_H_ + +typedef struct tls_peer_t tls_peer_t; + +#include "tls_handshake.h" + +/** + * TLS handshake protocol handler as peer. + */ +struct tls_peer_t { + + /** + * Implements the TLS handshake protocol handler. + */ + tls_handshake_t handshake; +}; + +/** + * Create a tls_peer instance. + */ +tls_peer_t *tls_peer_create(); + +#endif /** TLS_PEER_H_ @}*/ diff --git a/src/charon/plugins/eap_tls/tls/tls_server.c b/src/charon/plugins/eap_tls/tls/tls_server.c new file mode 100644 index 000000000..63a1e0085 --- /dev/null +++ b/src/charon/plugins/eap_tls/tls/tls_server.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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 "tls_server.h" + +#include <daemon.h> + +typedef struct private_tls_server_t private_tls_server_t; + +/** + * Private data of an tls_server_t object. + */ +struct private_tls_server_t { + + /** + * Public tls_server_t interface. + */ + tls_server_t public; +}; + + +METHOD(tls_handshake_t, process, status_t, + private_tls_server_t *this, tls_handshake_type_t type, chunk_t data) +{ + return NEED_MORE; +} + +METHOD(tls_handshake_t, build, status_t, + private_tls_server_t *this, tls_handshake_type_t *type, chunk_t *data) +{ + return INVALID_STATE; +} + +METHOD(tls_handshake_t, destroy, void, + private_tls_server_t *this) +{ + free(this); +} + +/** + * See header + */ +tls_server_t *tls_server_create() +{ + private_tls_server_t *this; + + INIT(this, + .public.handshake = { + .process = _process, + .build = _build, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/charon/plugins/eap_tls/tls/tls_server.h b/src/charon/plugins/eap_tls/tls/tls_server.h new file mode 100644 index 000000000..12b822bee --- /dev/null +++ b/src/charon/plugins/eap_tls/tls/tls_server.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * 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_server tls_server + * @{ @ingroup tls + */ + +#ifndef TLS_SERVER_H_ +#define TLS_SERVER_H_ + +typedef struct tls_server_t tls_server_t; + +#include "tls_handshake.h" + +/** + * TLS handshake protocol handler as peer. + */ +struct tls_server_t { + + /** + * Implements the TLS handshake protocol handler. + */ + tls_handshake_t handshake; +}; + +/** + * Create a tls_server instance. + */ +tls_server_t *tls_server_create(); + +#endif /** TLS_SERVER_H_ @}*/ |