Moved TLS stack to its own library
authorMartin Willi <martin@revosec.ch>
Tue, 3 Aug 2010 13:17:40 +0000 (15:17 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 3 Aug 2010 13:39:26 +0000 (15:39 +0200)
49 files changed:
Doxyfile.in
configure.in
src/Makefile.am
src/libcharon/Makefile.am
src/libcharon/plugins/eap_tls/Makefile.am
src/libcharon/plugins/eap_tls/eap_tls.c
src/libcharon/plugins/eap_tls/tls/tls.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_compression.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_compression.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_crypto.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_crypto.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_fragmentation.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_fragmentation.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_handshake.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_peer.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_peer.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_prf.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_prf.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_protection.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_protection.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_reader.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_reader.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_server.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_server.h [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_writer.c [deleted file]
src/libcharon/plugins/eap_tls/tls/tls_writer.h [deleted file]
src/libtls/Makefile.am [new file with mode: 0644]
src/libtls/tls.c [new file with mode: 0644]
src/libtls/tls.h [new file with mode: 0644]
src/libtls/tls_compression.c [new file with mode: 0644]
src/libtls/tls_compression.h [new file with mode: 0644]
src/libtls/tls_crypto.c [new file with mode: 0644]
src/libtls/tls_crypto.h [new file with mode: 0644]
src/libtls/tls_fragmentation.c [new file with mode: 0644]
src/libtls/tls_fragmentation.h [new file with mode: 0644]
src/libtls/tls_handshake.h [new file with mode: 0644]
src/libtls/tls_peer.c [new file with mode: 0644]
src/libtls/tls_peer.h [new file with mode: 0644]
src/libtls/tls_prf.c [new file with mode: 0644]
src/libtls/tls_prf.h [new file with mode: 0644]
src/libtls/tls_protection.c [new file with mode: 0644]
src/libtls/tls_protection.h [new file with mode: 0644]
src/libtls/tls_reader.c [new file with mode: 0644]
src/libtls/tls_reader.h [new file with mode: 0644]
src/libtls/tls_server.c [new file with mode: 0644]
src/libtls/tls_server.h [new file with mode: 0644]
src/libtls/tls_writer.c [new file with mode: 0644]
src/libtls/tls_writer.h [new file with mode: 0644]

index b79c990..52e62b7 100644 (file)
@@ -531,6 +531,7 @@ INPUT                  = @SRC_DIR@/src/libstrongswan \
                          @SRC_DIR@/src/libhydra \
                          @SRC_DIR@/src/libcharon \
                          @SRC_DIR@/src/libsimaka \
+                         @SRC_DIR@/src/libtls \
                          @SRC_DIR@/src/libfast \
                          @SRC_DIR@/src/manager
 
index 65f45c8..f15e5d2 100644 (file)
@@ -225,6 +225,10 @@ if test x$eap_sim = xtrue; then
        simaka=true;
 fi
 
+if test x$eap_tls = xtrue; then
+       tls=true;
+fi
+
 if test x$fips_prf = xtrue; then
        if test x$openssl = xfalse; then
                sha1=true;
@@ -895,6 +899,7 @@ AM_CONDITIONAL(USE_FILE_CONFIG, test x$pluto = xtrue -o x$stroke = xtrue)
 AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap)
 AM_CONDITIONAL(USE_VSTR, test x$vstr = xtrue)
 AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue)
+AM_CONDITIONAL(USE_TLS, test x$tls = xtrue)
 AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue)
 
 dnl ==============================
@@ -955,6 +960,7 @@ AC_OUTPUT(
        src/libhydra/plugins/resolve/Makefile
        src/libfreeswan/Makefile
        src/libsimaka/Makefile
+       src/libtls/Makefile
        src/pluto/Makefile
        src/pluto/plugins/xauth/Makefile
        src/whack/Makefile
index 8d4dd2e..0edddc9 100644 (file)
@@ -12,6 +12,10 @@ if USE_SIMAKA
   SUBDIRS += libsimaka
 endif
 
+if USE_TLS
+  SUBDIRS += libtls
+endif
+
 if USE_FILE_CONFIG
   SUBDIRS += libfreeswan starter ipsec _copyright
 endif
index 510f5e5..4681fb9 100644 (file)
@@ -352,6 +352,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_TLS
+if MONOLITHIC
+  # otherwise this library is linked to eap_tls
+  libcharon_la_LIBADD += $(top_builddir)/src/libtls/libtls.la
+endif
+endif
+
 if USE_MEDSRV
   SUBDIRS += plugins/medsrv
   PLUGINS += medsrv
index bd8f82a..29ddd82 100644 (file)
@@ -1,6 +1,6 @@
 
 INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
-       -I$(top_srcdir)/src/libcharon
+       -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls
 
 AM_CFLAGS = -rdynamic
 
@@ -8,18 +8,10 @@ if MONOLITHIC
 noinst_LTLIBRARIES = libstrongswan-eap-tls.la
 else
 plugin_LTLIBRARIES = libstrongswan-eap-tls.la
+libstrongswan_eap_tls_la_LIBADD = $(top_builddir)/src/libtls/libtls.la
 endif
 
-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_crypto.h tls/tls_crypto.c \
-       tls/tls_prf.h tls/tls_prf.c \
-       tls/tls_reader.h tls/tls_reader.c \
-       tls/tls_writer.h tls/tls_writer.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_SOURCES = \
+       eap_tls_plugin.h eap_tls_plugin.c eap_tls.h eap_tls.c
+
 libstrongswan_eap_tls_la_LDFLAGS = -module -avoid-version
index cf42949..453a4cc 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "eap_tls.h"
 
-#include "tls/tls.h"
+#include <tls.h>
 
 #include <daemon.h>
 #include <library.h>
diff --git a/src/libcharon/plugins/eap_tls/tls/tls.c b/src/libcharon/plugins/eap_tls/tls/tls.c
deleted file mode 100644 (file)
index ab03037..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.h"
-
-#include "tls_protection.h"
-#include "tls_compression.h"
-#include "tls_fragmentation.h"
-#include "tls_crypto.h"
-#include "tls_server.h"
-#include "tls_peer.h"
-
-#include <daemon.h>
-
-ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
-       "SSLv2");
-ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
-       "SSLv3",
-       "TLS 1.0",
-       "TLS 1.1",
-       "TLS 1.2");
-ENUM_END(tls_version_names, TLS_1_2);
-
-ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
-       "ChangeCipherSpec",
-       "Alert",
-       "Handshake",
-       "ApplicationData",
-);
-
-ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
-       "HelloRequest",
-       "ClientHello",
-       "ServerHello");
-ENUM_NEXT(tls_handshake_type_names, TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
-       "Certificate",
-       "ServerKeyExchange",
-       "CertificateRequest",
-       "ServerHelloDone",
-       "CertificateVerify",
-       "ClientKeyExchange");
-ENUM_NEXT(tls_handshake_type_names, TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
-       "Finished");
-ENUM_END(tls_handshake_type_names, TLS_FINISHED);
-
-
-typedef struct private_tls_t private_tls_t;
-
-/**
- * Private data of an tls_protection_t object.
- */
-struct private_tls_t {
-
-       /**
-        * Public tls_t interface.
-        */
-       tls_t public;
-
-       /**
-        * Role this TLS stack acts as.
-        */
-       bool is_server;
-
-       /**
-        * Server identity
-        */
-       identification_t *server;
-
-       /**
-        * Peer identity
-        */
-       identification_t *peer;
-
-       /**
-        * Negotiated TLS version
-        */
-       tls_version_t version;
-
-       /**
-        * TLS record protection layer
-        */
-       tls_protection_t *protection;
-
-       /**
-        * TLS record compression layer
-        */
-       tls_compression_t *compression;
-
-       /**
-        * TLS record fragmentation layer
-        */
-       tls_fragmentation_t *fragmentation;
-
-       /**
-        * TLS crypto helper context
-        */
-       tls_crypto_t *crypto;
-
-       /**
-        * TLS handshake protocol handler
-        */
-       tls_handshake_t *handshake;
-};
-
-METHOD(tls_t, process, status_t,
-       private_tls_t *this, tls_content_type_t type, chunk_t data)
-{
-       return this->protection->process(this->protection, type, data);
-}
-
-METHOD(tls_t, build, status_t,
-       private_tls_t *this, tls_content_type_t *type, chunk_t *data)
-{
-       return this->protection->build(this->protection, type, data);
-}
-
-METHOD(tls_t, is_server, bool,
-       private_tls_t *this)
-{
-       return this->is_server;
-}
-
-METHOD(tls_t, get_version, tls_version_t,
-       private_tls_t *this)
-{
-       return this->version;
-}
-
-METHOD(tls_t, set_version, void,
-       private_tls_t *this, tls_version_t version)
-{
-       this->version = version;
-}
-
-METHOD(tls_t, is_complete, bool,
-       private_tls_t *this)
-{
-       return this->crypto->get_eap_msk(this->crypto).len != 0;
-}
-
-METHOD(tls_t, get_eap_msk, chunk_t,
-       private_tls_t *this)
-{
-       return this->crypto->get_eap_msk(this->crypto);
-}
-
-METHOD(tls_t, destroy, void,
-       private_tls_t *this)
-{
-       this->protection->destroy(this->protection);
-       this->compression->destroy(this->compression);
-       this->fragmentation->destroy(this->fragmentation);
-       this->crypto->destroy(this->crypto);
-       this->handshake->destroy(this->handshake);
-       this->peer->destroy(this->peer);
-       this->server->destroy(this->server);
-
-       free(this);
-}
-
-/**
- * See header
- */
-tls_t *tls_create(bool is_server, identification_t *server,
-                                 identification_t *peer)
-{
-       private_tls_t *this;
-
-       INIT(this,
-               .public = {
-                       .process = _process,
-                       .build = _build,
-                       .is_server = _is_server,
-                       .get_version = _get_version,
-                       .set_version = _set_version,
-                       .is_complete = _is_complete,
-                       .get_eap_msk = _get_eap_msk,
-                       .destroy = _destroy,
-               },
-               .is_server = is_server,
-               .version = TLS_1_2,
-               .server = server->clone(server),
-               .peer = peer->clone(peer),
-       );
-
-       this->crypto = tls_crypto_create(&this->public);
-       if (is_server)
-       {
-               this->handshake = &tls_server_create(&this->public, this->crypto,
-                                                                               this->server, this->peer)->handshake;
-       }
-       else
-       {
-               this->handshake = &tls_peer_create(&this->public, this->crypto,
-                                                                               this->peer, this->server)->handshake;
-       }
-       this->fragmentation = tls_fragmentation_create(this->handshake);
-       this->compression = tls_compression_create(this->fragmentation);
-       this->protection = tls_protection_create(&this->public, this->compression);
-       this->crypto->set_protection(this->crypto, this->protection);
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls.h b/src/libcharon/plugins/eap_tls/tls/tls.h
deleted file mode 100644 (file)
index 283f591..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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 tlsgroup tls
- * @{ @ingroup eap_tls
- *
- * @defgroup tls tls
- * @{ @ingroup tls
- */
-
-#ifndef TLS_H_
-#define TLS_H_
-
-typedef enum tls_version_t tls_version_t;
-typedef enum tls_content_type_t tls_content_type_t;
-typedef enum tls_handshake_type_t tls_handshake_type_t;
-typedef struct tls_t tls_t;
-
-#include <library.h>
-
-/**
- * TLS/SSL version numbers
- */
-enum tls_version_t {
-       SSL_2_0 = 0x0200,
-       SSL_3_0 = 0x0300,
-       TLS_1_0 = 0x0301,
-       TLS_1_1 = 0x0302,
-       TLS_1_2 = 0x0303,
-};
-
-/**
- * Enum names for tls_version_t
- */
-extern enum_name_t *tls_version_names;
-
-/**
- * TLS higher level content type
- */
-enum tls_content_type_t {
-       TLS_CHANGE_CIPHER_SPEC = 20,
-       TLS_ALERT = 21,
-       TLS_HANDSHAKE = 22,
-       TLS_APPLICATION_DATA = 23,
-};
-
-/**
- * Enum names for tls_content_type_t
- */
-extern enum_name_t *tls_content_type_names;
-
-/**
- * TLS handshake subtype
- */
-enum tls_handshake_type_t {
-       TLS_HELLO_REQUEST = 0,
-       TLS_CLIENT_HELLO = 1,
-       TLS_SERVER_HELLO = 2,
-       TLS_CERTIFICATE = 11,
-       TLS_SERVER_KEY_EXCHANGE = 12,
-       TLS_CERTIFICATE_REQUEST = 13,
-       TLS_SERVER_HELLO_DONE = 14,
-       TLS_CERTIFICATE_VERIFY = 15,
-       TLS_CLIENT_KEY_EXCHANGE = 16,
-       TLS_FINISHED = 20,
-};
-
-/**
- * Enum names for tls_handshake_type_t
- */
-extern enum_name_t *tls_handshake_type_names;
-
-/**
- * A bottom-up driven TLS stack, suitable for EAP implementations.
- */
-struct tls_t {
-
-       /**
-        * Process a TLS record, pass it to upper layers.
-        *
-        * @param type          type of the TLS record to process
-        * @param data          associated TLS record data
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if more invocations to process/build needed
-        */
-       status_t (*process)(tls_t *this, tls_content_type_t type, chunk_t data);
-
-       /**
-        * Query upper layer for TLS record, build protected record.
-        *
-        * @param type          type of the built TLS record
-        * @param data          allocated data of the built TLS record
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if upper layers have more records to send
-        *                                      - INVALID_STATE if more input records required
-        */
-       status_t (*build)(tls_t *this, tls_content_type_t *type, chunk_t *data);
-
-       /**
-        * Check if TLS stack is acting as a server.
-        *
-        * @return                      TRUE if server, FALSE if peer
-        */
-       bool (*is_server)(tls_t *this);
-
-       /**
-        * Get the negotiated TLS/SSL version.
-        *
-        * @return                      negotiated TLS version
-        */
-       tls_version_t (*get_version)(tls_t *this);
-
-       /**
-        * Set the negotiated TLS/SSL version.
-        *
-        * @param version       negotiated TLS version
-        */
-       void (*set_version)(tls_t *this, tls_version_t version);
-
-       /**
-        * Check if TLS negotiation completed successfully.
-        *
-        * @return                      TRUE if TLS negotation and authentication complete
-        */
-       bool (*is_complete)(tls_t *this);
-
-       /**
-        * Get the MSK for EAP-TLS.
-        *
-        * @return                      MSK, internal data
-        */
-       chunk_t (*get_eap_msk)(tls_t *this);
-
-       /**
-        * Destroy a tls_t.
-        */
-       void (*destroy)(tls_t *this);
-};
-
-/**
- * Create a tls instance.
- *
- * @param is_server            TRUE to act as server, FALSE for client
- * @param server               server identity
- * @param peer                 peer identity
- * @return                             TLS stack
- */
-tls_t *tls_create(bool is_server, identification_t *server,
-                                 identification_t *peer);
-
-#endif /** TLS_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_compression.c b/src/libcharon/plugins/eap_tls/tls/tls_compression.c
deleted file mode 100644 (file)
index 4535580..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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_compression.h"
-
-#include <daemon.h>
-
-typedef struct private_tls_compression_t private_tls_compression_t;
-
-/**
- * Private data of an tls_compression_t object.
- */
-struct private_tls_compression_t {
-
-       /**
-        * Public tls_compression_t interface.
-        */
-       tls_compression_t public;
-
-       /**
-        * Upper layer, TLS record fragmentation
-        */
-       tls_fragmentation_t *fragmentation;
-};
-
-METHOD(tls_compression_t, process, status_t,
-       private_tls_compression_t *this, tls_content_type_t type, chunk_t data)
-{
-       return this->fragmentation->process(this->fragmentation, type, data);
-}
-
-METHOD(tls_compression_t, build, status_t,
-       private_tls_compression_t *this, tls_content_type_t *type, chunk_t *data)
-{
-       return this->fragmentation->build(this->fragmentation, type, data);
-}
-
-METHOD(tls_compression_t, destroy, void,
-       private_tls_compression_t *this)
-{
-       free(this);
-}
-
-/**
- * See header
- */
-tls_compression_t *tls_compression_create(tls_fragmentation_t *fragmentation)
-{
-       private_tls_compression_t *this;
-
-       INIT(this,
-               .public = {
-                       .process = _process,
-                       .build = _build,
-                       .destroy = _destroy,
-               },
-               .fragmentation = fragmentation,
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_compression.h b/src/libcharon/plugins/eap_tls/tls/tls_compression.h
deleted file mode 100644 (file)
index a615430..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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_compression tls_compression
- * @{ @ingroup tls
- */
-
-#ifndef TLS_COMPRESSION_H_
-#define TLS_COMPRESSION_H_
-
-typedef struct tls_compression_t tls_compression_t;
-
-#include <library.h>
-
-#include "tls.h"
-#include "tls_fragmentation.h"
-
-/**
- * TLS record protocol compression layer.
- */
-struct tls_compression_t {
-
-       /**
-        * Process a compressed TLS record, pass it to upper layers.
-        *
-        * @param type          type of the TLS record to process
-        * @param data          associated TLS record data
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if more invocations to process/build needed
-        */
-       status_t (*process)(tls_compression_t *this,
-                                               tls_content_type_t type, chunk_t data);
-
-       /**
-        * Query upper layer for TLS record, build compressed record.
-        *
-        * @param type          type of the built TLS record
-        * @param data          allocated data of the built TLS record
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if upper layers have more records to send
-        *                                      - INVALID_STATE if more input records required
-        */
-       status_t (*build)(tls_compression_t *this,
-                                         tls_content_type_t *type, chunk_t *data);
-
-       /**
-        * Destroy a tls_compression_t.
-        */
-       void (*destroy)(tls_compression_t *this);
-};
-
-/**
- * Create a tls_compression instance.
- *
- * @param fragmentation                fragmentation layer of TLS stack
- * @return                                     TLS compression layer.
- */
-tls_compression_t *tls_compression_create(tls_fragmentation_t *fragmentation);
-
-#endif /** TLS_COMPRESSION_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_crypto.c b/src/libcharon/plugins/eap_tls/tls/tls_crypto.c
deleted file mode 100644 (file)
index f889462..0000000
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * 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_crypto.h"
-
-#include <daemon.h>
-
-typedef struct private_tls_crypto_t private_tls_crypto_t;
-
-/**
- * Private data of an tls_crypto_t object.
- */
-struct private_tls_crypto_t {
-
-       /**
-        * Public tls_crypto_t interface.
-        */
-       tls_crypto_t public;
-
-       /**
-        * Protection layer
-        */
-       tls_protection_t *protection;
-
-       /**
-        * List of supported/acceptable cipher suites
-        */
-       tls_cipher_suite_t *suites;
-
-       /**
-        * Number of supported suites
-        */
-       int suite_count;
-
-       /**
-        * Selected cipher suite
-        */
-       tls_cipher_suite_t suite;
-
-       /**
-        * TLS context
-        */
-       tls_t *tls;
-
-       /**
-        * All handshake data concatentated
-        */
-       chunk_t handshake;
-
-       /**
-        * Connection state TLS PRF
-        */
-       tls_prf_t *prf;
-
-       /**
-        * Signer instance for inbound traffic
-        */
-       signer_t *signer_in;
-
-       /**
-        * Signer instance for outbound traffic
-        */
-       signer_t *signer_out;
-
-       /**
-        * Crypter instance for inbound traffic
-        */
-       crypter_t *crypter_in;
-
-       /**
-        * Crypter instance for outbound traffic
-        */
-       crypter_t *crypter_out;
-
-       /**
-        * IV for input decryption, if < TLSv1.2
-        */
-       chunk_t iv_in;
-
-       /**
-        * IV for output decryption, if < TLSv1.2
-        */
-       chunk_t iv_out;
-
-       /**
-        * EAP-TLS MSK
-        */
-       chunk_t msk;
-};
-
-typedef struct {
-       tls_cipher_suite_t suite;
-       hash_algorithm_t hash;
-       pseudo_random_function_t prf;
-       integrity_algorithm_t mac;
-       encryption_algorithm_t encr;
-       size_t encr_size;
-} suite_algs_t;
-
-/**
- * Mapping suites to a set of algorithms
- */
-static suite_algs_t suite_algs[] = {
-       { TLS_RSA_WITH_NULL_MD5,
-               HASH_MD5,
-               PRF_HMAC_MD5,
-               AUTH_HMAC_MD5_128,
-               ENCR_NULL, 0
-       },
-       { TLS_RSA_WITH_NULL_SHA,
-               HASH_SHA1,
-               PRF_HMAC_SHA1,
-               AUTH_HMAC_SHA1_160,
-               ENCR_NULL, 0
-       },
-       { TLS_RSA_WITH_NULL_SHA256,
-               HASH_SHA256,
-               PRF_HMAC_SHA2_256,
-               AUTH_HMAC_SHA2_256_256,
-               ENCR_NULL, 0
-       },
-       { TLS_RSA_WITH_AES_128_CBC_SHA,
-               HASH_SHA1,
-               PRF_HMAC_SHA1,
-               AUTH_HMAC_SHA1_160,
-               ENCR_AES_CBC, 16
-       },
-       { TLS_RSA_WITH_AES_256_CBC_SHA,
-               HASH_SHA1,
-               PRF_HMAC_SHA1,
-               AUTH_HMAC_SHA1_160,
-               ENCR_AES_CBC, 32
-       },
-       { TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-               HASH_SHA1,
-               PRF_HMAC_SHA1,
-               AUTH_HMAC_SHA1_160,
-               ENCR_3DES, 0
-       },
-       { TLS_RSA_WITH_AES_128_CBC_SHA256,
-               HASH_SHA256,
-               PRF_HMAC_SHA2_256,
-               AUTH_HMAC_SHA2_256_256,
-               ENCR_AES_CBC, 16
-       },
-};
-
-/**
- * Look up algoritms by a suite
- */
-static suite_algs_t *find_suite(tls_cipher_suite_t suite)
-{
-       int i;
-
-       for (i = 0; i < countof(suite_algs); i++)
-       {
-               if (suite_algs[i].suite == suite)
-               {
-                       return &suite_algs[i];
-               }
-       }
-       return NULL;
-}
-
-/**
- * Initialize the cipher suite list
- */
-static void build_cipher_suite_list(private_tls_crypto_t *this)
-{
-       encryption_algorithm_t encr;
-       integrity_algorithm_t mac;
-       enumerator_t *encrs, *macs;
-       tls_cipher_suite_t supported[64], unique[64];
-       int count = 0, i, j;
-
-       /* we assume that we support RSA, but no DHE yet */
-       macs = lib->crypto->create_signer_enumerator(lib->crypto);
-       while (macs->enumerate(macs, &mac))
-       {
-               switch (mac)
-               {
-                       case AUTH_HMAC_SHA1_160:
-                               supported[count++] = TLS_RSA_WITH_NULL_SHA;
-                               break;
-                       case AUTH_HMAC_SHA2_256_256:
-                               supported[count++] = TLS_RSA_WITH_NULL_SHA256;
-                               break;
-                       case AUTH_HMAC_MD5_128:
-                               supported[count++] = TLS_RSA_WITH_NULL_MD5;
-                               break;
-                       default:
-                               break;
-               }
-               encrs = lib->crypto->create_crypter_enumerator(lib->crypto);
-               while (encrs->enumerate(encrs, &encr))
-               {
-                       switch (encr)
-                       {
-                               case ENCR_AES_CBC:
-                                       switch (mac)
-                                       {
-                                               case AUTH_HMAC_SHA1_160:
-                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
-                                                       supported[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
-                                                       break;
-                                               case AUTH_HMAC_SHA2_256_256:
-                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
-                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
-                                                       break;
-                                               default:
-                                                       break;
-                                       }
-                                       break;
-                               case ENCR_3DES:
-                                       switch (mac)
-                                       {
-                                               case AUTH_HMAC_SHA1_160:
-                                                       supported[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-                                                       break;
-                                               default:
-                                                       break;
-                                       }
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               encrs->destroy(encrs);
-       }
-       macs->destroy(macs);
-
-       /* remove duplicates */
-       this->suite_count = 0;
-       for (i = 0; i < count; i++)
-       {
-               bool match = FALSE;
-
-               for (j = 0; j < this->suite_count; j++)
-               {
-                       if (supported[i] == unique[j])
-                       {
-                               match = TRUE;
-                               break;
-                       }
-               }
-               if (!match)
-               {
-                       unique[this->suite_count++] = supported[i];
-               }
-       }
-       free(this->suites);
-       this->suites = malloc(sizeof(tls_cipher_suite_t) * this->suite_count);
-       memcpy(this->suites, unique, sizeof(tls_cipher_suite_t) * this->suite_count);
-}
-
-METHOD(tls_crypto_t, get_cipher_suites, int,
-       private_tls_crypto_t *this, tls_cipher_suite_t **suites)
-{
-       *suites = this->suites;
-       return this->suite_count;
-}
-
-/**
- * Create crypto primitives
- */
-static bool create_ciphers(private_tls_crypto_t *this, tls_cipher_suite_t suite)
-{
-       suite_algs_t *algs;
-
-       algs = find_suite(suite);
-       if (!algs)
-       {
-               DBG1(DBG_IKE, "selected TLS suite not supported");
-               return FALSE;
-       }
-
-       DESTROY_IF(this->prf);
-       if (this->tls->get_version(this->tls) < TLS_1_2)
-       {
-               this->prf = tls_prf_create_10();
-       }
-       else
-       {
-               this->prf = tls_prf_create_12(algs->prf);
-       }
-       if (!this->prf)
-       {
-               DBG1(DBG_IKE, "selected TLS PRF not supported");
-               return FALSE;
-       }
-
-       DESTROY_IF(this->signer_in);
-       DESTROY_IF(this->signer_out);
-       this->signer_in = lib->crypto->create_signer(lib->crypto, algs->mac);
-       this->signer_out = lib->crypto->create_signer(lib->crypto, algs->mac);
-       if (!this->signer_in || !this->signer_out)
-       {
-               DBG1(DBG_IKE, "selected TLS MAC %N not supported",
-                        integrity_algorithm_names, algs->mac);
-               return FALSE;
-       }
-
-       DESTROY_IF(this->crypter_in);
-       DESTROY_IF(this->crypter_out);
-       if (algs->encr == ENCR_NULL)
-       {
-               this->crypter_in = this->crypter_out = NULL;
-       }
-       else
-       {
-               this->crypter_in = lib->crypto->create_crypter(lib->crypto,
-                                                                                               algs->encr, algs->encr_size);
-               this->crypter_out = lib->crypto->create_crypter(lib->crypto,
-                                                                                               algs->encr, algs->encr_size);
-               if (!this->crypter_in || !this->crypter_out)
-               {
-                       DBG1(DBG_IKE, "selected TLS crypter %N not supported",
-                                encryption_algorithm_names, algs->encr);
-                       return FALSE;
-               }
-       }
-       return TRUE;
-}
-
-METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t,
-       private_tls_crypto_t *this, tls_cipher_suite_t *suites, int count)
-{
-       int i, j;
-
-       for (i = 0; i < this->suite_count; i++)
-       {
-               for (j = 0; j < count; j++)
-               {
-                       if (this->suites[i] == suites[j])
-                       {
-                               if (create_ciphers(this, this->suites[i]))
-                               {
-                                       this->suite = this->suites[i];
-                                       return this->suite;
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
-METHOD(tls_crypto_t, set_protection, void,
-       private_tls_crypto_t *this, tls_protection_t *protection)
-{
-       this->protection = protection;
-}
-
-METHOD(tls_crypto_t, append_handshake, void,
-       private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data)
-{
-       u_int32_t header;
-
-       /* reconstruct handshake header */
-       header = htonl(data.len | (type << 24));
-       this->handshake = chunk_cat("mcc", this->handshake,
-                                                               chunk_from_thing(header), data);
-}
-
-/**
- * Create a hash of the stored handshake data
- */
-static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash)
-{
-       if (this->tls->get_version(this->tls) >= TLS_1_2)
-       {
-               hasher_t *hasher;
-               suite_algs_t *alg;
-
-               alg = find_suite(this->suite);
-               if (!alg)
-               {
-                       return FALSE;
-               }
-               hasher = lib->crypto->create_hasher(lib->crypto, alg->hash);
-               if (!hasher)
-               {
-                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, alg->hash);
-                       return FALSE;
-               }
-               hasher->allocate_hash(hasher, this->handshake, hash);
-               hasher->destroy(hasher);
-       }
-       else
-       {
-               hasher_t *md5, *sha1;
-               char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
-
-               md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
-               if (!md5)
-               {
-                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_MD5);
-                       return FALSE;
-               }
-               md5->get_hash(md5, this->handshake, buf);
-               md5->destroy(md5);
-               sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
-               if (!sha1)
-               {
-                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_SHA1);
-                       return FALSE;
-               }
-               sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
-               sha1->destroy(sha1);
-
-               *hash = chunk_clone(chunk_from_thing(buf));
-       }
-       return TRUE;
-}
-
-METHOD(tls_crypto_t, sign_handshake, bool,
-       private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer)
-{
-       chunk_t sig, hash;
-
-       if (this->tls->get_version(this->tls) >= TLS_1_2)
-       {
-               /* TODO: use supported algorithms instead of fixed SHA1/RSA */
-               if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, &sig))
-               {
-                       return FALSE;
-               }
-               writer->write_uint8(writer, 2);
-               writer->write_uint8(writer, 1);
-               writer->write_data16(writer, sig);
-               free(sig.ptr);
-       }
-       else
-       {
-               if (!hash_handshake(this, &hash))
-               {
-                       return FALSE;
-               }
-               if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
-               {
-                       free(hash.ptr);
-                       return FALSE;
-               }
-               writer->write_data16(writer, sig);
-               free(hash.ptr);
-               free(sig.ptr);
-       }
-       return TRUE;
-}
-
-METHOD(tls_crypto_t, verify_handshake, bool,
-       private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader)
-{
-       if (this->tls->get_version(this->tls) >= TLS_1_2)
-       {
-               u_int8_t hash, alg;
-               chunk_t sig;
-
-               if (!reader->read_uint8(reader, &hash) ||
-                       !reader->read_uint8(reader, &alg) ||
-                       !reader->read_data16(reader, &sig))
-               {
-                       DBG1(DBG_IKE, "received invalid Certificate Verify");
-                       return FALSE;
-               }
-               /* TODO: map received hash/sig alg to signature scheme */
-               if (hash != 2 || alg != 1 ||
-                       !key->verify(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig))
-               {
-                       return FALSE;
-               }
-       }
-       else
-       {
-               chunk_t sig, hash;
-
-               if (!reader->read_data16(reader, &sig))
-               {
-                       DBG1(DBG_IKE, "received invalid Certificate Verify");
-                       return FALSE;
-               }
-               if (!hash_handshake(this, &hash))
-               {
-                       return FALSE;
-               }
-               if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig))
-               {
-                       free(hash.ptr);
-                       return FALSE;
-               }
-               free(hash.ptr);
-       }
-       return TRUE;
-}
-
-METHOD(tls_crypto_t, calculate_finished, bool,
-       private_tls_crypto_t *this, char *label, char out[12])
-{
-       chunk_t seed;
-
-       if (!this->prf)
-       {
-               return FALSE;
-       }
-       if (!hash_handshake(this, &seed))
-       {
-               return FALSE;
-       }
-       this->prf->get_bytes(this->prf, label, seed, 12, out);
-       free(seed.ptr);
-       return TRUE;
-}
-
-METHOD(tls_crypto_t, derive_secrets, void,
-       private_tls_crypto_t *this, chunk_t premaster,
-       chunk_t client_random, chunk_t server_random)
-{
-       char master[48];
-       chunk_t seed, block, client_write, server_write;
-       int mks, eks = 0, ivs = 0;
-
-       /* derive master secret */
-       seed = chunk_cata("cc", client_random, server_random);
-       this->prf->set_key(this->prf, premaster);
-       this->prf->get_bytes(this->prf, "master secret", seed,
-                                                sizeof(master), master);
-
-       this->prf->set_key(this->prf, chunk_from_thing(master));
-       memset(master, 0, sizeof(master));
-
-       /* derive key block for key expansion */
-       mks = this->signer_out->get_key_size(this->signer_out);
-       if (this->crypter_out)
-       {
-               eks = this->crypter_out->get_key_size(this->crypter_out);
-               if (this->tls->get_version(this->tls) < TLS_1_1)
-               {
-                       ivs = this->crypter_out->get_block_size(this->crypter_out);
-               }
-       }
-       seed = chunk_cata("cc", server_random, client_random);
-       block = chunk_alloca((mks + eks + ivs) * 2);
-       this->prf->get_bytes(this->prf, "key expansion", seed, block.len, block.ptr);
-
-       /* signer keys */
-       client_write = chunk_create(block.ptr, mks);
-       block = chunk_skip(block, mks);
-       server_write = chunk_create(block.ptr, mks);
-       block = chunk_skip(block, mks);
-       if (this->tls->is_server(this->tls))
-       {
-               this->signer_in->set_key(this->signer_in, client_write);
-               this->signer_out->set_key(this->signer_out, server_write);
-       }
-       else
-       {
-               this->signer_out->set_key(this->signer_out, client_write);
-               this->signer_in->set_key(this->signer_in, server_write);
-       }
-
-       /* crypter keys, and IVs if < TLSv1.2 */
-       if (this->crypter_out && this->crypter_in)
-       {
-               client_write = chunk_create(block.ptr, eks);
-               block = chunk_skip(block, eks);
-               server_write = chunk_create(block.ptr, eks);
-               block = chunk_skip(block, eks);
-
-               if (this->tls->is_server(this->tls))
-               {
-                       this->crypter_in->set_key(this->crypter_in, client_write);
-                       this->crypter_out->set_key(this->crypter_out, server_write);
-               }
-               else
-               {
-                       this->crypter_out->set_key(this->crypter_out, client_write);
-                       this->crypter_in->set_key(this->crypter_in, server_write);
-               }
-               if (ivs)
-               {
-                       client_write = chunk_create(block.ptr, ivs);
-                       block = chunk_skip(block, ivs);
-                       server_write = chunk_create(block.ptr, ivs);
-                       block = chunk_skip(block, ivs);
-
-                       if (this->tls->is_server(this->tls))
-                       {
-                               this->iv_in = chunk_clone(client_write);
-                               this->iv_out = chunk_clone(server_write);
-                       }
-                       else
-                       {
-                               this->iv_out = chunk_clone(client_write);
-                               this->iv_in = chunk_clone(server_write);
-                       }
-               }
-       }
-}
-
-METHOD(tls_crypto_t, change_cipher, void,
-       private_tls_crypto_t *this, bool inbound)
-{
-       if (this->protection)
-       {
-               if (inbound)
-               {
-                       this->protection->set_cipher(this->protection, TRUE,
-                                                       this->signer_in, this->crypter_in, this->iv_in);
-               }
-               else
-               {
-                       this->protection->set_cipher(this->protection, FALSE,
-                                                       this->signer_out, this->crypter_out, this->iv_out);
-               }
-       }
-}
-
-METHOD(tls_crypto_t, derive_eap_msk, void,
-       private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
-{
-       chunk_t seed;
-
-       seed = chunk_cata("cc", client_random, server_random);
-       free(this->msk.ptr);
-       this->msk = chunk_alloc(64);
-       this->prf->get_bytes(this->prf, "client EAP encryption", seed,
-                                                this->msk.len, this->msk.ptr);
-}
-
-METHOD(tls_crypto_t, get_eap_msk, chunk_t,
-       private_tls_crypto_t *this)
-{
-       return this->msk;
-}
-
-METHOD(tls_crypto_t, destroy, void,
-       private_tls_crypto_t *this)
-{
-       DESTROY_IF(this->signer_in);
-       DESTROY_IF(this->signer_out);
-       DESTROY_IF(this->crypter_in);
-       DESTROY_IF(this->crypter_out);
-       free(this->iv_in.ptr);
-       free(this->iv_out.ptr);
-       free(this->handshake.ptr);
-       free(this->msk.ptr);
-       DESTROY_IF(this->prf);
-       free(this->suites);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_crypto_t *tls_crypto_create(tls_t *tls)
-{
-       private_tls_crypto_t *this;
-
-       INIT(this,
-               .public = {
-                       .get_cipher_suites = _get_cipher_suites,
-                       .select_cipher_suite = _select_cipher_suite,
-                       .set_protection = _set_protection,
-                       .append_handshake = _append_handshake,
-                       .sign_handshake = _sign_handshake,
-                       .verify_handshake = _verify_handshake,
-                       .calculate_finished = _calculate_finished,
-                       .derive_secrets = _derive_secrets,
-                       .change_cipher = _change_cipher,
-                       .derive_eap_msk = _derive_eap_msk,
-                       .get_eap_msk = _get_eap_msk,
-                       .destroy = _destroy,
-               },
-               .tls = tls,
-       );
-
-       build_cipher_suite_list(this);
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_crypto.h b/src/libcharon/plugins/eap_tls/tls/tls_crypto.h
deleted file mode 100644 (file)
index 69b8da7..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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_crypto tls_crypto
- * @{ @ingroup tls
- */
-
-#ifndef TLS_CRYPTO_H_
-#define TLS_CRYPTO_H_
-
-typedef struct tls_crypto_t tls_crypto_t;
-typedef enum tls_cipher_suite_t tls_cipher_suite_t;
-
-#include "tls.h"
-#include "tls_prf.h"
-#include "tls_protection.h"
-
-#include <credentials/keys/private_key.h>
-
-/**
- * TLS cipher suites
- */
-enum tls_cipher_suite_t {
-       TLS_NULL_WITH_NULL_NULL =                               0x00,
-       TLS_RSA_WITH_NULL_MD5 =                                 0x01,
-       TLS_RSA_WITH_NULL_SHA =                                 0x02,
-       TLS_RSA_WITH_NULL_SHA256 =                              0x3B,
-       TLS_RSA_WITH_RC4_128_MD5 =                              0x04,
-       TLS_RSA_WITH_RC4_128_SHA =                              0x05,
-       TLS_RSA_WITH_3DES_EDE_CBC_SHA =                 0x0A,
-       TLS_RSA_WITH_AES_128_CBC_SHA =                  0x2F,
-       TLS_RSA_WITH_AES_256_CBC_SHA =                  0x35,
-       TLS_RSA_WITH_AES_128_CBC_SHA256 =               0x3C,
-       TLS_RSA_WITH_AES_256_CBC_SHA256 =               0x3D,
-       TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =              0x0D,
-       TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =              0x10,
-       TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =             0x13,
-       TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =             0x16,
-       TLS_DH_DSS_WITH_AES_128_CBC_SHA =               0x30,
-       TLS_DH_RSA_WITH_AES_128_CBC_SHA =               0x31,
-       TLS_DHE_DSS_WITH_AES_128_CBC_SHA =              0x32,
-       TLS_DHE_RSA_WITH_AES_128_CBC_SHA =              0x33,
-       TLS_DH_DSS_WITH_AES_256_CBC_SHA =               0x36,
-       TLS_DH_RSA_WITH_AES_256_CBC_SHA =               0x37,
-       TLS_DHE_DSS_WITH_AES_256_CBC_SHA =              0x38,
-       TLS_DHE_RSA_WITH_AES_256_CBC_SHA =              0x39,
-       TLS_DH_DSS_WITH_AES_128_CBC_SHA256 =    0x3E,
-       TLS_DH_RSA_WITH_AES_128_CBC_SHA256 =    0x3F,
-       TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 =   0x40,
-       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 =   0x67,
-       TLS_DH_DSS_WITH_AES_256_CBC_SHA256 =    0x68,
-       TLS_DH_RSA_WITH_AES_256_CBC_SHA256 =    0x69,
-       TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 =   0x6A,
-       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 =   0x6B,
-       TLS_DH_ANON_WITH_RC4_128_MD5 =                  0x18,
-       TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA =             0x1B,
-       TLS_DH_ANON_WITH_AES_128_CBC_SHA =              0x34,
-       TLS_DH_ANON_WITH_AES_256_CBC_SHA =              0x3A,
-       TLS_DH_ANON_WITH_AES_128_CBC_SHA256 =   0x6C,
-       TLS_DH_ANON_WITH_AES_256_CBC_SHA256 =   0x6D,
-};
-
-/**
- * TLS crypto helper functions.
- */
-struct tls_crypto_t {
-
-       /**
-        * Get a list of supported TLS cipher suites.
-        *
-        * @param suites                list of suites, points to internal data
-        * @return                              number of suites returned
-        */
-       int (*get_cipher_suites)(tls_crypto_t *this, tls_cipher_suite_t **suites);
-
-       /**
-        * Select and store a cipher suite from a given list of candidates.
-        *
-        * @param suites                list of candidates to select from
-        * @param count                 number of suites
-        * @return                              selected suite, 0 if none acceptable
-        */
-       tls_cipher_suite_t (*select_cipher_suite)(tls_crypto_t *this,
-                                                                               tls_cipher_suite_t *suites, int count);
-
-       /**
-        * Set the protection layer of the TLS stack to control it.
-        *
-        * @param protection            protection layer to work on
-        */
-       void (*set_protection)(tls_crypto_t *this, tls_protection_t *protection);
-
-       /**
-        * Store exchanged handshake data, used for cryptographic operations.
-        *
-        * @param type                  handshake sub type
-        * @param data                  data to append to handshake buffer
-        */
-       void (*append_handshake)(tls_crypto_t *this,
-                                                        tls_handshake_type_t type, chunk_t data);
-
-       /**
-        * Create a signature of the handshake data using a given private key.
-        *
-        * @param key                   private key to use for signature
-        * @param writer                TLS writer to write signature to
-        * @return                              TRUE if signature create successfully
-        */
-       bool (*sign_handshake)(tls_crypto_t *this, private_key_t *key,
-                                                  tls_writer_t *writer);
-
-       /**
-        * Verify the signature over handshake data using a given public key.
-        *
-        * @param key                   public key to verify signature with
-        * @param reader                TLS reader to read signature from
-        * @return                              TRUE if signature valid
-        */
-       bool (*verify_handshake)(tls_crypto_t *this, public_key_t *key,
-                                                        tls_reader_t *reader);
-
-       /**
-        * Calculate the data of a TLS finished message.
-        *
-        * @param label                 ASCII label to use for calculation
-        * @param out                   buffer to write finished data to
-        * @return                              TRUE if calculation successful
-        */
-       bool (*calculate_finished)(tls_crypto_t *this, char *label, char out[12]);
-
-       /**
-        * Derive the master secret, MAC and encryption keys.
-        *
-        * @param premaster             premaster secret
-        * @param client_random random data from client hello
-        * @param server_random random data from server hello
-        */
-       void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster,
-                                                  chunk_t client_random, chunk_t server_random);
-
-       /**
-        * Change the cipher used at protection layer.
-        *
-        * @param inbound               TRUE to change inbound cipher, FALSE for outbound
-        */
-       void (*change_cipher)(tls_crypto_t *this, bool inbound);
-
-       /**
-        * Derive the EAP-TLS MSK.
-        *
-        * @param client_random random data from client hello
-        * @param server_random random data from server hello
-        */
-       void (*derive_eap_msk)(tls_crypto_t *this,
-                                                  chunk_t client_random, chunk_t server_random);
-
-       /**
-        * Get the MSK to use in EAP-TLS.
-        *
-        * @return                              MSK, points to internal data
-        */
-       chunk_t (*get_eap_msk)(tls_crypto_t *this);
-
-       /**
-        * Destroy a tls_crypto_t.
-        */
-       void (*destroy)(tls_crypto_t *this);
-};
-
-/**
- * Create a tls_crypto instance.
- */
-tls_crypto_t *tls_crypto_create(tls_t *tls);
-
-#endif /** TLS_CRYPTO_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_fragmentation.c b/src/libcharon/plugins/eap_tls/tls/tls_fragmentation.c
deleted file mode 100644 (file)
index 7a99c92..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * 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_fragmentation.h"
-
-#include "tls_reader.h"
-
-#include <daemon.h>
-
-typedef struct private_tls_fragmentation_t private_tls_fragmentation_t;
-
-/**
- * Private data of an tls_fragmentation_t object.
- */
-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;
-
-       /**
-        * Handshake output buffer
-        */
-       chunk_t output;
-};
-
-/**
- * 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
-
-/**
- * Process TLS handshake protocol data
- */
-static status_t process_handshake(private_tls_fragmentation_t *this,
-                                                                 tls_reader_t *reader)
-{
-       while (reader->remaining(reader))
-       {
-               tls_reader_t *msg;
-               u_int8_t type;
-               u_int32_t len;
-               status_t status;
-               chunk_t data;
-
-               if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
-               {
-                       DBG1(DBG_IKE, "TLS fragment has invalid length");
-                       return FAILED;
-               }
-
-               if (this->input.len == 0)
-               {       /* new handshake message */
-                       if (!reader->read_uint8(reader, &type) ||
-                               !reader->read_uint24(reader, &len))
-                       {
-                               return FAILED;
-                       }
-                       this->type = type;
-                       if (len > MAX_TLS_HANDSHAKE_LEN)
-                       {
-                               DBG1(DBG_IKE, "TLS handshake message exceeds maximum length");
-                               return FAILED;
-                       }
-                       chunk_free(&this->input);
-                       this->inpos = 0;
-                       if (len)
-                       {
-                               this->input = chunk_alloc(len);
-                       }
-               }
-
-               len = min(this->input.len - this->inpos, reader->remaining(reader));
-               if (!reader->read_data(reader, len, &data))
-               {
-                       return FAILED;
-               }
-               memcpy(this->input.ptr + this->inpos, data.ptr, len);
-               this->inpos += len;
-
-               if (this->input.len == this->inpos)
-               {       /* message completely defragmented, process */
-                       msg = tls_reader_create(this->input);
-                       status = this->handshake->process(this->handshake, this->type, msg);
-                       msg->destroy(msg);
-                       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)
-{
-       tls_reader_t *reader;
-       status_t status;
-
-       reader = tls_reader_create(data);
-       switch (type)
-       {
-               case TLS_CHANGE_CIPHER_SPEC:
-                       if (this->handshake->change_cipherspec(this->handshake))
-                       {
-                               status = NEED_MORE;
-                               break;
-                       }
-                       status = FAILED;
-                       break;
-               case TLS_ALERT:
-                       /* TODO: handle Alert */
-                       status = FAILED;
-                       break;
-               case TLS_HANDSHAKE:
-                       status = process_handshake(this, reader);
-                       break;
-               case TLS_APPLICATION_DATA:
-                       /* skip application data */
-                       status = NEED_MORE;
-                       break;
-               default:
-                       DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type);
-                       status = NEED_MORE;
-                       break;
-       }
-       reader->destroy(reader);
-       return status;
-}
-
-METHOD(tls_fragmentation_t, build, status_t,
-       private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
-{
-       tls_handshake_type_t hs_type;
-       tls_writer_t *writer, *msg;
-       status_t status;
-
-       if (this->handshake->cipherspec_changed(this->handshake))
-       {
-               *type = TLS_CHANGE_CIPHER_SPEC;
-               *data = chunk_clone(chunk_from_chars(0x01));
-               return NEED_MORE;
-       }
-
-       if (!this->output.len)
-       {
-               msg = tls_writer_create(64);
-               do
-               {
-                       writer = tls_writer_create(64);
-                       status = this->handshake->build(this->handshake, &hs_type, writer);
-                       switch (status)
-                       {
-                               case NEED_MORE:
-                                       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);
-               }
-               while (status == NEED_MORE);
-
-               msg->destroy(msg);
-               if (status != INVALID_STATE)
-               {
-                       return status;
-               }
-       }
-
-       if (this->output.len)
-       {
-               *type = TLS_HANDSHAKE;
-               if (this->output.len <= MAX_TLS_FRAGMENT_LEN)
-               {
-                       *data = this->output;
-                       this->output = chunk_empty;
-                       return NEED_MORE;
-               }
-               *data = chunk_create(this->output.ptr, MAX_TLS_FRAGMENT_LEN);
-               this->output = chunk_clone(chunk_skip(this->output, MAX_TLS_FRAGMENT_LEN));
-               return NEED_MORE;
-       }
-       return status;
-}
-
-METHOD(tls_fragmentation_t, destroy, void,
-       private_tls_fragmentation_t *this)
-{
-       free(this->input.ptr);
-       free(this->output.ptr);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
-{
-       private_tls_fragmentation_t *this;
-
-       INIT(this,
-               .public = {
-                       .process = _process,
-                       .build = _build,
-                       .destroy = _destroy,
-               },
-               .handshake = handshake,
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_fragmentation.h b/src/libcharon/plugins/eap_tls/tls/tls_fragmentation.h
deleted file mode 100644 (file)
index 61bf548..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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_fragmentation tls_fragmentation
- * @{ @ingroup tls
- */
-
-#ifndef TLS_FRAGMENTATION_H_
-#define TLS_FRAGMENTATION_H_
-
-typedef struct tls_fragmentation_t tls_fragmentation_t;
-
-#include <library.h>
-
-#include "tls.h"
-#include "tls_handshake.h"
-
-/**
- * TLS record protocol fragmentation layer.
- */
-struct tls_fragmentation_t {
-
-       /**
-        * Process a fragmented TLS record, pass it to upper layers.
-        *
-        * @param type          type of the TLS record to process
-        * @param data          associated TLS record data
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if more invocations to process/build needed
-        */
-       status_t (*process)(tls_fragmentation_t *this,
-                                               tls_content_type_t type, chunk_t data);
-
-       /**
-        * Query upper layer for TLS messages, build fragmented records.
-        *
-        * @param type          type of the built TLS record
-        * @param data          allocated data of the built TLS record
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if upper layers have more records to send
-        *                                      - INVALID_STATE if more input records required
-        */
-       status_t (*build)(tls_fragmentation_t *this,
-                                         tls_content_type_t *type, chunk_t *data);
-
-       /**
-        * Destroy a tls_fragmentation_t.
-        */
-       void (*destroy)(tls_fragmentation_t *this);
-};
-
-/**
- * Create a tls_fragmentation instance.
- *
- * @param handshake                    upper layer handshake protocol
- * @return                                     TLS fragmentation layer.
- */
-tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake);
-
-#endif /** TLS_FRAGMENTATION_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_handshake.h b/src/libcharon/plugins/eap_tls/tls/tls_handshake.h
deleted file mode 100644 (file)
index 1139740..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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"
-#include "tls_reader.h"
-#include "tls_writer.h"
-
-/**
- * TLS handshake state machine interface.
- */
-struct tls_handshake_t {
-
-       /**
-        * Process received TLS handshake message.
-        *
-        * @param type          TLS handshake message type
-        * @param reader        TLS data buffer
-        * @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, tls_reader_t *reader);
-
-       /**
-        * Build TLS handshake messages to send out.
-        *
-        * @param type          type of created handshake message
-        * @param writer        TLS data buffer to write to
-        * @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, tls_writer_t *writer);
-
-       /**
-        * Check if the cipher spec for outgoing messages has changed.
-        *
-        * @return                      TRUE if cipher spec changed
-        */
-       bool (*cipherspec_changed)(tls_handshake_t *this);
-
-       /**
-        * Change the cipher spec for incoming messages.
-        *
-        * @return                      TRUE if cipher spec changed
-        */
-       bool (*change_cipherspec)(tls_handshake_t *this);
-
-       /**
-        * Destroy a tls_handshake_t.
-        */
-       void (*destroy)(tls_handshake_t *this);
-};
-
-#endif /** TLS_HANDSHAKE_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_peer.c b/src/libcharon/plugins/eap_tls/tls/tls_peer.c
deleted file mode 100644 (file)
index 9597359..0000000
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * 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;
-
-typedef enum {
-       STATE_INIT,
-       STATE_HELLO_SENT,
-       STATE_HELLO_RECEIVED,
-       STATE_HELLO_DONE,
-       STATE_CERT_SENT,
-       STATE_CERT_RECEIVED,
-       STATE_CERTREQ_RECEIVED,
-       STATE_KEY_EXCHANGE_SENT,
-       STATE_VERIFY_SENT,
-       STATE_CIPHERSPEC_CHANGED_OUT,
-       STATE_FINISHED_SENT,
-       STATE_CIPHERSPEC_CHANGED_IN,
-       STATE_COMPLETE,
-} peer_state_t;
-
-/**
- * Private data of an tls_peer_t object.
- */
-struct private_tls_peer_t {
-
-       /**
-        * Public tls_peer_t interface.
-        */
-       tls_peer_t public;
-
-       /**
-        * TLS stack
-        */
-       tls_t *tls;
-
-       /**
-        * TLS crypto context
-        */
-       tls_crypto_t *crypto;
-
-       /**
-        * Peer identity
-        */
-       identification_t *peer;
-
-       /**
-        * Server identity
-        */
-       identification_t *server;
-
-       /**
-        * State we are in
-        */
-       peer_state_t state;
-
-       /**
-        * Hello random data selected by client
-        */
-       char client_random[32];
-
-       /**
-        * Hello random data selected by server
-        */
-       char server_random[32];
-
-       /**
-        * Auth helper for peer authentication
-        */
-       auth_cfg_t *peer_auth;
-
-       /**
-        * Auth helper for server authentication
-        */
-       auth_cfg_t *server_auth;
-
-       /**
-        * Peer private key
-        */
-       private_key_t *private;
-};
-
-/**
- * Process a server hello message
- */
-static status_t process_server_hello(private_tls_peer_t *this,
-                                                                        tls_reader_t *reader)
-{
-       u_int8_t compression;
-       u_int16_t version, cipher;
-       chunk_t random, session, ext = chunk_empty;
-       tls_cipher_suite_t suite;
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_SERVER_HELLO, reader->peek(reader));
-
-       if (!reader->read_uint16(reader, &version) ||
-               !reader->read_data(reader, sizeof(this->server_random), &random) ||
-               !reader->read_data8(reader, &session) ||
-               !reader->read_uint16(reader, &cipher) ||
-               !reader->read_uint8(reader, &compression) ||
-               (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
-       {
-               DBG1(DBG_IKE, "received invalid ServerHello");
-               return FAILED;
-       }
-
-       memcpy(this->server_random, random.ptr, sizeof(this->server_random));
-
-       if (version < this->tls->get_version(this->tls))
-       {
-               this->tls->set_version(this->tls, version);
-       }
-       suite = cipher;
-       if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1))
-       {
-               DBG1(DBG_IKE, "received cipher suite inacceptable");
-               return FAILED;
-       }
-       this->state = STATE_HELLO_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process a Certificate message
- */
-static status_t process_certificate(private_tls_peer_t *this,
-                                                                       tls_reader_t *reader)
-{
-       certificate_t *cert;
-       tls_reader_t *certs;
-       chunk_t data;
-       bool first = TRUE;
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_CERTIFICATE, reader->peek(reader));
-
-       if (!reader->read_data24(reader, &data))
-       {
-               return FAILED;
-       }
-       certs = tls_reader_create(data);
-       while (certs->remaining(certs))
-       {
-               if (!certs->read_data24(certs, &data))
-               {
-                       certs->destroy(certs);
-                       return FAILED;
-               }
-               cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-                                                                 BUILD_BLOB_ASN1_DER, data, BUILD_END);
-               if (cert)
-               {
-                       if (first)
-                       {
-                               this->server_auth->add(this->server_auth,
-                                                                          AUTH_HELPER_SUBJECT_CERT, cert);
-                               DBG1(DBG_IKE, "received TLS server certificate '%Y'",
-                                        cert->get_subject(cert));
-                               first = FALSE;
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
-                                        cert->get_subject(cert));
-                               this->server_auth->add(this->server_auth,
-                                                                          AUTH_HELPER_IM_CERT, cert);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
-               }
-       }
-       certs->destroy(certs);
-       this->state = STATE_CERT_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process a Certificate message
- */
-static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
-{
-       chunk_t types, hashsig, data;
-       tls_reader_t *authorities;
-       identification_t *id;
-       certificate_t *cert;
-
-       this->crypto->append_handshake(this->crypto,
-                                                               TLS_CERTIFICATE_REQUEST, reader->peek(reader));
-
-       if (!reader->read_data8(reader, &types))
-       {
-               return FAILED;
-       }
-       if (this->tls->get_version(this->tls) >= TLS_1_2)
-       {
-               if (!reader->read_data16(reader, &hashsig))
-               {
-                       return FAILED;
-               }
-               /* TODO: store supported hashsig algorithms */
-       }
-       if (!reader->read_data16(reader, &data))
-       {
-               return FAILED;
-       }
-       authorities = tls_reader_create(data);
-       while (authorities->remaining(authorities))
-       {
-               if (!authorities->read_data16(authorities, &data))
-               {
-                       authorities->destroy(authorities);
-                       return FAILED;
-               }
-               id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
-               cert = lib->credmgr->get_cert(lib->credmgr,
-                                                                         CERT_X509, KEY_ANY, id, TRUE);
-               if (cert)
-               {
-                       DBG1(DBG_IKE, "received cert request for '%Y", id);
-                       this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "received cert request for unknown CA '%Y'", id);
-               }
-               id->destroy(id);
-       }
-       authorities->destroy(authorities);
-       this->state = STATE_CERTREQ_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process Hello Done message
- */
-static status_t process_hello_done(private_tls_peer_t *this,
-                                                                  tls_reader_t *reader)
-{
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_SERVER_HELLO_DONE, reader->peek(reader));
-       this->state = STATE_HELLO_DONE;
-       return NEED_MORE;
-}
-
-/**
- * Process finished message
- */
-static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
-{
-       chunk_t received;
-       char buf[12];
-
-       if (!reader->read_data(reader, sizeof(buf), &received))
-       {
-               DBG1(DBG_IKE, "received server finished too short");
-               return FAILED;
-       }
-       if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
-       {
-               DBG1(DBG_IKE, "calculating server finished failed");
-               return FAILED;
-       }
-       if (!chunk_equals(received, chunk_from_thing(buf)))
-       {
-               DBG1(DBG_IKE, "received server finished invalid");
-               return FAILED;
-       }
-       this->state = STATE_COMPLETE;
-       this->crypto->derive_eap_msk(this->crypto,
-                                                                chunk_from_thing(this->client_random),
-                                                                chunk_from_thing(this->server_random));
-       return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, process, status_t,
-       private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
-{
-       tls_handshake_type_t expected;
-
-       switch (this->state)
-       {
-               case STATE_HELLO_SENT:
-                       if (type == TLS_SERVER_HELLO)
-                       {
-                               return process_server_hello(this, reader);
-                       }
-                       expected = TLS_SERVER_HELLO;
-                       break;
-               case STATE_HELLO_RECEIVED:
-                       if (type == TLS_CERTIFICATE)
-                       {
-                               return process_certificate(this, reader);
-                       }
-                       expected = TLS_CERTIFICATE;
-                       break;
-               case STATE_CERT_RECEIVED:
-                       if (type == TLS_CERTIFICATE_REQUEST)
-                       {
-                               return process_certreq(this, reader);
-                       }
-                       expected = TLS_CERTIFICATE_REQUEST;
-                       break;
-               case STATE_CERTREQ_RECEIVED:
-                       if (type == TLS_SERVER_HELLO_DONE)
-                       {
-                               return process_hello_done(this, reader);
-                       }
-                       expected = TLS_SERVER_HELLO_DONE;
-                       break;
-               case STATE_CIPHERSPEC_CHANGED_IN:
-                       if (type == TLS_FINISHED)
-                       {
-                               return process_finished(this, reader);
-                       }
-                       expected = TLS_FINISHED;
-                       break;
-               default:
-                       DBG1(DBG_IKE, "TLS %N not expected in current state",
-                                tls_handshake_type_names, type);
-                       return FAILED;
-       }
-       DBG1(DBG_IKE, "TLS %N expected, but received %N",
-                tls_handshake_type_names, expected, tls_handshake_type_names, type);
-       return FAILED;
-}
-
-/**
- * Send a client hello
- */
-static status_t send_client_hello(private_tls_peer_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       tls_cipher_suite_t *suite;
-       int count, i;
-       rng_t *rng;
-
-       htoun32(&this->client_random, time(NULL));
-       rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-       if (!rng)
-       {
-               return FAILED;
-       }
-       rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4);
-       rng->destroy(rng);
-
-       writer->write_uint16(writer, this->tls->get_version(this->tls));
-       writer->write_data(writer, chunk_from_thing(this->client_random));
-       /* session identifier => none */
-       writer->write_data8(writer, chunk_empty);
-
-       count = this->crypto->get_cipher_suites(this->crypto, &suite);
-       writer->write_uint16(writer, count * 2);
-       for (i = 0; i < count; i++)
-       {
-               writer->write_uint16(writer, suite[i]);
-       }
-       /* NULL compression only */
-       writer->write_uint8(writer, 1);
-       writer->write_uint8(writer, 0);
-
-       *type = TLS_CLIENT_HELLO;
-       this->state = STATE_HELLO_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Certificate
- */
-static status_t send_certificate(private_tls_peer_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       enumerator_t *enumerator;
-       certificate_t *cert;
-       auth_rule_t rule;
-       tls_writer_t *certs;
-       chunk_t data;
-
-       this->private = lib->credmgr->get_private(lib->credmgr,
-                                                                               KEY_ANY, this->peer, this->peer_auth);
-       if (!this->private)
-       {
-               DBG1(DBG_IKE, "no TLS peer certificate found for '%Y'", this->peer);
-               return FAILED;
-       }
-
-       /* generate certificate payload */
-       certs = tls_writer_create(256);
-       cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
-       if (cert)
-       {
-               if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
-               {
-                       DBG1(DBG_IKE, "sending TLS peer certificate '%Y'",
-                                cert->get_subject(cert));
-                       certs->write_data24(certs, data);
-                       free(data.ptr);
-               }
-       }
-       enumerator = this->peer_auth->create_enumerator(this->peer_auth);
-       while (enumerator->enumerate(enumerator, &rule, &cert))
-       {
-               if (rule == AUTH_RULE_IM_CERT)
-               {
-                       if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
-                       {
-                               DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
-                                        cert->get_subject(cert));
-                               certs->write_data24(certs, data);
-                               free(data.ptr);
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       writer->write_data24(writer, certs->get_buf(certs));
-       certs->destroy(certs);
-
-       *type = TLS_CERTIFICATE;
-       this->state = STATE_CERT_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send client key exchange
- */
-static status_t send_key_exchange(private_tls_peer_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       public_key_t *public = NULL, *current;
-       enumerator_t *enumerator;
-       auth_cfg_t *auth;
-       rng_t *rng;
-       char premaster[48];
-       chunk_t encrypted;
-
-       rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
-       if (!rng)
-       {
-               DBG1(DBG_IKE, "no suitable RNG found for TLS premaster secret");
-               return FAILED;
-       }
-       rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
-       rng->destroy(rng);
-       htoun16(premaster, TLS_1_2);
-
-       this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
-                                                                chunk_from_thing(this->client_random),
-                                                                chunk_from_thing(this->server_random));
-
-       enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
-                                                                       KEY_ANY, this->server, this->server_auth);
-       while (enumerator->enumerate(enumerator, &current, &auth))
-       {
-               public = current->get_ref(current);
-               break;
-       }
-       enumerator->destroy(enumerator);
-
-       if (!public)
-       {
-               DBG1(DBG_IKE, "no TLS public key found for server '%Y'", this->server);
-               return FAILED;
-       }
-       if (!public->encrypt(public, chunk_from_thing(premaster), &encrypted))
-       {
-               public->destroy(public);
-               DBG1(DBG_IKE, "encrypting TLS premaster secret failed");
-               return FAILED;
-       }
-
-       public->destroy(public);
-
-       writer->write_data16(writer, encrypted);
-       free(encrypted.ptr);
-
-       *type = TLS_CLIENT_KEY_EXCHANGE;
-       this->state = STATE_KEY_EXCHANGE_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send certificate verify
- */
-static status_t send_certificate_verify(private_tls_peer_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       if (!this->private ||
-               !this->crypto->sign_handshake(this->crypto, this->private, writer))
-       {
-               DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
-               return FAILED;
-       }
-
-       *type = TLS_CERTIFICATE_VERIFY;
-       this->state = STATE_VERIFY_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Finished
- */
-static status_t send_finished(private_tls_peer_t *this,
-                                                         tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       char buf[12];
-
-       if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
-       {
-               DBG1(DBG_IKE, "calculating client finished data failed");
-               return FAILED;
-       }
-
-       writer->write_data(writer, chunk_from_thing(buf));
-
-       *type = TLS_FINISHED;
-       this->state = STATE_FINISHED_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, build, status_t,
-       private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       switch (this->state)
-       {
-               case STATE_INIT:
-                       return send_client_hello(this, type, writer);
-               case STATE_HELLO_DONE:
-                       return send_certificate(this, type, writer);
-               case STATE_CERT_SENT:
-                       return send_key_exchange(this, type, writer);
-               case STATE_KEY_EXCHANGE_SENT:
-                       return send_certificate_verify(this, type, writer);
-               case STATE_CIPHERSPEC_CHANGED_OUT:
-                       return send_finished(this, type, writer);
-               default:
-                       return INVALID_STATE;
-       }
-}
-
-METHOD(tls_handshake_t, cipherspec_changed, bool,
-       private_tls_peer_t *this)
-{
-       if (this->state == STATE_VERIFY_SENT)
-       {
-               this->crypto->change_cipher(this->crypto, FALSE);
-               this->state = STATE_CIPHERSPEC_CHANGED_OUT;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(tls_handshake_t, change_cipherspec, bool,
-       private_tls_peer_t *this)
-{
-       if (this->state == STATE_FINISHED_SENT)
-       {
-               this->crypto->change_cipher(this->crypto, TRUE);
-               this->state = STATE_CIPHERSPEC_CHANGED_IN;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(tls_handshake_t, destroy, void,
-       private_tls_peer_t *this)
-{
-       DESTROY_IF(this->private);
-       this->peer_auth->destroy(this->peer_auth);
-       this->server_auth->destroy(this->server_auth);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
-                                                       identification_t *peer, identification_t *server)
-{
-       private_tls_peer_t *this;
-
-       INIT(this,
-               .public.handshake = {
-                       .process = _process,
-                       .build = _build,
-                       .cipherspec_changed = _cipherspec_changed,
-                       .change_cipherspec = _change_cipherspec,
-                       .destroy = _destroy,
-               },
-               .state = STATE_INIT,
-               .tls = tls,
-               .crypto = crypto,
-               .peer = peer,
-               .server = server,
-               .peer_auth = auth_cfg_create(),
-               .server_auth = auth_cfg_create(),
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_peer.h b/src/libcharon/plugins/eap_tls/tls/tls_peer.h
deleted file mode 100644 (file)
index 7857d32..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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"
-#include "tls_crypto.h"
-
-#include <library.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(tls_t *tls, tls_crypto_t *crypto,
-                                                       identification_t *peer, identification_t *server);
-
-#endif /** TLS_PEER_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_prf.c b/src/libcharon/plugins/eap_tls/tls/tls_prf.c
deleted file mode 100644 (file)
index f181d01..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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_prf.h"
-
-typedef struct private_tls_prf12_t private_tls_prf12_t;
-
-/**
- * Private data of an tls_prf_t object.
- */
-struct private_tls_prf12_t {
-
-       /**
-        * Public tls_prf_t interface.
-        */
-       tls_prf_t public;
-
-       /**
-        * Underlying primitive PRF
-        */
-       prf_t *prf;
-};
-
-METHOD(tls_prf_t, set_key12, void,
-       private_tls_prf12_t *this, chunk_t key)
-{
-       this->prf->set_key(this->prf, key);
-}
-
-/**
- * The P_hash function as in TLS 1.0/1.2
- */
-static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size,
-                                  size_t bytes, char *out)
-{
-       char buf[block_size], abuf[block_size];
-       chunk_t a;
-
-       /* seed = label + seed */
-       seed = chunk_cata("cc", chunk_create(label, strlen(label)), seed);
-       /* A(0) = seed */
-       a = seed;
-
-       while (TRUE)
-       {
-               /* A(i) = HMAC_hash(secret, A(i-1)) */
-               prf->get_bytes(prf, a, abuf);
-               a = chunk_from_thing(abuf);
-               /* HMAC_hash(secret, A(i) + seed) */
-               prf->get_bytes(prf, a, NULL);
-               prf->get_bytes(prf, seed, buf);
-
-               if (bytes <= block_size)
-               {
-                       memcpy(out, buf, bytes);
-                       break;
-               }
-               memcpy(out, buf, block_size);
-               out += block_size;
-               bytes -= block_size;
-       }
-}
-
-METHOD(tls_prf_t, get_bytes12, void,
-       private_tls_prf12_t *this, char *label, chunk_t seed,
-       size_t bytes, char *out)
-{
-       p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf),
-                  bytes, out);
-}
-
-METHOD(tls_prf_t, destroy12, void,
-       private_tls_prf12_t *this)
-{
-       this->prf->destroy(this->prf);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf)
-{
-       private_tls_prf12_t *this;
-
-       INIT(this,
-               .public = {
-                       .set_key = _set_key12,
-                       .get_bytes = _get_bytes12,
-                       .destroy = _destroy12,
-               },
-               .prf = lib->crypto->create_prf(lib->crypto, prf),
-       );
-       if (!this->prf)
-       {
-               free(this);
-               return NULL;
-       }
-       return &this->public;
-}
-
-
-typedef struct private_tls_prf10_t private_tls_prf10_t;
-
-/**
- * Private data of an tls_prf_t object.
- */
-struct private_tls_prf10_t {
-
-       /**
-        * Public tls_prf_t interface.
-        */
-       tls_prf_t public;
-
-       /**
-        * Underlying MD5 PRF
-        */
-       prf_t *md5;
-
-       /**
-        * Underlying SHA1 PRF
-        */
-       prf_t *sha1;
-};
-
-METHOD(tls_prf_t, set_key10, void,
-       private_tls_prf10_t *this, chunk_t key)
-{
-       size_t len = key.len / 2 + key.len % 2;
-
-       this->md5->set_key(this->md5, chunk_create(key.ptr, len));
-       this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, len));
-}
-
-METHOD(tls_prf_t, get_bytes10, void,
-       private_tls_prf10_t *this, char *label, chunk_t seed,
-       size_t bytes, char *out)
-{
-       char buf[bytes];
-
-       p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5),
-                  bytes, out);
-       p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1),
-                  bytes, buf);
-       memxor(out, buf, bytes);
-}
-
-METHOD(tls_prf_t, destroy10, void,
-       private_tls_prf10_t *this)
-{
-       DESTROY_IF(this->md5);
-       DESTROY_IF(this->sha1);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_prf_t *tls_prf_create_10(pseudo_random_function_t prf)
-{
-       private_tls_prf10_t *this;
-
-       INIT(this,
-               .public = {
-                       .set_key = _set_key10,
-                       .get_bytes = _get_bytes10,
-                       .destroy = _destroy10,
-               },
-               .md5 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_MD5),
-               .sha1 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA1),
-       );
-       if (!this->md5 || !this->sha1)
-       {
-               destroy10(this);
-               return NULL;
-       }
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_prf.h b/src/libcharon/plugins/eap_tls/tls/tls_prf.h
deleted file mode 100644 (file)
index 7326be9..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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_prf tls_prf
- * @{ @ingroup tls
- */
-
-#ifndef TLS_PRF_H_
-#define TLS_PRF_H_
-
-typedef struct tls_prf_t tls_prf_t;
-
-#include <crypto/prfs/prf.h>
-
-/**
- * The PRF function specified on TLS, based on HMAC.
- */
-struct tls_prf_t {
-
-       /**
-        * Set the key of the PRF function.
-        *
-        * @param key           key to set
-        */
-       void (*set_key)(tls_prf_t *this, chunk_t key);
-
-       /**
-        * Generate a series of bytes using a label and a seed.
-        *
-        * @param label         ASCII input label
-        * @param seed          seed input value
-        * @param bytes         number of bytes to get
-        * @param out           buffer receiving bytes
-        */
-       void (*get_bytes)(tls_prf_t *this, char *label, chunk_t seed,
-                                         size_t bytes, char *out);
-
-       /**
-        * Destroy a tls_prf_t.
-        */
-       void (*destroy)(tls_prf_t *this);
-};
-
-/**
- * Create a tls_prf instance with specific algorithm as in TLS 1.2.
- *
- * @param hash                 underlying PRF function to use
- * @return                             TLS PRF algorithm
- */
-tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf);
-
-/**
- * Create a tls_prf instance with XOred SHA1/MD5 as in TLS 1.0/1.1.
- *
- * @return                             TLS PRF algorithm
- */
-tls_prf_t *tls_prf_create_10();
-
-#endif /** TLS_PRF_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_protection.c b/src/libcharon/plugins/eap_tls/tls/tls_protection.c
deleted file mode 100644 (file)
index 75fae0a..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * 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_protection.h"
-
-#include <daemon.h>
-
-typedef struct private_tls_protection_t private_tls_protection_t;
-
-/**
- * Private data of an tls_protection_t object.
- */
-struct private_tls_protection_t {
-
-       /**
-        * Public tls_protection_t interface.
-        */
-       tls_protection_t public;
-
-       /**
-        * TLS context
-        */
-       tls_t *tls;
-
-       /**
-        * Upper layer, TLS record compression
-        */
-       tls_compression_t *compression;
-
-       /**
-        * RNG if we generate IVs ourself
-        */
-       rng_t *rng;
-
-       /**
-        * Sequence number of incoming records
-        */
-       u_int32_t seq_in;
-
-       /**
-        * Sequence number for outgoing records
-        */
-       u_int32_t seq_out;
-
-       /**
-        * Signer instance for inbound traffic
-        */
-       signer_t *signer_in;
-
-       /**
-        * Signer instance for outbound traffic
-        */
-       signer_t *signer_out;
-
-       /**
-        * Crypter instance for inbound traffic
-        */
-       crypter_t *crypter_in;
-
-       /**
-        * Crypter instance for outbound traffic
-        */
-       crypter_t *crypter_out;
-
-       /**
-        * Current IV for input decryption
-        */
-       chunk_t iv_in;
-
-       /**
-        * Current IV for output decryption
-        */
-       chunk_t iv_out;
-};
-
-/**
- * Create the header to append to the record data to create the MAC
- */
-static chunk_t sigheader(u_int32_t seq, u_int8_t type,
-                                                u_int16_t version, u_int16_t length)
-{
-       /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
-       u_int32_t seq_high = 0;
-
-       seq = htonl(seq);
-       version = htons(version);
-       length = htons(length);
-
-       return chunk_cat("ccccc", chunk_from_thing(seq_high),
-                                       chunk_from_thing(seq), chunk_from_thing(type),
-                                       chunk_from_thing(version), chunk_from_thing(length));
-}
-
-METHOD(tls_protection_t, process, status_t,
-       private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
-{
-       if (this->crypter_in)
-       {
-               chunk_t iv, next_iv = chunk_empty;
-               u_int8_t bs, padding_length;
-
-               bs = this->crypter_in->get_block_size(this->crypter_in);
-               if (data.len < bs || data.len % bs)
-               {
-                       DBG1(DBG_IKE, "encrypted TLS record not multiple of block size");
-                       return FAILED;
-               }
-               if (this->iv_in.len)
-               {       /* < TLSv1.1 uses IV from key derivation/last block */
-                       iv = this->iv_in;
-                       next_iv = chunk_clone(chunk_create(data.ptr + data.len - bs, bs));
-               }
-               else
-               {       /* TLSv1.1 uses random IVs, prepended to record */
-                       iv = chunk_create(data.ptr, bs);
-                       data = chunk_skip(data, bs);
-                       if (data.len < bs)
-                       {
-                               DBG1(DBG_IKE, "TLS record too short to decrypt");
-                               return FAILED;
-                       }
-               }
-               this->crypter_in->decrypt(this->crypter_in, data, iv, NULL);
-
-               if (next_iv.len)
-               {       /* next record IV is last ciphertext block of this record */
-                       memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
-                       free(next_iv.ptr);
-               }
-
-               padding_length = data.ptr[data.len - 1];
-               if (padding_length >= data.len)
-               {
-                       DBG1(DBG_IKE, "invalid TLS record padding");
-                       return FAILED;
-               }
-               data.len -= padding_length + 1;
-       }
-       if (this->signer_in)
-       {
-               chunk_t mac, macdata, header;
-               u_int8_t bs;
-
-               bs = this->signer_in->get_block_size(this->signer_in);
-               if (data.len <= bs)
-               {
-                       DBG1(DBG_IKE, "TLS record too short to verify MAC");
-                       return FAILED;
-               }
-               mac = chunk_skip(data, data.len - bs);
-               data.len -= bs;
-
-               header = sigheader(this->seq_in, type,
-                                                  this->tls->get_version(this->tls), data.len);
-               macdata = chunk_cat("mc", header, data);
-               if (!this->signer_in->verify_signature(this->signer_in, macdata, mac))
-               {
-                       DBG1(DBG_IKE, "TLS record MAC verification failed");
-                       free(macdata.ptr);
-                       return FAILED;
-               }
-               free(macdata.ptr);
-       }
-
-       if (type == TLS_CHANGE_CIPHER_SPEC)
-       {
-               this->seq_in = 0;
-       }
-       else
-       {
-               this->seq_in++;
-       }
-       return this->compression->process(this->compression, type, data);
-}
-
-METHOD(tls_protection_t, build, status_t,
-       private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
-{
-       status_t status;
-
-       status = this->compression->build(this->compression, type, data);
-       if (*type == TLS_CHANGE_CIPHER_SPEC)
-       {
-               this->seq_out = 0;
-               return status;
-       }
-
-       if (status == NEED_MORE)
-       {
-               if (this->signer_out)
-               {
-                       chunk_t mac, header;
-
-                       header = sigheader(this->seq_out, *type,
-                                                          this->tls->get_version(this->tls), data->len);
-                       this->signer_out->get_signature(this->signer_out, header, NULL);
-                       free(header.ptr);
-                       this->signer_out->allocate_signature(this->signer_out, *data, &mac);
-                       if (this->crypter_out)
-                       {
-                               chunk_t padding, iv;
-                               u_int8_t bs, padding_length;
-
-                               bs = this->crypter_out->get_block_size(this->crypter_out);
-                               padding_length = bs - ((data->len + mac.len + 1) % bs);
-
-                               padding = chunk_alloca(padding_length);
-                               memset(padding.ptr, padding_length, padding.len);
-
-                               if (this->iv_out.len)
-                               {       /* < TLSv1.1 uses IV from key derivation/last block */
-                                       iv = this->iv_out;
-                               }
-                               else
-                               {       /* TLSv1.1 uses random IVs, prepended to record */
-                                       if (!this->rng)
-                                       {
-                                               DBG1(DBG_IKE, "no RNG supported to generate TLS IV");
-                                               free(data->ptr);
-                                               return FAILED;
-                                       }
-                                       this->rng->allocate_bytes(this->rng, bs, &iv);
-                               }
-
-                               *data = chunk_cat("mmcc", *data, mac, padding,
-                                                                 chunk_from_thing(padding_length));
-                               /* encrypt inline */
-                               this->crypter_out->encrypt(this->crypter_out, *data, iv, NULL);
-
-                               if (this->iv_out.len)
-                               {       /* next record IV is last ciphertext block of this record */
-                                       memcpy(this->iv_out.ptr, data->ptr - this->iv_out.len,
-                                                  this->iv_out.len);
-                               }
-                               else
-                               {       /* prepend IV */
-                                       *data = chunk_cat("mm", iv, *data);
-                               }
-                       }
-                       else
-                       {       /* NULL encryption */
-                               *data = chunk_cat("mm", *data, mac);
-                       }
-               }
-       }
-       this->seq_out++;
-       return status;
-}
-
-METHOD(tls_protection_t, set_cipher, void,
-       private_tls_protection_t *this, bool inbound, signer_t *signer,
-       crypter_t *crypter, chunk_t iv)
-{
-       if (inbound)
-       {
-               this->signer_in = signer;
-               this->crypter_in = crypter;
-               this->iv_in = iv;
-       }
-       else
-       {
-               this->signer_out = signer;
-               this->crypter_out = crypter;
-               this->iv_out = iv;
-               if (!iv.len)
-               {       /* generate IVs if none given */
-                       this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-               }
-       }
-}
-
-METHOD(tls_protection_t, destroy, void,
-       private_tls_protection_t *this)
-{
-       DESTROY_IF(this->rng);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_protection_t *tls_protection_create(tls_t *tls,
-                                                                               tls_compression_t *compression)
-{
-       private_tls_protection_t *this;
-
-       INIT(this,
-               .public = {
-                       .process = _process,
-                       .build = _build,
-                       .set_cipher = _set_cipher,
-                       .destroy = _destroy,
-               },
-               .tls = tls,
-               .compression = compression,
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_protection.h b/src/libcharon/plugins/eap_tls/tls/tls_protection.h
deleted file mode 100644 (file)
index fab9137..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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_protection tls_protection
- * @{ @ingroup tls
- */
-
-#ifndef TLS_PROTECTION_H_
-#define TLS_PROTECTION_H_
-
-typedef struct tls_protection_t tls_protection_t;
-
-#include <library.h>
-
-#include "tls.h"
-#include "tls_compression.h"
-
-/**
- * TLS record protocol protection layer.
- */
-struct tls_protection_t {
-
-       /**
-        * Process a protected TLS record, pass it to upper layers.
-        *
-        * @param type          type of the TLS record to process
-        * @param data          associated TLS record data
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if more invocations to process/build needed
-        */
-       status_t (*process)(tls_protection_t *this,
-                                               tls_content_type_t type, chunk_t data);
-
-       /**
-        * Query upper layer for TLS record, build protected record.
-        *
-        * @param type          type of the built TLS record
-        * @param data          allocated data of the built TLS record
-        * @return
-        *                                      - SUCCESS if TLS negotiation complete
-        *                                      - FAILED if TLS handshake failed
-        *                                      - NEED_MORE if upper layers have more records to send
-        *                                      - INVALID_STATE if more input records required
-        */
-       status_t (*build)(tls_protection_t *this,
-                                         tls_content_type_t *type, chunk_t *data);
-
-       /**
-        * Set a new cipher, including encryption and integrity algorithms.
-        *
-        * @param inbound       TRUE to use cipher for inbound data, FALSE for outbound
-        * @param signer        new signer to use, gets owned by protection layer
-        * @param crypter       new crypter to use, gets owned by protection layer
-        * @param iv            initial IV for crypter, gets owned by protection layer
-        */
-       void (*set_cipher)(tls_protection_t *this, bool inbound, signer_t *signer,
-                                          crypter_t *crypter, chunk_t iv);
-
-       /**
-        * Destroy a tls_protection_t.
-        */
-       void (*destroy)(tls_protection_t *this);
-};
-
-/**
- * Create a tls_protection instance.
- *
- * @param tls                          TLS context
- * @param compression          compression layer of TLS stack
- * @return                                     TLS protection layer.
- */
-tls_protection_t *tls_protection_create(tls_t *tls,
-                                                                               tls_compression_t *compression);
-
-#endif /** TLS_PROTECTION_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_reader.c b/src/libcharon/plugins/eap_tls/tls/tls_reader.c
deleted file mode 100644 (file)
index b21eb04..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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.
- */
-
-#include "tls_reader.h"
-
-#include <daemon.h>
-
-typedef struct private_tls_reader_t private_tls_reader_t;
-
-/**
- * Private data of an tls_reader_t object.
- */
-struct private_tls_reader_t {
-
-       /**
-        * Public tls_reader_t interface.
-        */
-       tls_reader_t public;
-
-       /**
-        * Remaining data to process
-        */
-       chunk_t buf;
-};
-
-METHOD(tls_reader_t, remaining, u_int32_t,
-       private_tls_reader_t *this)
-{
-       return this->buf.len;
-}
-
-METHOD(tls_reader_t, peek, chunk_t,
-       private_tls_reader_t *this)
-{
-       return this->buf;
-}
-
-METHOD(tls_reader_t, read_uint8, bool,
-       private_tls_reader_t *this, u_int8_t *res)
-{
-       if (this->buf.len < 1)
-       {
-               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
-                        this->buf.len, 8);
-               return FALSE;
-       }
-       *res = this->buf.ptr[0];
-       this->buf = chunk_skip(this->buf, 1);
-       return TRUE;
-}
-
-METHOD(tls_reader_t, read_uint16, bool,
-       private_tls_reader_t *this, u_int16_t *res)
-{
-       if (this->buf.len < 2)
-       {
-               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
-                        this->buf.len, 16);
-               return FALSE;
-       }
-       *res = untoh16(this->buf.ptr);
-       this->buf = chunk_skip(this->buf, 2);
-       return TRUE;
-}
-
-METHOD(tls_reader_t, read_uint24, bool,
-       private_tls_reader_t *this, u_int32_t *res)
-{
-       if (this->buf.len < 3)
-       {
-               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
-                        this->buf.len, 24);
-               return FALSE;
-       }
-       *res = untoh32(this->buf.ptr) >> 8;
-       this->buf = chunk_skip(this->buf, 3);
-       return TRUE;
-}
-
-METHOD(tls_reader_t, read_uint32, bool,
-       private_tls_reader_t *this, u_int32_t *res)
-{
-       if (this->buf.len < 4)
-       {
-               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
-                        this->buf.len, 32);
-               return FALSE;
-       }
-       *res = untoh32(this->buf.ptr);
-       this->buf = chunk_skip(this->buf, 4);
-       return TRUE;
-}
-
-METHOD(tls_reader_t, read_data, bool,
-       private_tls_reader_t *this, u_int32_t len, chunk_t *res)
-{
-       if (this->buf.len < len)
-       {
-               DBG1(DBG_IKE, "%d bytes insufficient to parse %d bytes TLS data",
-                        this->buf.len, len);
-               return FALSE;
-       }
-       *res = chunk_create(this->buf.ptr, len);
-       this->buf = chunk_skip(this->buf, len);
-       return TRUE;
-}
-
-METHOD(tls_reader_t, read_data8, bool,
-       private_tls_reader_t *this, chunk_t *res)
-{
-       u_int8_t len;
-
-       if (!read_uint8(this, &len))
-       {
-               return FALSE;
-       }
-       return read_data(this, len, res);
-}
-
-METHOD(tls_reader_t, read_data16, bool,
-       private_tls_reader_t *this, chunk_t *res)
-{
-       u_int16_t len;
-
-       if (!read_uint16(this, &len))
-       {
-               return FALSE;
-       }
-       return read_data(this, len, res);
-}
-
-METHOD(tls_reader_t, read_data24, bool,
-       private_tls_reader_t *this, chunk_t *res)
-{
-       u_int32_t len;
-
-       if (!read_uint24(this, &len))
-       {
-               return FALSE;
-       }
-       return read_data(this, len, res);
-}
-
-METHOD(tls_reader_t, read_data32, bool,
-       private_tls_reader_t *this, chunk_t *res)
-{
-       u_int32_t len;
-
-       if (!read_uint32(this, &len))
-       {
-               return FALSE;
-       }
-       return read_data(this, len, res);
-}
-
-METHOD(tls_reader_t, destroy, void,
-       private_tls_reader_t *this)
-{
-       free(this);
-}
-
-/**
- * See header
- */
-tls_reader_t *tls_reader_create(chunk_t data)
-{
-       private_tls_reader_t *this;
-
-       INIT(this,
-               .public = {
-                       .remaining = _remaining,
-                       .peek = _peek,
-                       .read_uint8 = _read_uint8,
-                       .read_uint16 = _read_uint16,
-                       .read_uint24 = _read_uint24,
-                       .read_uint32 = _read_uint32,
-                       .read_data = _read_data,
-                       .read_data8 = _read_data8,
-                       .read_data16 = _read_data16,
-                       .read_data24 = _read_data24,
-                       .read_data32 = _read_data32,
-                       .destroy = _destroy,
-               },
-               .buf = data,
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_reader.h b/src/libcharon/plugins/eap_tls/tls/tls_reader.h
deleted file mode 100644 (file)
index a8917df..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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_reader tls_reader
- * @{ @ingroup tls
- */
-
-#ifndef TLS_READER_H_
-#define TLS_READER_H_
-
-typedef struct tls_reader_t tls_reader_t;
-
-#include <library.h>
-
-/**
- * TLS record parser.
- */
-struct tls_reader_t {
-
-       /**
-        * Get the number of remaining bytes.
-        *
-        * @return                      number of remaining bytes in buffer
-        */
-       u_int32_t (*remaining)(tls_reader_t *this);
-
-       /**
-        * Peek the remaining data, not consuming any bytes.
-        *
-        * @return                      remaining data
-        */
-       chunk_t (*peek)(tls_reader_t *this);
-
-       /**
-        * Read a 8-bit integer from the buffer, advance.
-        *
-        * @param res           pointer to result
-        * @return                      TRUE if integer read successfully
-        */
-       bool (*read_uint8)(tls_reader_t *this, u_int8_t *res);
-
-       /**
-        * Read a 16-bit integer from the buffer, advance.
-        *
-        * @param res           pointer to result
-        * @return                      TRUE if integer read successfully
-        */
-       bool (*read_uint16)(tls_reader_t *this, u_int16_t *res);
-
-       /**
-        * Read a 24-bit integer from the buffer, advance.
-        *
-        * @param res           pointer to result
-        * @return                      TRUE if integer read successfully
-        */
-       bool (*read_uint24)(tls_reader_t *this, u_int32_t *res);
-
-       /**
-        * Read a 32-bit integer from the buffer, advance.
-        *
-        * @param res           pointer to result
-        * @return                      TRUE if integer read successfully
-        */
-       bool (*read_uint32)(tls_reader_t *this, u_int32_t *res);
-
-       /**
-        * Read a chunk of len bytes, advance.
-        *
-        * @param len           number of bytes to read
-        * @param res           pointer to result, not cloned
-        * @return                      TRUE if data read successfully
-        */
-       bool (*read_data)(tls_reader_t *this, u_int32_t len, chunk_t *res);
-
-       /**
-        * Read a chunk of bytes with a 8-bit length header, advance.
-        *
-        * @param res           pointer to result, not cloned
-        * @return                      TRUE if data read successfully
-        */
-       bool (*read_data8)(tls_reader_t *this, chunk_t *res);
-
-       /**
-        * Read a chunk of bytes with a 16-bit length header, advance.
-        *
-        * @param res           pointer to result, not cloned
-        * @return                      TRUE if data read successfully
-        */
-       bool (*read_data16)(tls_reader_t *this, chunk_t *res);
-
-       /**
-        * Read a chunk of bytes with a 24-bit length header, advance.
-        *
-        * @param res           pointer to result, not cloned
-        * @return                      TRUE if data read successfully
-        */
-       bool (*read_data24)(tls_reader_t *this, chunk_t *res);
-
-       /**
-        * Read a chunk of bytes with a 32-bit length header, advance.
-        *
-        * @param res           pointer to result, not cloned
-        * @return                      TRUE if data read successfully
-        */
-       bool (*read_data32)(tls_reader_t *this, chunk_t *res);
-
-       /**
-        * Destroy a tls_reader_t.
-        */
-       void (*destroy)(tls_reader_t *this);
-};
-
-/**
- * Create a tls_reader instance.
- */
-tls_reader_t *tls_reader_create(chunk_t data);
-
-#endif /** tls_reader_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_server.c b/src/libcharon/plugins/eap_tls/tls/tls_server.c
deleted file mode 100644 (file)
index 60c6268..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * 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 <time.h>
-
-#include <daemon.h>
-
-typedef struct private_tls_server_t private_tls_server_t;
-
-
-typedef enum {
-       STATE_INIT,
-       STATE_HELLO_RECEIVED,
-       STATE_HELLO_SENT,
-       STATE_CERT_SENT,
-       STATE_CERTREQ_SENT,
-       STATE_HELLO_DONE,
-       STATE_CERT_RECEIVED,
-       STATE_KEY_EXCHANGE_RECEIVED,
-       STATE_CERT_VERIFY_RECEIVED,
-       STATE_CIPHERSPEC_CHANGED_IN,
-       STATE_FINISHED_RECEIVED,
-       STATE_CIPHERSPEC_CHANGED_OUT,
-       STATE_FINISHED_SENT,
-} server_state_t;
-
-/**
- * Private data of an tls_server_t object.
- */
-struct private_tls_server_t {
-
-       /**
-        * Public tls_server_t interface.
-        */
-       tls_server_t public;
-
-       /**
-        * TLS stack
-        */
-       tls_t *tls;
-
-       /**
-        * TLS crypto context
-        */
-       tls_crypto_t *crypto;
-
-       /**
-        * Server identity
-        */
-       identification_t *server;
-
-       /**
-        * Peer identity
-        */
-       identification_t *peer;
-
-       /**
-        * State we are in
-        */
-       server_state_t state;
-
-       /**
-        * Hello random data selected by client
-        */
-       char client_random[32];
-
-       /**
-        * Hello random data selected by server
-        */
-       char server_random[32];
-
-       /**
-        * Auth helper for peer authentication
-        */
-       auth_cfg_t *peer_auth;
-
-       /**
-        * Auth helper for server authentication
-        */
-       auth_cfg_t *server_auth;
-
-       /**
-        * Peer private key
-        */
-       private_key_t *private;
-
-       /**
-        * Selected TLS cipher suite
-        */
-       tls_cipher_suite_t suite;
-};
-
-/**
- * Process client hello message
- */
-static status_t process_client_hello(private_tls_server_t *this,
-                                                                        tls_reader_t *reader)
-{
-       u_int16_t version;
-       chunk_t random, session, ciphers, compression, ext = chunk_empty;
-       tls_cipher_suite_t *suites;
-       int count, i;
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_CLIENT_HELLO, reader->peek(reader));
-
-       if (!reader->read_uint16(reader, &version) ||
-               !reader->read_data(reader, sizeof(this->client_random), &random) ||
-               !reader->read_data8(reader, &session) ||
-               !reader->read_data16(reader, &ciphers) ||
-               !reader->read_data8(reader, &compression) ||
-               (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
-       {
-               DBG1(DBG_IKE, "received invalid ClientHello");
-               return FAILED;
-       }
-
-       memcpy(this->client_random, random.ptr, sizeof(this->client_random));
-
-       if (version < this->tls->get_version(this->tls))
-       {
-               this->tls->set_version(this->tls, version);
-       }
-       count = ciphers.len / sizeof(u_int16_t);
-       suites = alloca(count * sizeof(tls_cipher_suite_t));
-       for (i = 0; i < count; i++)
-       {
-               suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
-       }
-       this->suite = this->crypto->select_cipher_suite(this->crypto, suites, count);
-       if (!this->suite)
-       {
-               DBG1(DBG_IKE, "received cipher suite inacceptable");
-               return FAILED;
-       }
-       this->state = STATE_HELLO_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process certificate
- */
-static status_t process_certificate(private_tls_server_t *this,
-                                                                       tls_reader_t *reader)
-{
-       certificate_t *cert;
-       tls_reader_t *certs;
-       chunk_t data;
-       bool first = TRUE;
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_CERTIFICATE, reader->peek(reader));
-
-       if (!reader->read_data24(reader, &data))
-       {
-               return FAILED;
-       }
-       certs = tls_reader_create(data);
-       while (certs->remaining(certs))
-       {
-               if (!certs->read_data24(certs, &data))
-               {
-                       certs->destroy(certs);
-                       return FAILED;
-               }
-               cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
-                                                                 BUILD_BLOB_ASN1_DER, data, BUILD_END);
-               if (cert)
-               {
-                       if (first)
-                       {
-                               this->peer_auth->add(this->peer_auth,
-                                                                        AUTH_HELPER_SUBJECT_CERT, cert);
-                               DBG1(DBG_IKE, "received TLS peer certificate '%Y'",
-                                        cert->get_subject(cert));
-                               first = FALSE;
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
-                                        cert->get_subject(cert));
-                               this->peer_auth->add(this->peer_auth, AUTH_HELPER_IM_CERT, cert);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
-               }
-       }
-       certs->destroy(certs);
-       this->state = STATE_CERT_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process Client Key Exchange
- */
-static status_t process_key_exchange(private_tls_server_t *this,
-                                                                        tls_reader_t *reader)
-{
-       chunk_t encrypted, premaster;
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_CLIENT_KEY_EXCHANGE, reader->peek(reader));
-
-       if (!reader->read_data16(reader, &encrypted))
-       {
-               DBG1(DBG_IKE, "received invalid Client Key Exchange");
-               return FAILED;
-       }
-
-       if (!this->private ||
-               !this->private->decrypt(this->private, encrypted, &premaster))
-       {
-               DBG1(DBG_IKE, "decrypting Client Key Exchange data failed");
-               return FAILED;
-       }
-       this->crypto->derive_secrets(this->crypto, premaster,
-                                                                chunk_from_thing(this->client_random),
-                                                                chunk_from_thing(this->server_random));
-       chunk_clear(&premaster);
-
-       this->state = STATE_KEY_EXCHANGE_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process Certificate verify
- */
-static status_t process_cert_verify(private_tls_server_t *this,
-                                                                       tls_reader_t *reader)
-{
-       bool verified = FALSE;
-       enumerator_t *enumerator;
-       public_key_t *public;
-       auth_cfg_t *auth;
-       tls_reader_t *sig;
-
-       enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
-                                                                               KEY_ANY, this->peer, this->peer_auth);
-       while (enumerator->enumerate(enumerator, &public, &auth))
-       {
-               sig = tls_reader_create(reader->peek(reader));
-               verified = this->crypto->verify_handshake(this->crypto, public, sig);
-               sig->destroy(sig);
-               if (verified)
-               {
-                       break;
-               }
-               DBG1(DBG_IKE, "signature verification failed, trying another key");
-       }
-       enumerator->destroy(enumerator);
-
-       if (!verified)
-       {
-               DBG1(DBG_IKE, "no trusted certificate found for '%Y' to verify TLS peer",
-                        this->peer);
-               return FAILED;
-       }
-
-       this->crypto->append_handshake(this->crypto,
-                                                                  TLS_CERTIFICATE_VERIFY, reader->peek(reader));
-       this->state = STATE_CERT_VERIFY_RECEIVED;
-       return NEED_MORE;
-}
-
-/**
- * Process finished message
- */
-static status_t process_finished(private_tls_server_t *this,
-                                                                tls_reader_t *reader)
-{
-       chunk_t received;
-       char buf[12];
-
-       if (!reader->read_data(reader, sizeof(buf), &received))
-       {
-               DBG1(DBG_IKE, "received client finished too short");
-               return FAILED;
-       }
-       if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
-       {
-               DBG1(DBG_IKE, "calculating client finished failed");
-               return FAILED;
-       }
-       if (!chunk_equals(received, chunk_from_thing(buf)))
-       {
-               DBG1(DBG_IKE, "received client finished invalid");
-               return FAILED;
-       }
-
-       this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
-       this->state = STATE_FINISHED_RECEIVED;
-       return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, process, status_t,
-       private_tls_server_t *this, tls_handshake_type_t type, tls_reader_t *reader)
-{
-       tls_handshake_type_t expected;
-
-       switch (this->state)
-       {
-               case STATE_INIT:
-                       if (type == TLS_CLIENT_HELLO)
-                       {
-                               return process_client_hello(this, reader);
-                       }
-                       expected = TLS_CLIENT_HELLO;
-                       break;
-               case STATE_HELLO_DONE:
-                       if (type == TLS_CERTIFICATE)
-                       {
-                               return process_certificate(this, reader);
-                       }
-                       expected = TLS_CERTIFICATE;
-                       break;
-               case STATE_CERT_RECEIVED:
-                       if (type == TLS_CLIENT_KEY_EXCHANGE)
-                       {
-                               return process_key_exchange(this, reader);
-                       }
-                       expected = TLS_CLIENT_KEY_EXCHANGE;
-                       break;
-               case STATE_KEY_EXCHANGE_RECEIVED:
-                       if (type == TLS_CERTIFICATE_VERIFY)
-                       {
-                               return process_cert_verify(this, reader);
-                       }
-                       expected = TLS_CERTIFICATE_VERIFY;
-                       break;
-               case STATE_CIPHERSPEC_CHANGED_IN:
-                       if (type == TLS_FINISHED)
-                       {
-                               return process_finished(this, reader);
-                       }
-                       expected = TLS_FINISHED;
-                       break;
-               default:
-                       DBG1(DBG_IKE, "TLS %N not expected in current state",
-                                tls_handshake_type_names, type);
-                       return FAILED;
-       }
-       DBG1(DBG_IKE, "TLS %N expected, but received %N",
-                tls_handshake_type_names, expected, tls_handshake_type_names, type);
-       return FAILED;
-}
-
-/**
- * Send ServerHello message
- */
-static status_t send_server_hello(private_tls_server_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       rng_t *rng;
-
-       htoun32(&this->server_random, time(NULL));
-       rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-       if (!rng)
-       {
-               return FAILED;
-       }
-       rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
-       rng->destroy(rng);
-
-       writer->write_uint16(writer, this->tls->get_version(this->tls));
-       writer->write_data(writer, chunk_from_thing(this->server_random));
-       /* session identifier => none, we don't support session resumption */
-       writer->write_data8(writer, chunk_empty);
-       /* add selected suite */
-       writer->write_uint16(writer, this->suite);
-       /* NULL compression only */
-       writer->write_uint8(writer, 0);
-
-       *type = TLS_SERVER_HELLO;
-       this->state = STATE_HELLO_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Certificate
- */
-static status_t send_certificate(private_tls_server_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       enumerator_t *enumerator;
-       certificate_t *cert;
-       auth_rule_t rule;
-       tls_writer_t *certs;
-       chunk_t data;
-
-       this->private = lib->credmgr->get_private(lib->credmgr,
-                                                                       KEY_ANY, this->server, this->server_auth);
-       if (!this->private)
-       {
-               DBG1(DBG_IKE, "no TLS server certificate found for '%Y'", this->server);
-               return FAILED;
-       }
-
-       /* generate certificate payload */
-       certs = tls_writer_create(256);
-       cert = this->server_auth->get(this->server_auth, AUTH_RULE_SUBJECT_CERT);
-       if (cert)
-       {
-               if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
-               {
-                       DBG1(DBG_IKE, "sending TLS server certificate '%Y'",
-                                cert->get_subject(cert));
-                       certs->write_data24(certs, data);
-                       free(data.ptr);
-               }
-       }
-       enumerator = this->server_auth->create_enumerator(this->server_auth);
-       while (enumerator->enumerate(enumerator, &rule, &cert))
-       {
-               if (rule == AUTH_RULE_IM_CERT)
-               {
-                       if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
-                       {
-                               DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
-                                        cert->get_subject(cert));
-                               certs->write_data24(certs, data);
-                               free(data.ptr);
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       writer->write_data24(writer, certs->get_buf(certs));
-       certs->destroy(certs);
-
-       *type = TLS_CERTIFICATE;
-       this->state = STATE_CERT_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Certificate Request
- */
-static status_t send_certificate_request(private_tls_server_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       tls_writer_t *authorities;
-       enumerator_t *enumerator;
-       certificate_t *cert;
-       identification_t *id;
-
-       /* currently only RSA signatures are supported */
-       writer->write_data8(writer, chunk_from_chars(1));
-       if (this->tls->get_version(this->tls) >= TLS_1_2)
-       {
-               /* enforce RSA with SHA1 signatures */
-               writer->write_data16(writer, chunk_from_chars(2, 1));
-       }
-
-       authorities = tls_writer_create(64);
-       enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
-                                                                                               CERT_X509, KEY_RSA, NULL, TRUE);
-       while (enumerator->enumerate(enumerator, &cert))
-       {
-               id = cert->get_subject(cert);
-               authorities->write_data16(authorities, id->get_encoding(id));
-       }
-       enumerator->destroy(enumerator);
-       writer->write_data16(writer, authorities->get_buf(authorities));
-       authorities->destroy(authorities);
-
-       *type = TLS_CERTIFICATE_REQUEST;
-       this->state = STATE_CERTREQ_SENT;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Hello Done
- */
-static status_t send_hello_done(private_tls_server_t *this,
-                                                       tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       *type = TLS_SERVER_HELLO_DONE;
-       this->state = STATE_HELLO_DONE;
-       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
-       return NEED_MORE;
-}
-
-/**
- * Send Finished
- */
-static status_t send_finished(private_tls_server_t *this,
-                                                         tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       char buf[12];
-
-       if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
-       {
-               DBG1(DBG_IKE, "calculating server finished data failed");
-               return FAILED;
-       }
-
-       writer->write_data(writer, chunk_from_thing(buf));
-
-       *type = TLS_FINISHED;
-       this->state = STATE_FINISHED_SENT;
-       this->crypto->derive_eap_msk(this->crypto,
-                                                                chunk_from_thing(this->client_random),
-                                                                chunk_from_thing(this->server_random));
-       return NEED_MORE;
-}
-
-METHOD(tls_handshake_t, build, status_t,
-       private_tls_server_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
-{
-       switch (this->state)
-       {
-               case STATE_HELLO_RECEIVED:
-                       return send_server_hello(this, type, writer);
-               case STATE_HELLO_SENT:
-                       return send_certificate(this, type, writer);
-               case STATE_CERT_SENT:
-                       return send_certificate_request(this, type, writer);
-               case STATE_CERTREQ_SENT:
-                       return send_hello_done(this, type, writer);
-               case STATE_CIPHERSPEC_CHANGED_OUT:
-                       return send_finished(this, type, writer);
-               case STATE_FINISHED_SENT:
-                       return INVALID_STATE;
-               default:
-                       return INVALID_STATE;
-       }
-}
-
-METHOD(tls_handshake_t, cipherspec_changed, bool,
-       private_tls_server_t *this)
-{
-       if (this->state == STATE_FINISHED_RECEIVED)
-       {
-               this->crypto->change_cipher(this->crypto, FALSE);
-               this->state = STATE_CIPHERSPEC_CHANGED_OUT;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(tls_handshake_t, change_cipherspec, bool,
-       private_tls_server_t *this)
-{
-       if (this->state == STATE_CERT_VERIFY_RECEIVED)
-       {
-               this->crypto->change_cipher(this->crypto, TRUE);
-               this->state = STATE_CIPHERSPEC_CHANGED_IN;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-METHOD(tls_handshake_t, destroy, void,
-       private_tls_server_t *this)
-{
-       DESTROY_IF(this->private);
-       this->peer_auth->destroy(this->peer_auth);
-       this->server_auth->destroy(this->server_auth);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto,
-                                                       identification_t *server, identification_t *peer)
-{
-       private_tls_server_t *this;
-
-       INIT(this,
-               .public.handshake = {
-                       .process = _process,
-                       .build = _build,
-                       .cipherspec_changed = _cipherspec_changed,
-                       .change_cipherspec = _change_cipherspec,
-                       .destroy = _destroy,
-               },
-               .tls = tls,
-               .crypto = crypto,
-               .server = server,
-               .peer = peer,
-               .state = STATE_INIT,
-               .peer_auth = auth_cfg_create(),
-               .server_auth = auth_cfg_create(),
-       );
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_server.h b/src/libcharon/plugins/eap_tls/tls/tls_server.h
deleted file mode 100644 (file)
index 3fddea2..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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"
-#include "tls_crypto.h"
-
-#include <library.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(tls_t *tls, tls_crypto_t *crypto,
-                                                       identification_t *server, identification_t *peer);
-
-#endif /** TLS_SERVER_H_ @}*/
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_writer.c b/src/libcharon/plugins/eap_tls/tls/tls_writer.c
deleted file mode 100644 (file)
index f1d9d79..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.
- */
-
-#include "tls_writer.h"
-
-typedef struct private_tls_writer_t private_tls_writer_t;
-
-/**
- * Private data of an tls_writer_t object.
- */
-struct private_tls_writer_t {
-
-       /**
-        * Public tls_writer_t interface.
-        */
-       tls_writer_t public;
-
-       /**
-        * Allocated buffer
-        */
-       chunk_t buf;
-
-       /**
-        * Used bytes in buffer
-        */
-       size_t used;
-
-       /**
-        * Number of bytes to increase buffer size
-        */
-       size_t increase;
-};
-
-/**
- * Increase buffer size
- */
-static void increase(private_tls_writer_t *this)
-{
-       this->buf.len += this->increase;
-       this->buf.ptr = realloc(this->buf.ptr, this->buf.len);
-}
-
-METHOD(tls_writer_t, write_uint8, void,
-       private_tls_writer_t *this, u_int8_t value)
-{
-       if (this->used + 1 > this->buf.len)
-       {
-               increase(this);
-       }
-       this->buf.ptr[this->used] = value;
-       this->used += 1;
-}
-
-METHOD(tls_writer_t, write_uint16, void,
-       private_tls_writer_t *this, u_int16_t value)
-{
-       if (this->used + 2 > this->buf.len)
-       {
-               increase(this);
-       }
-       htoun16(this->buf.ptr + this->used, value);
-       this->used += 2;
-}
-
-METHOD(tls_writer_t, write_uint24, void,
-       private_tls_writer_t *this, u_int32_t value)
-{
-       if (this->used + 3 > this->buf.len)
-       {
-               increase(this);
-       }
-       value = htonl(value);
-       memcpy(this->buf.ptr + this->used, ((char*)&value) + 1, 3);
-       this->used += 3;
-}
-
-METHOD(tls_writer_t, write_uint32, void,
-       private_tls_writer_t *this, u_int32_t value)
-{
-       if (this->used + 4 > this->buf.len)
-       {
-               increase(this);
-       }
-       htoun32(this->buf.ptr + this->used, value);
-       this->used += 4;
-}
-
-METHOD(tls_writer_t, write_data, void,
-       private_tls_writer_t *this, chunk_t value)
-{
-       while (this->used + value.len > this->buf.len)
-       {
-               increase(this);
-       }
-       memcpy(this->buf.ptr + this->used, value.ptr, value.len);
-       this->used += value.len;
-}
-
-METHOD(tls_writer_t, write_data8, void,
-       private_tls_writer_t *this, chunk_t value)
-{
-       write_uint8(this, value.len);
-       write_data(this, value);
-}
-
-METHOD(tls_writer_t, write_data16, void,
-       private_tls_writer_t *this, chunk_t value)
-{
-       write_uint16(this, value.len);
-       write_data(this, value);
-}
-
-METHOD(tls_writer_t, write_data24, void,
-       private_tls_writer_t *this, chunk_t value)
-{
-       write_uint24(this, value.len);
-       write_data(this, value);
-}
-
-METHOD(tls_writer_t, write_data32, void,
-       private_tls_writer_t *this, chunk_t value)
-{
-       write_uint32(this, value.len);
-       write_data(this, value);
-}
-
-METHOD(tls_writer_t, wrap8, void,
-       private_tls_writer_t *this)
-{
-       if (this->used + 1 > this->buf.len)
-       {
-               increase(this);
-       }
-       memmove(this->buf.ptr + 1, this->buf.ptr, 1);
-       this->buf.ptr[0] = this->used;
-       this->used += 1;
-}
-
-METHOD(tls_writer_t, wrap16, void,
-       private_tls_writer_t *this)
-{
-       if (this->used + 2 > this->buf.len)
-       {
-               increase(this);
-       }
-       memmove(this->buf.ptr + 2, this->buf.ptr, 2);
-       htoun16(this->buf.ptr, this->used);
-       this->used += 2;
-}
-
-METHOD(tls_writer_t, wrap24, void,
-       private_tls_writer_t *this)
-{
-       u_int32_t len;
-
-       if (this->used + 3 > this->buf.len)
-       {
-               increase(this);
-       }
-       memmove(this->buf.ptr + 3, this->buf.ptr, 3);
-
-       len = htonl(this->used);
-       memcpy(this->buf.ptr, ((char*)&len) + 1, 3);
-       this->used += 3;
-}
-
-METHOD(tls_writer_t, wrap32, void,
-       private_tls_writer_t *this)
-{
-       if (this->used + 4 > this->buf.len)
-       {
-               increase(this);
-       }
-       memmove(this->buf.ptr + 4, this->buf.ptr, 4);
-       htoun32(this->buf.ptr, this->used);
-       this->used += 4;
-}
-
-METHOD(tls_writer_t, get_buf, chunk_t,
-       private_tls_writer_t *this)
-{
-       return chunk_create(this->buf.ptr, this->used);
-}
-
-METHOD(tls_writer_t, destroy, void,
-       private_tls_writer_t *this)
-{
-       free(this->buf.ptr);
-       free(this);
-}
-
-/**
- * See header
- */
-tls_writer_t *tls_writer_create(u_int32_t bufsize)
-{
-       private_tls_writer_t *this;
-
-       INIT(this,
-               .public = {
-                       .write_uint8 = _write_uint8,
-                       .write_uint16 = _write_uint16,
-                       .write_uint24 = _write_uint24,
-                       .write_uint32 = _write_uint32,
-                       .write_data = _write_data,
-                       .write_data8 = _write_data8,
-                       .write_data16 = _write_data16,
-                       .write_data24 = _write_data24,
-                       .write_data32 = _write_data32,
-                       .wrap8 = _wrap8,
-                       .wrap16 = _wrap16,
-                       .wrap24 = _wrap24,
-                       .wrap32 = _wrap32,
-                       .get_buf = _get_buf,
-                       .destroy = _destroy,
-               },
-               .increase = bufsize ?: 32,
-       );
-       if (bufsize)
-       {
-               this->buf = chunk_alloc(bufsize);
-       }
-
-       return &this->public;
-}
diff --git a/src/libcharon/plugins/eap_tls/tls/tls_writer.h b/src/libcharon/plugins/eap_tls/tls/tls_writer.h
deleted file mode 100644 (file)
index ce8ba6a..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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_writer tls_writer
- * @{ @ingroup tls
- */
-
-#ifndef TLS_WRITER_H_
-#define TLS_WRITER_H_
-
-typedef struct tls_writer_t tls_writer_t;
-
-#include <library.h>
-
-/**
- * TLS record generator.
- */
-struct tls_writer_t {
-
-       /**
-        * Append a 8-bit integer to the buffer.
-        *
-        * @param value         value to append
-        */
-       void (*write_uint8)(tls_writer_t *this, u_int8_t value);
-
-       /**
-        * Append a 16-bit integer to the buffer.
-        *
-        * @param value         value to append
-        */
-       void (*write_uint16)(tls_writer_t *this, u_int16_t value);
-
-       /**
-        * Append a 24-bit integer to the buffer.
-        *
-        * @param value         value to append
-        */
-       void (*write_uint24)(tls_writer_t *this, u_int32_t value);
-
-       /**
-        * Append a 32-bit integer to the buffer.
-        *
-        * @param value         value to append
-        */
-       void (*write_uint32)(tls_writer_t *this, u_int32_t value);
-
-       /**
-        * Append a chunk of data without a length header.
-        *
-        * @param value         value to append
-        */
-       void (*write_data)(tls_writer_t *this, chunk_t value);
-
-       /**
-        * Append a chunk of data with a 16-bit length header.
-        *
-        * @param value         value to append
-        */
-       void (*write_data8)(tls_writer_t *this, chunk_t value);
-
-       /**
-        * Append a chunk of data with a 8-bit length header.
-        *
-        * @param value         value to append
-        */
-       void (*write_data16)(tls_writer_t *this, chunk_t value);
-
-       /**
-        * Append a chunk of data with a 24-bit length header.
-        *
-        * @param value         value to append
-        */
-       void (*write_data24)(tls_writer_t *this, chunk_t value);
-
-       /**
-        * Append a chunk of data with a 32-bit length header.
-        *
-        * @param value         value to append
-        */
-       void (*write_data32)(tls_writer_t *this, chunk_t value);
-
-       /**
-        * Prepend a 8-bit length header to existing data.
-        */
-       void (*wrap8)(tls_writer_t *this);
-
-       /**
-        * Prepend a 16-bit length header to existing data.
-        */
-       void (*wrap16)(tls_writer_t *this);
-
-       /**
-        * Prepend a 24-bit length header to existing data.
-        */
-       void (*wrap24)(tls_writer_t *this);
-
-       /**
-        * Prepend a 32-bit length header to existing data.
-        */
-       void (*wrap32)(tls_writer_t *this);
-
-       /**
-        * Get the encoded data buffer.
-        *
-        * @return                      chunk to internal buffer
-        */
-       chunk_t (*get_buf)(tls_writer_t *this);
-
-       /**
-        * Destroy a tls_writer_t.
-        */
-       void (*destroy)(tls_writer_t *this);
-};
-
-/**
- * Create a tls_writer instance.
- *
- * @param bufsize              initially allocated buffer size
- */
-tls_writer_t *tls_writer_create(u_int32_t bufsize);
-
-#endif /** TLS_WRITER_H_ @}*/
diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am
new file mode 100644 (file)
index 0000000..d61cd84
--- /dev/null
@@ -0,0 +1,15 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+noinst_LTLIBRARIES = libtls.la
+libtls_la_SOURCES = \
+       tls_protection.h tls_protection.c \
+       tls_compression.h tls_compression.c \
+       tls_fragmentation.h tls_fragmentation.c \
+       tls_crypto.h tls_crypto.c \
+       tls_prf.h tls_prf.c \
+       tls_reader.h tls_reader.c \
+       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
diff --git a/src/libtls/tls.c b/src/libtls/tls.c
new file mode 100644 (file)
index 0000000..4384c07
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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.h"
+
+#include "tls_protection.h"
+#include "tls_compression.h"
+#include "tls_fragmentation.h"
+#include "tls_crypto.h"
+#include "tls_server.h"
+#include "tls_peer.h"
+
+ENUM_BEGIN(tls_version_names, SSL_2_0, SSL_2_0,
+       "SSLv2");
+ENUM_NEXT(tls_version_names, SSL_3_0, TLS_1_2, SSL_2_0,
+       "SSLv3",
+       "TLS 1.0",
+       "TLS 1.1",
+       "TLS 1.2");
+ENUM_END(tls_version_names, TLS_1_2);
+
+ENUM(tls_content_type_names, TLS_CHANGE_CIPHER_SPEC, TLS_APPLICATION_DATA,
+       "ChangeCipherSpec",
+       "Alert",
+       "Handshake",
+       "ApplicationData",
+);
+
+ENUM_BEGIN(tls_handshake_type_names, TLS_HELLO_REQUEST, TLS_SERVER_HELLO,
+       "HelloRequest",
+       "ClientHello",
+       "ServerHello");
+ENUM_NEXT(tls_handshake_type_names, TLS_CERTIFICATE, TLS_CLIENT_KEY_EXCHANGE, TLS_SERVER_HELLO,
+       "Certificate",
+       "ServerKeyExchange",
+       "CertificateRequest",
+       "ServerHelloDone",
+       "CertificateVerify",
+       "ClientKeyExchange");
+ENUM_NEXT(tls_handshake_type_names, TLS_FINISHED, TLS_FINISHED, TLS_CLIENT_KEY_EXCHANGE,
+       "Finished");
+ENUM_END(tls_handshake_type_names, TLS_FINISHED);
+
+
+typedef struct private_tls_t private_tls_t;
+
+/**
+ * Private data of an tls_protection_t object.
+ */
+struct private_tls_t {
+
+       /**
+        * Public tls_t interface.
+        */
+       tls_t public;
+
+       /**
+        * Role this TLS stack acts as.
+        */
+       bool is_server;
+
+       /**
+        * Server identity
+        */
+       identification_t *server;
+
+       /**
+        * Peer identity
+        */
+       identification_t *peer;
+
+       /**
+        * Negotiated TLS version
+        */
+       tls_version_t version;
+
+       /**
+        * TLS record protection layer
+        */
+       tls_protection_t *protection;
+
+       /**
+        * TLS record compression layer
+        */
+       tls_compression_t *compression;
+
+       /**
+        * TLS record fragmentation layer
+        */
+       tls_fragmentation_t *fragmentation;
+
+       /**
+        * TLS crypto helper context
+        */
+       tls_crypto_t *crypto;
+
+       /**
+        * TLS handshake protocol handler
+        */
+       tls_handshake_t *handshake;
+};
+
+METHOD(tls_t, process, status_t,
+       private_tls_t *this, tls_content_type_t type, chunk_t data)
+{
+       return this->protection->process(this->protection, type, data);
+}
+
+METHOD(tls_t, build, status_t,
+       private_tls_t *this, tls_content_type_t *type, chunk_t *data)
+{
+       return this->protection->build(this->protection, type, data);
+}
+
+METHOD(tls_t, is_server, bool,
+       private_tls_t *this)
+{
+       return this->is_server;
+}
+
+METHOD(tls_t, get_version, tls_version_t,
+       private_tls_t *this)
+{
+       return this->version;
+}
+
+METHOD(tls_t, set_version, void,
+       private_tls_t *this, tls_version_t version)
+{
+       this->version = version;
+}
+
+METHOD(tls_t, is_complete, bool,
+       private_tls_t *this)
+{
+       return this->crypto->get_eap_msk(this->crypto).len != 0;
+}
+
+METHOD(tls_t, get_eap_msk, chunk_t,
+       private_tls_t *this)
+{
+       return this->crypto->get_eap_msk(this->crypto);
+}
+
+METHOD(tls_t, destroy, void,
+       private_tls_t *this)
+{
+       this->protection->destroy(this->protection);
+       this->compression->destroy(this->compression);
+       this->fragmentation->destroy(this->fragmentation);
+       this->crypto->destroy(this->crypto);
+       this->handshake->destroy(this->handshake);
+       this->peer->destroy(this->peer);
+       this->server->destroy(this->server);
+
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_t *tls_create(bool is_server, identification_t *server,
+                                 identification_t *peer)
+{
+       private_tls_t *this;
+
+       INIT(this,
+               .public = {
+                       .process = _process,
+                       .build = _build,
+                       .is_server = _is_server,
+                       .get_version = _get_version,
+                       .set_version = _set_version,
+                       .is_complete = _is_complete,
+                       .get_eap_msk = _get_eap_msk,
+                       .destroy = _destroy,
+               },
+               .is_server = is_server,
+               .version = TLS_1_2,
+               .server = server->clone(server),
+               .peer = peer->clone(peer),
+       );
+
+       this->crypto = tls_crypto_create(&this->public);
+       if (is_server)
+       {
+               this->handshake = &tls_server_create(&this->public, this->crypto,
+                                                                               this->server, this->peer)->handshake;
+       }
+       else
+       {
+               this->handshake = &tls_peer_create(&this->public, this->crypto,
+                                                                               this->peer, this->server)->handshake;
+       }
+       this->fragmentation = tls_fragmentation_create(this->handshake);
+       this->compression = tls_compression_create(this->fragmentation);
+       this->protection = tls_protection_create(&this->public, this->compression);
+       this->crypto->set_protection(this->crypto, this->protection);
+
+       return &this->public;
+}
diff --git a/src/libtls/tls.h b/src/libtls/tls.h
new file mode 100644 (file)
index 0000000..67ee742
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 libtls libtls
+ *
+ * @addtogroup libtls
+ * TLS implementation on top of libstrongswan
+ *
+ * @defgroup tls tls
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_H_
+#define TLS_H_
+
+typedef enum tls_version_t tls_version_t;
+typedef enum tls_content_type_t tls_content_type_t;
+typedef enum tls_handshake_type_t tls_handshake_type_t;
+typedef struct tls_t tls_t;
+
+#include <library.h>
+
+/**
+ * TLS/SSL version numbers
+ */
+enum tls_version_t {
+       SSL_2_0 = 0x0200,
+       SSL_3_0 = 0x0300,
+       TLS_1_0 = 0x0301,
+       TLS_1_1 = 0x0302,
+       TLS_1_2 = 0x0303,
+};
+
+/**
+ * Enum names for tls_version_t
+ */
+extern enum_name_t *tls_version_names;
+
+/**
+ * TLS higher level content type
+ */
+enum tls_content_type_t {
+       TLS_CHANGE_CIPHER_SPEC = 20,
+       TLS_ALERT = 21,
+       TLS_HANDSHAKE = 22,
+       TLS_APPLICATION_DATA = 23,
+};
+
+/**
+ * Enum names for tls_content_type_t
+ */
+extern enum_name_t *tls_content_type_names;
+
+/**
+ * TLS handshake subtype
+ */
+enum tls_handshake_type_t {
+       TLS_HELLO_REQUEST = 0,
+       TLS_CLIENT_HELLO = 1,
+       TLS_SERVER_HELLO = 2,
+       TLS_CERTIFICATE = 11,
+       TLS_SERVER_KEY_EXCHANGE = 12,
+       TLS_CERTIFICATE_REQUEST = 13,
+       TLS_SERVER_HELLO_DONE = 14,
+       TLS_CERTIFICATE_VERIFY = 15,
+       TLS_CLIENT_KEY_EXCHANGE = 16,
+       TLS_FINISHED = 20,
+};
+
+/**
+ * Enum names for tls_handshake_type_t
+ */
+extern enum_name_t *tls_handshake_type_names;
+
+/**
+ * A bottom-up driven TLS stack, suitable for EAP implementations.
+ */
+struct tls_t {
+
+       /**
+        * Process a TLS record, pass it to upper layers.
+        *
+        * @param type          type of the TLS record to process
+        * @param data          associated TLS record data
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if more invocations to process/build needed
+        */
+       status_t (*process)(tls_t *this, tls_content_type_t type, chunk_t data);
+
+       /**
+        * Query upper layer for TLS record, build protected record.
+        *
+        * @param type          type of the built TLS record
+        * @param data          allocated data of the built TLS record
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if upper layers have more records to send
+        *                                      - INVALID_STATE if more input records required
+        */
+       status_t (*build)(tls_t *this, tls_content_type_t *type, chunk_t *data);
+
+       /**
+        * Check if TLS stack is acting as a server.
+        *
+        * @return                      TRUE if server, FALSE if peer
+        */
+       bool (*is_server)(tls_t *this);
+
+       /**
+        * Get the negotiated TLS/SSL version.
+        *
+        * @return                      negotiated TLS version
+        */
+       tls_version_t (*get_version)(tls_t *this);
+
+       /**
+        * Set the negotiated TLS/SSL version.
+        *
+        * @param version       negotiated TLS version
+        */
+       void (*set_version)(tls_t *this, tls_version_t version);
+
+       /**
+        * Check if TLS negotiation completed successfully.
+        *
+        * @return                      TRUE if TLS negotation and authentication complete
+        */
+       bool (*is_complete)(tls_t *this);
+
+       /**
+        * Get the MSK for EAP-TLS.
+        *
+        * @return                      MSK, internal data
+        */
+       chunk_t (*get_eap_msk)(tls_t *this);
+
+       /**
+        * Destroy a tls_t.
+        */
+       void (*destroy)(tls_t *this);
+};
+
+/**
+ * Create a tls instance.
+ *
+ * @param is_server            TRUE to act as server, FALSE for client
+ * @param server               server identity
+ * @param peer                 peer identity
+ * @return                             TLS stack
+ */
+tls_t *tls_create(bool is_server, identification_t *server,
+                                 identification_t *peer);
+
+#endif /** TLS_H_ @}*/
diff --git a/src/libtls/tls_compression.c b/src/libtls/tls_compression.c
new file mode 100644 (file)
index 0000000..02a3578
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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_compression.h"
+
+typedef struct private_tls_compression_t private_tls_compression_t;
+
+/**
+ * Private data of an tls_compression_t object.
+ */
+struct private_tls_compression_t {
+
+       /**
+        * Public tls_compression_t interface.
+        */
+       tls_compression_t public;
+
+       /**
+        * Upper layer, TLS record fragmentation
+        */
+       tls_fragmentation_t *fragmentation;
+};
+
+METHOD(tls_compression_t, process, status_t,
+       private_tls_compression_t *this, tls_content_type_t type, chunk_t data)
+{
+       return this->fragmentation->process(this->fragmentation, type, data);
+}
+
+METHOD(tls_compression_t, build, status_t,
+       private_tls_compression_t *this, tls_content_type_t *type, chunk_t *data)
+{
+       return this->fragmentation->build(this->fragmentation, type, data);
+}
+
+METHOD(tls_compression_t, destroy, void,
+       private_tls_compression_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_compression_t *tls_compression_create(tls_fragmentation_t *fragmentation)
+{
+       private_tls_compression_t *this;
+
+       INIT(this,
+               .public = {
+                       .process = _process,
+                       .build = _build,
+                       .destroy = _destroy,
+               },
+               .fragmentation = fragmentation,
+       );
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_compression.h b/src/libtls/tls_compression.h
new file mode 100644 (file)
index 0000000..bd27ab5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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_compression tls_compression
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_COMPRESSION_H_
+#define TLS_COMPRESSION_H_
+
+typedef struct tls_compression_t tls_compression_t;
+
+#include <library.h>
+
+#include "tls.h"
+#include "tls_fragmentation.h"
+
+/**
+ * TLS record protocol compression layer.
+ */
+struct tls_compression_t {
+
+       /**
+        * Process a compressed TLS record, pass it to upper layers.
+        *
+        * @param type          type of the TLS record to process
+        * @param data          associated TLS record data
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if more invocations to process/build needed
+        */
+       status_t (*process)(tls_compression_t *this,
+                                               tls_content_type_t type, chunk_t data);
+
+       /**
+        * Query upper layer for TLS record, build compressed record.
+        *
+        * @param type          type of the built TLS record
+        * @param data          allocated data of the built TLS record
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if upper layers have more records to send
+        *                                      - INVALID_STATE if more input records required
+        */
+       status_t (*build)(tls_compression_t *this,
+                                         tls_content_type_t *type, chunk_t *data);
+
+       /**
+        * Destroy a tls_compression_t.
+        */
+       void (*destroy)(tls_compression_t *this);
+};
+
+/**
+ * Create a tls_compression instance.
+ *
+ * @param fragmentation                fragmentation layer of TLS stack
+ * @return                                     TLS compression layer.
+ */
+tls_compression_t *tls_compression_create(tls_fragmentation_t *fragmentation);
+
+#endif /** TLS_COMPRESSION_H_ @}*/
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
new file mode 100644 (file)
index 0000000..085c11e
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * 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_crypto.h"
+
+#include <debug.h>
+
+typedef struct private_tls_crypto_t private_tls_crypto_t;
+
+/**
+ * Private data of an tls_crypto_t object.
+ */
+struct private_tls_crypto_t {
+
+       /**
+        * Public tls_crypto_t interface.
+        */
+       tls_crypto_t public;
+
+       /**
+        * Protection layer
+        */
+       tls_protection_t *protection;
+
+       /**
+        * List of supported/acceptable cipher suites
+        */
+       tls_cipher_suite_t *suites;
+
+       /**
+        * Number of supported suites
+        */
+       int suite_count;
+
+       /**
+        * Selected cipher suite
+        */
+       tls_cipher_suite_t suite;
+
+       /**
+        * TLS context
+        */
+       tls_t *tls;
+
+       /**
+        * All handshake data concatentated
+        */
+       chunk_t handshake;
+
+       /**
+        * Connection state TLS PRF
+        */
+       tls_prf_t *prf;
+
+       /**
+        * Signer instance for inbound traffic
+        */
+       signer_t *signer_in;
+
+       /**
+        * Signer instance for outbound traffic
+        */
+       signer_t *signer_out;
+
+       /**
+        * Crypter instance for inbound traffic
+        */
+       crypter_t *crypter_in;
+
+       /**
+        * Crypter instance for outbound traffic
+        */
+       crypter_t *crypter_out;
+
+       /**
+        * IV for input decryption, if < TLSv1.2
+        */
+       chunk_t iv_in;
+
+       /**
+        * IV for output decryption, if < TLSv1.2
+        */
+       chunk_t iv_out;
+
+       /**
+        * EAP-TLS MSK
+        */
+       chunk_t msk;
+};
+
+typedef struct {
+       tls_cipher_suite_t suite;
+       hash_algorithm_t hash;
+       pseudo_random_function_t prf;
+       integrity_algorithm_t mac;
+       encryption_algorithm_t encr;
+       size_t encr_size;
+} suite_algs_t;
+
+/**
+ * Mapping suites to a set of algorithms
+ */
+static suite_algs_t suite_algs[] = {
+       { TLS_RSA_WITH_NULL_MD5,
+               HASH_MD5,
+               PRF_HMAC_MD5,
+               AUTH_HMAC_MD5_128,
+               ENCR_NULL, 0
+       },
+       { TLS_RSA_WITH_NULL_SHA,
+               HASH_SHA1,
+               PRF_HMAC_SHA1,
+               AUTH_HMAC_SHA1_160,
+               ENCR_NULL, 0
+       },
+       { TLS_RSA_WITH_NULL_SHA256,
+               HASH_SHA256,
+               PRF_HMAC_SHA2_256,
+               AUTH_HMAC_SHA2_256_256,
+               ENCR_NULL, 0
+       },
+       { TLS_RSA_WITH_AES_128_CBC_SHA,
+               HASH_SHA1,
+               PRF_HMAC_SHA1,
+               AUTH_HMAC_SHA1_160,
+               ENCR_AES_CBC, 16
+       },
+       { TLS_RSA_WITH_AES_256_CBC_SHA,
+               HASH_SHA1,
+               PRF_HMAC_SHA1,
+               AUTH_HMAC_SHA1_160,
+               ENCR_AES_CBC, 32
+       },
+       { TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+               HASH_SHA1,
+               PRF_HMAC_SHA1,
+               AUTH_HMAC_SHA1_160,
+               ENCR_3DES, 0
+       },
+       { TLS_RSA_WITH_AES_128_CBC_SHA256,
+               HASH_SHA256,
+               PRF_HMAC_SHA2_256,
+               AUTH_HMAC_SHA2_256_256,
+               ENCR_AES_CBC, 16
+       },
+};
+
+/**
+ * Look up algoritms by a suite
+ */
+static suite_algs_t *find_suite(tls_cipher_suite_t suite)
+{
+       int i;
+
+       for (i = 0; i < countof(suite_algs); i++)
+       {
+               if (suite_algs[i].suite == suite)
+               {
+                       return &suite_algs[i];
+               }
+       }
+       return NULL;
+}
+
+/**
+ * Initialize the cipher suite list
+ */
+static void build_cipher_suite_list(private_tls_crypto_t *this)
+{
+       encryption_algorithm_t encr;
+       integrity_algorithm_t mac;
+       enumerator_t *encrs, *macs;
+       tls_cipher_suite_t supported[64], unique[64];
+       int count = 0, i, j;
+
+       /* we assume that we support RSA, but no DHE yet */
+       macs = lib->crypto->create_signer_enumerator(lib->crypto);
+       while (macs->enumerate(macs, &mac))
+       {
+               switch (mac)
+               {
+                       case AUTH_HMAC_SHA1_160:
+                               supported[count++] = TLS_RSA_WITH_NULL_SHA;
+                               break;
+                       case AUTH_HMAC_SHA2_256_256:
+                               supported[count++] = TLS_RSA_WITH_NULL_SHA256;
+                               break;
+                       case AUTH_HMAC_MD5_128:
+                               supported[count++] = TLS_RSA_WITH_NULL_MD5;
+                               break;
+                       default:
+                               break;
+               }
+               encrs = lib->crypto->create_crypter_enumerator(lib->crypto);
+               while (encrs->enumerate(encrs, &encr))
+               {
+                       switch (encr)
+                       {
+                               case ENCR_AES_CBC:
+                                       switch (mac)
+                                       {
+                                               case AUTH_HMAC_SHA1_160:
+                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+                                                       supported[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+                                                       break;
+                                               case AUTH_HMAC_SHA2_256_256:
+                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+                                                       supported[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                                       break;
+                               case ENCR_3DES:
+                                       switch (mac)
+                                       {
+                                               case AUTH_HMAC_SHA1_160:
+                                                       supported[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               encrs->destroy(encrs);
+       }
+       macs->destroy(macs);
+
+       /* remove duplicates */
+       this->suite_count = 0;
+       for (i = 0; i < count; i++)
+       {
+               bool match = FALSE;
+
+               for (j = 0; j < this->suite_count; j++)
+               {
+                       if (supported[i] == unique[j])
+                       {
+                               match = TRUE;
+                               break;
+                       }
+               }
+               if (!match)
+               {
+                       unique[this->suite_count++] = supported[i];
+               }
+       }
+       free(this->suites);
+       this->suites = malloc(sizeof(tls_cipher_suite_t) * this->suite_count);
+       memcpy(this->suites, unique, sizeof(tls_cipher_suite_t) * this->suite_count);
+}
+
+METHOD(tls_crypto_t, get_cipher_suites, int,
+       private_tls_crypto_t *this, tls_cipher_suite_t **suites)
+{
+       *suites = this->suites;
+       return this->suite_count;
+}
+
+/**
+ * Create crypto primitives
+ */
+static bool create_ciphers(private_tls_crypto_t *this, tls_cipher_suite_t suite)
+{
+       suite_algs_t *algs;
+
+       algs = find_suite(suite);
+       if (!algs)
+       {
+               DBG1(DBG_IKE, "selected TLS suite not supported");
+               return FALSE;
+       }
+
+       DESTROY_IF(this->prf);
+       if (this->tls->get_version(this->tls) < TLS_1_2)
+       {
+               this->prf = tls_prf_create_10();
+       }
+       else
+       {
+               this->prf = tls_prf_create_12(algs->prf);
+       }
+       if (!this->prf)
+       {
+               DBG1(DBG_IKE, "selected TLS PRF not supported");
+               return FALSE;
+       }
+
+       DESTROY_IF(this->signer_in);
+       DESTROY_IF(this->signer_out);
+       this->signer_in = lib->crypto->create_signer(lib->crypto, algs->mac);
+       this->signer_out = lib->crypto->create_signer(lib->crypto, algs->mac);
+       if (!this->signer_in || !this->signer_out)
+       {
+               DBG1(DBG_IKE, "selected TLS MAC %N not supported",
+                        integrity_algorithm_names, algs->mac);
+               return FALSE;
+       }
+
+       DESTROY_IF(this->crypter_in);
+       DESTROY_IF(this->crypter_out);
+       if (algs->encr == ENCR_NULL)
+       {
+               this->crypter_in = this->crypter_out = NULL;
+       }
+       else
+       {
+               this->crypter_in = lib->crypto->create_crypter(lib->crypto,
+                                                                                               algs->encr, algs->encr_size);
+               this->crypter_out = lib->crypto->create_crypter(lib->crypto,
+                                                                                               algs->encr, algs->encr_size);
+               if (!this->crypter_in || !this->crypter_out)
+               {
+                       DBG1(DBG_IKE, "selected TLS crypter %N not supported",
+                                encryption_algorithm_names, algs->encr);
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t,
+       private_tls_crypto_t *this, tls_cipher_suite_t *suites, int count)
+{
+       int i, j;
+
+       for (i = 0; i < this->suite_count; i++)
+       {
+               for (j = 0; j < count; j++)
+               {
+                       if (this->suites[i] == suites[j])
+                       {
+                               if (create_ciphers(this, this->suites[i]))
+                               {
+                                       this->suite = this->suites[i];
+                                       return this->suite;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+METHOD(tls_crypto_t, set_protection, void,
+       private_tls_crypto_t *this, tls_protection_t *protection)
+{
+       this->protection = protection;
+}
+
+METHOD(tls_crypto_t, append_handshake, void,
+       private_tls_crypto_t *this, tls_handshake_type_t type, chunk_t data)
+{
+       u_int32_t header;
+
+       /* reconstruct handshake header */
+       header = htonl(data.len | (type << 24));
+       this->handshake = chunk_cat("mcc", this->handshake,
+                                                               chunk_from_thing(header), data);
+}
+
+/**
+ * Create a hash of the stored handshake data
+ */
+static bool hash_handshake(private_tls_crypto_t *this, chunk_t *hash)
+{
+       if (this->tls->get_version(this->tls) >= TLS_1_2)
+       {
+               hasher_t *hasher;
+               suite_algs_t *alg;
+
+               alg = find_suite(this->suite);
+               if (!alg)
+               {
+                       return FALSE;
+               }
+               hasher = lib->crypto->create_hasher(lib->crypto, alg->hash);
+               if (!hasher)
+               {
+                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, alg->hash);
+                       return FALSE;
+               }
+               hasher->allocate_hash(hasher, this->handshake, hash);
+               hasher->destroy(hasher);
+       }
+       else
+       {
+               hasher_t *md5, *sha1;
+               char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1];
+
+               md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
+               if (!md5)
+               {
+                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_MD5);
+                       return FALSE;
+               }
+               md5->get_hash(md5, this->handshake, buf);
+               md5->destroy(md5);
+               sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+               if (!sha1)
+               {
+                       DBG1(DBG_IKE, "%N not supported", hash_algorithm_names, HASH_SHA1);
+                       return FALSE;
+               }
+               sha1->get_hash(sha1, this->handshake, buf + HASH_SIZE_MD5);
+               sha1->destroy(sha1);
+
+               *hash = chunk_clone(chunk_from_thing(buf));
+       }
+       return TRUE;
+}
+
+METHOD(tls_crypto_t, sign_handshake, bool,
+       private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer)
+{
+       chunk_t sig, hash;
+
+       if (this->tls->get_version(this->tls) >= TLS_1_2)
+       {
+               /* TODO: use supported algorithms instead of fixed SHA1/RSA */
+               if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, &sig))
+               {
+                       return FALSE;
+               }
+               writer->write_uint8(writer, 2);
+               writer->write_uint8(writer, 1);
+               writer->write_data16(writer, sig);
+               free(sig.ptr);
+       }
+       else
+       {
+               if (!hash_handshake(this, &hash))
+               {
+                       return FALSE;
+               }
+               if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
+               {
+                       free(hash.ptr);
+                       return FALSE;
+               }
+               writer->write_data16(writer, sig);
+               free(hash.ptr);
+               free(sig.ptr);
+       }
+       return TRUE;
+}
+
+METHOD(tls_crypto_t, verify_handshake, bool,
+       private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader)
+{
+       if (this->tls->get_version(this->tls) >= TLS_1_2)
+       {
+               u_int8_t hash, alg;
+               chunk_t sig;
+
+               if (!reader->read_uint8(reader, &hash) ||
+                       !reader->read_uint8(reader, &alg) ||
+                       !reader->read_data16(reader, &sig))
+               {
+                       DBG1(DBG_IKE, "received invalid Certificate Verify");
+                       return FALSE;
+               }
+               /* TODO: map received hash/sig alg to signature scheme */
+               if (hash != 2 || alg != 1 ||
+                       !key->verify(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig))
+               {
+                       return FALSE;
+               }
+       }
+       else
+       {
+               chunk_t sig, hash;
+
+               if (!reader->read_data16(reader, &sig))
+               {
+                       DBG1(DBG_IKE, "received invalid Certificate Verify");
+                       return FALSE;
+               }
+               if (!hash_handshake(this, &hash))
+               {
+                       return FALSE;
+               }
+               if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig))
+               {
+                       free(hash.ptr);
+                       return FALSE;
+               }
+               free(hash.ptr);
+       }
+       return TRUE;
+}
+
+METHOD(tls_crypto_t, calculate_finished, bool,
+       private_tls_crypto_t *this, char *label, char out[12])
+{
+       chunk_t seed;
+
+       if (!this->prf)
+       {
+               return FALSE;
+       }
+       if (!hash_handshake(this, &seed))
+       {
+               return FALSE;
+       }
+       this->prf->get_bytes(this->prf, label, seed, 12, out);
+       free(seed.ptr);
+       return TRUE;
+}
+
+METHOD(tls_crypto_t, derive_secrets, void,
+       private_tls_crypto_t *this, chunk_t premaster,
+       chunk_t client_random, chunk_t server_random)
+{
+       char master[48];
+       chunk_t seed, block, client_write, server_write;
+       int mks, eks = 0, ivs = 0;
+
+       /* derive master secret */
+       seed = chunk_cata("cc", client_random, server_random);
+       this->prf->set_key(this->prf, premaster);
+       this->prf->get_bytes(this->prf, "master secret", seed,
+                                                sizeof(master), master);
+
+       this->prf->set_key(this->prf, chunk_from_thing(master));
+       memset(master, 0, sizeof(master));
+
+       /* derive key block for key expansion */
+       mks = this->signer_out->get_key_size(this->signer_out);
+       if (this->crypter_out)
+       {
+               eks = this->crypter_out->get_key_size(this->crypter_out);
+               if (this->tls->get_version(this->tls) < TLS_1_1)
+               {
+                       ivs = this->crypter_out->get_block_size(this->crypter_out);
+               }
+       }
+       seed = chunk_cata("cc", server_random, client_random);
+       block = chunk_alloca((mks + eks + ivs) * 2);
+       this->prf->get_bytes(this->prf, "key expansion", seed, block.len, block.ptr);
+
+       /* signer keys */
+       client_write = chunk_create(block.ptr, mks);
+       block = chunk_skip(block, mks);
+       server_write = chunk_create(block.ptr, mks);
+       block = chunk_skip(block, mks);
+       if (this->tls->is_server(this->tls))
+       {
+               this->signer_in->set_key(this->signer_in, client_write);
+               this->signer_out->set_key(this->signer_out, server_write);
+       }
+       else
+       {
+               this->signer_out->set_key(this->signer_out, client_write);
+               this->signer_in->set_key(this->signer_in, server_write);
+       }
+
+       /* crypter keys, and IVs if < TLSv1.2 */
+       if (this->crypter_out && this->crypter_in)
+       {
+               client_write = chunk_create(block.ptr, eks);
+               block = chunk_skip(block, eks);
+               server_write = chunk_create(block.ptr, eks);
+               block = chunk_skip(block, eks);
+
+               if (this->tls->is_server(this->tls))
+               {
+                       this->crypter_in->set_key(this->crypter_in, client_write);
+                       this->crypter_out->set_key(this->crypter_out, server_write);
+               }
+               else
+               {
+                       this->crypter_out->set_key(this->crypter_out, client_write);
+                       this->crypter_in->set_key(this->crypter_in, server_write);
+               }
+               if (ivs)
+               {
+                       client_write = chunk_create(block.ptr, ivs);
+                       block = chunk_skip(block, ivs);
+                       server_write = chunk_create(block.ptr, ivs);
+                       block = chunk_skip(block, ivs);
+
+                       if (this->tls->is_server(this->tls))
+                       {
+                               this->iv_in = chunk_clone(client_write);
+                               this->iv_out = chunk_clone(server_write);
+                       }
+                       else
+                       {
+                               this->iv_out = chunk_clone(client_write);
+                               this->iv_in = chunk_clone(server_write);
+                       }
+               }
+       }
+}
+
+METHOD(tls_crypto_t, change_cipher, void,
+       private_tls_crypto_t *this, bool inbound)
+{
+       if (this->protection)
+       {
+               if (inbound)
+               {
+                       this->protection->set_cipher(this->protection, TRUE,
+                                                       this->signer_in, this->crypter_in, this->iv_in);
+               }
+               else
+               {
+                       this->protection->set_cipher(this->protection, FALSE,
+                                                       this->signer_out, this->crypter_out, this->iv_out);
+               }
+       }
+}
+
+METHOD(tls_crypto_t, derive_eap_msk, void,
+       private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
+{
+       chunk_t seed;
+
+       seed = chunk_cata("cc", client_random, server_random);
+       free(this->msk.ptr);
+       this->msk = chunk_alloc(64);
+       this->prf->get_bytes(this->prf, "client EAP encryption", seed,
+                                                this->msk.len, this->msk.ptr);
+}
+
+METHOD(tls_crypto_t, get_eap_msk, chunk_t,
+       private_tls_crypto_t *this)
+{
+       return this->msk;
+}
+
+METHOD(tls_crypto_t, destroy, void,
+       private_tls_crypto_t *this)
+{
+       DESTROY_IF(this->signer_in);
+       DESTROY_IF(this->signer_out);
+       DESTROY_IF(this->crypter_in);
+       DESTROY_IF(this->crypter_out);
+       free(this->iv_in.ptr);
+       free(this->iv_out.ptr);
+       free(this->handshake.ptr);
+       free(this->msk.ptr);
+       DESTROY_IF(this->prf);
+       free(this->suites);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_crypto_t *tls_crypto_create(tls_t *tls)
+{
+       private_tls_crypto_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_cipher_suites = _get_cipher_suites,
+                       .select_cipher_suite = _select_cipher_suite,
+                       .set_protection = _set_protection,
+                       .append_handshake = _append_handshake,
+                       .sign_handshake = _sign_handshake,
+                       .verify_handshake = _verify_handshake,
+                       .calculate_finished = _calculate_finished,
+                       .derive_secrets = _derive_secrets,
+                       .change_cipher = _change_cipher,
+                       .derive_eap_msk = _derive_eap_msk,
+                       .get_eap_msk = _get_eap_msk,
+                       .destroy = _destroy,
+               },
+               .tls = tls,
+       );
+
+       build_cipher_suite_list(this);
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h
new file mode 100644 (file)
index 0000000..0d2588a
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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_crypto tls_crypto
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_CRYPTO_H_
+#define TLS_CRYPTO_H_
+
+typedef struct tls_crypto_t tls_crypto_t;
+typedef enum tls_cipher_suite_t tls_cipher_suite_t;
+
+#include "tls.h"
+#include "tls_prf.h"
+#include "tls_protection.h"
+
+#include <credentials/keys/private_key.h>
+
+/**
+ * TLS cipher suites
+ */
+enum tls_cipher_suite_t {
+       TLS_NULL_WITH_NULL_NULL =                               0x00,
+       TLS_RSA_WITH_NULL_MD5 =                                 0x01,
+       TLS_RSA_WITH_NULL_SHA =                                 0x02,
+       TLS_RSA_WITH_NULL_SHA256 =                              0x3B,
+       TLS_RSA_WITH_RC4_128_MD5 =                              0x04,
+       TLS_RSA_WITH_RC4_128_SHA =                              0x05,
+       TLS_RSA_WITH_3DES_EDE_CBC_SHA =                 0x0A,
+       TLS_RSA_WITH_AES_128_CBC_SHA =                  0x2F,
+       TLS_RSA_WITH_AES_256_CBC_SHA =                  0x35,
+       TLS_RSA_WITH_AES_128_CBC_SHA256 =               0x3C,
+       TLS_RSA_WITH_AES_256_CBC_SHA256 =               0x3D,
+       TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =              0x0D,
+       TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =              0x10,
+       TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =             0x13,
+       TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =             0x16,
+       TLS_DH_DSS_WITH_AES_128_CBC_SHA =               0x30,
+       TLS_DH_RSA_WITH_AES_128_CBC_SHA =               0x31,
+       TLS_DHE_DSS_WITH_AES_128_CBC_SHA =              0x32,
+       TLS_DHE_RSA_WITH_AES_128_CBC_SHA =              0x33,
+       TLS_DH_DSS_WITH_AES_256_CBC_SHA =               0x36,
+       TLS_DH_RSA_WITH_AES_256_CBC_SHA =               0x37,
+       TLS_DHE_DSS_WITH_AES_256_CBC_SHA =              0x38,
+       TLS_DHE_RSA_WITH_AES_256_CBC_SHA =              0x39,
+       TLS_DH_DSS_WITH_AES_128_CBC_SHA256 =    0x3E,
+       TLS_DH_RSA_WITH_AES_128_CBC_SHA256 =    0x3F,
+       TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 =   0x40,
+       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 =   0x67,
+       TLS_DH_DSS_WITH_AES_256_CBC_SHA256 =    0x68,
+       TLS_DH_RSA_WITH_AES_256_CBC_SHA256 =    0x69,
+       TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 =   0x6A,
+       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 =   0x6B,
+       TLS_DH_ANON_WITH_RC4_128_MD5 =                  0x18,
+       TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA =             0x1B,
+       TLS_DH_ANON_WITH_AES_128_CBC_SHA =              0x34,
+       TLS_DH_ANON_WITH_AES_256_CBC_SHA =              0x3A,
+       TLS_DH_ANON_WITH_AES_128_CBC_SHA256 =   0x6C,
+       TLS_DH_ANON_WITH_AES_256_CBC_SHA256 =   0x6D,
+};
+
+/**
+ * TLS crypto helper functions.
+ */
+struct tls_crypto_t {
+
+       /**
+        * Get a list of supported TLS cipher suites.
+        *
+        * @param suites                list of suites, points to internal data
+        * @return                              number of suites returned
+        */
+       int (*get_cipher_suites)(tls_crypto_t *this, tls_cipher_suite_t **suites);
+
+       /**
+        * Select and store a cipher suite from a given list of candidates.
+        *
+        * @param suites                list of candidates to select from
+        * @param count                 number of suites
+        * @return                              selected suite, 0 if none acceptable
+        */
+       tls_cipher_suite_t (*select_cipher_suite)(tls_crypto_t *this,
+                                                                               tls_cipher_suite_t *suites, int count);
+
+       /**
+        * Set the protection layer of the TLS stack to control it.
+        *
+        * @param protection            protection layer to work on
+        */
+       void (*set_protection)(tls_crypto_t *this, tls_protection_t *protection);
+
+       /**
+        * Store exchanged handshake data, used for cryptographic operations.
+        *
+        * @param type                  handshake sub type
+        * @param data                  data to append to handshake buffer
+        */
+       void (*append_handshake)(tls_crypto_t *this,
+                                                        tls_handshake_type_t type, chunk_t data);
+
+       /**
+        * Create a signature of the handshake data using a given private key.
+        *
+        * @param key                   private key to use for signature
+        * @param writer                TLS writer to write signature to
+        * @return                              TRUE if signature create successfully
+        */
+       bool (*sign_handshake)(tls_crypto_t *this, private_key_t *key,
+                                                  tls_writer_t *writer);
+
+       /**
+        * Verify the signature over handshake data using a given public key.
+        *
+        * @param key                   public key to verify signature with
+        * @param reader                TLS reader to read signature from
+        * @return                              TRUE if signature valid
+        */
+       bool (*verify_handshake)(tls_crypto_t *this, public_key_t *key,
+                                                        tls_reader_t *reader);
+
+       /**
+        * Calculate the data of a TLS finished message.
+        *
+        * @param label                 ASCII label to use for calculation
+        * @param out                   buffer to write finished data to
+        * @return                              TRUE if calculation successful
+        */
+       bool (*calculate_finished)(tls_crypto_t *this, char *label, char out[12]);
+
+       /**
+        * Derive the master secret, MAC and encryption keys.
+        *
+        * @param premaster             premaster secret
+        * @param client_random random data from client hello
+        * @param server_random random data from server hello
+        */
+       void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster,
+                                                  chunk_t client_random, chunk_t server_random);
+
+       /**
+        * Change the cipher used at protection layer.
+        *
+        * @param inbound               TRUE to change inbound cipher, FALSE for outbound
+        */
+       void (*change_cipher)(tls_crypto_t *this, bool inbound);
+
+       /**
+        * Derive the EAP-TLS MSK.
+        *
+        * @param client_random random data from client hello
+        * @param server_random random data from server hello
+        */
+       void (*derive_eap_msk)(tls_crypto_t *this,
+                                                  chunk_t client_random, chunk_t server_random);
+
+       /**
+        * Get the MSK to use in EAP-TLS.
+        *
+        * @return                              MSK, points to internal data
+        */
+       chunk_t (*get_eap_msk)(tls_crypto_t *this);
+
+       /**
+        * Destroy a tls_crypto_t.
+        */
+       void (*destroy)(tls_crypto_t *this);
+};
+
+/**
+ * Create a tls_crypto instance.
+ */
+tls_crypto_t *tls_crypto_create(tls_t *tls);
+
+#endif /** TLS_CRYPTO_H_ @}*/
diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c
new file mode 100644 (file)
index 0000000..a8d8aa2
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * 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_fragmentation.h"
+
+#include "tls_reader.h"
+
+#include <debug.h>
+
+typedef struct private_tls_fragmentation_t private_tls_fragmentation_t;
+
+/**
+ * Private data of an tls_fragmentation_t object.
+ */
+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;
+
+       /**
+        * Handshake output buffer
+        */
+       chunk_t output;
+};
+
+/**
+ * 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
+
+/**
+ * Process TLS handshake protocol data
+ */
+static status_t process_handshake(private_tls_fragmentation_t *this,
+                                                                 tls_reader_t *reader)
+{
+       while (reader->remaining(reader))
+       {
+               tls_reader_t *msg;
+               u_int8_t type;
+               u_int32_t len;
+               status_t status;
+               chunk_t data;
+
+               if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
+               {
+                       DBG1(DBG_IKE, "TLS fragment has invalid length");
+                       return FAILED;
+               }
+
+               if (this->input.len == 0)
+               {       /* new handshake message */
+                       if (!reader->read_uint8(reader, &type) ||
+                               !reader->read_uint24(reader, &len))
+                       {
+                               return FAILED;
+                       }
+                       this->type = type;
+                       if (len > MAX_TLS_HANDSHAKE_LEN)
+                       {
+                               DBG1(DBG_IKE, "TLS handshake message exceeds maximum length");
+                               return FAILED;
+                       }
+                       chunk_free(&this->input);
+                       this->inpos = 0;
+                       if (len)
+                       {
+                               this->input = chunk_alloc(len);
+                       }
+               }
+
+               len = min(this->input.len - this->inpos, reader->remaining(reader));
+               if (!reader->read_data(reader, len, &data))
+               {
+                       return FAILED;
+               }
+               memcpy(this->input.ptr + this->inpos, data.ptr, len);
+               this->inpos += len;
+
+               if (this->input.len == this->inpos)
+               {       /* message completely defragmented, process */
+                       msg = tls_reader_create(this->input);
+                       status = this->handshake->process(this->handshake, this->type, msg);
+                       msg->destroy(msg);
+                       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)
+{
+       tls_reader_t *reader;
+       status_t status;
+
+       reader = tls_reader_create(data);
+       switch (type)
+       {
+               case TLS_CHANGE_CIPHER_SPEC:
+                       if (this->handshake->change_cipherspec(this->handshake))
+                       {
+                               status = NEED_MORE;
+                               break;
+                       }
+                       status = FAILED;
+                       break;
+               case TLS_ALERT:
+                       /* TODO: handle Alert */
+                       status = FAILED;
+                       break;
+               case TLS_HANDSHAKE:
+                       status = process_handshake(this, reader);
+                       break;
+               case TLS_APPLICATION_DATA:
+                       /* skip application data */
+                       status = NEED_MORE;
+                       break;
+               default:
+                       DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type);
+                       status = NEED_MORE;
+                       break;
+       }
+       reader->destroy(reader);
+       return status;
+}
+
+METHOD(tls_fragmentation_t, build, status_t,
+       private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
+{
+       tls_handshake_type_t hs_type;
+       tls_writer_t *writer, *msg;
+       status_t status;
+
+       if (this->handshake->cipherspec_changed(this->handshake))
+       {
+               *type = TLS_CHANGE_CIPHER_SPEC;
+               *data = chunk_clone(chunk_from_chars(0x01));
+               return NEED_MORE;
+       }
+
+       if (!this->output.len)
+       {
+               msg = tls_writer_create(64);
+               do
+               {
+                       writer = tls_writer_create(64);
+                       status = this->handshake->build(this->handshake, &hs_type, writer);
+                       switch (status)
+                       {
+                               case NEED_MORE:
+                                       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);
+               }
+               while (status == NEED_MORE);
+
+               msg->destroy(msg);
+               if (status != INVALID_STATE)
+               {
+                       return status;
+               }
+       }
+
+       if (this->output.len)
+       {
+               *type = TLS_HANDSHAKE;
+               if (this->output.len <= MAX_TLS_FRAGMENT_LEN)
+               {
+                       *data = this->output;
+                       this->output = chunk_empty;
+                       return NEED_MORE;
+               }
+               *data = chunk_create(this->output.ptr, MAX_TLS_FRAGMENT_LEN);
+               this->output = chunk_clone(chunk_skip(this->output, MAX_TLS_FRAGMENT_LEN));
+               return NEED_MORE;
+       }
+       return status;
+}
+
+METHOD(tls_fragmentation_t, destroy, void,
+       private_tls_fragmentation_t *this)
+{
+       free(this->input.ptr);
+       free(this->output.ptr);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
+{
+       private_tls_fragmentation_t *this;
+
+       INIT(this,
+               .public = {
+                       .process = _process,
+                       .build = _build,
+                       .destroy = _destroy,
+               },
+               .handshake = handshake,
+       );
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_fragmentation.h b/src/libtls/tls_fragmentation.h
new file mode 100644 (file)
index 0000000..e141a33
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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_fragmentation tls_fragmentation
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_FRAGMENTATION_H_
+#define TLS_FRAGMENTATION_H_
+
+typedef struct tls_fragmentation_t tls_fragmentation_t;
+
+#include <library.h>
+
+#include "tls.h"
+#include "tls_handshake.h"
+
+/**
+ * TLS record protocol fragmentation layer.
+ */
+struct tls_fragmentation_t {
+
+       /**
+        * Process a fragmented TLS record, pass it to upper layers.
+        *
+        * @param type          type of the TLS record to process
+        * @param data          associated TLS record data
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if more invocations to process/build needed
+        */
+       status_t (*process)(tls_fragmentation_t *this,
+                                               tls_content_type_t type, chunk_t data);
+
+       /**
+        * Query upper layer for TLS messages, build fragmented records.
+        *
+        * @param type          type of the built TLS record
+        * @param data          allocated data of the built TLS record
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if upper layers have more records to send
+        *                                      - INVALID_STATE if more input records required
+        */
+       status_t (*build)(tls_fragmentation_t *this,
+                                         tls_content_type_t *type, chunk_t *data);
+
+       /**
+        * Destroy a tls_fragmentation_t.
+        */
+       void (*destroy)(tls_fragmentation_t *this);
+};
+
+/**
+ * Create a tls_fragmentation instance.
+ *
+ * @param handshake                    upper layer handshake protocol
+ * @return                                     TLS fragmentation layer.
+ */
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake);
+
+#endif /** TLS_FRAGMENTATION_H_ @}*/
diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h
new file mode 100644 (file)
index 0000000..c079862
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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_handshake tls_handshake
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_HANDSHAKE_H_
+#define TLS_HANDSHAKE_H_
+
+typedef struct tls_handshake_t tls_handshake_t;
+
+#include "tls.h"
+#include "tls_reader.h"
+#include "tls_writer.h"
+
+/**
+ * TLS handshake state machine interface.
+ */
+struct tls_handshake_t {
+
+       /**
+        * Process received TLS handshake message.
+        *
+        * @param type          TLS handshake message type
+        * @param reader        TLS data buffer
+        * @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, tls_reader_t *reader);
+
+       /**
+        * Build TLS handshake messages to send out.
+        *
+        * @param type          type of created handshake message
+        * @param writer        TLS data buffer to write to
+        * @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, tls_writer_t *writer);
+
+       /**
+        * Check if the cipher spec for outgoing messages has changed.
+        *
+        * @return                      TRUE if cipher spec changed
+        */
+       bool (*cipherspec_changed)(tls_handshake_t *this);
+
+       /**
+        * Change the cipher spec for incoming messages.
+        *
+        * @return                      TRUE if cipher spec changed
+        */
+       bool (*change_cipherspec)(tls_handshake_t *this);
+
+       /**
+        * Destroy a tls_handshake_t.
+        */
+       void (*destroy)(tls_handshake_t *this);
+};
+
+#endif /** TLS_HANDSHAKE_H_ @}*/
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
new file mode 100644 (file)
index 0000000..c87002f
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * 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 <debug.h>
+
+#include <time.h>
+
+typedef struct private_tls_peer_t private_tls_peer_t;
+
+typedef enum {
+       STATE_INIT,
+       STATE_HELLO_SENT,
+       STATE_HELLO_RECEIVED,
+       STATE_HELLO_DONE,
+       STATE_CERT_SENT,
+       STATE_CERT_RECEIVED,
+       STATE_CERTREQ_RECEIVED,
+       STATE_KEY_EXCHANGE_SENT,
+       STATE_VERIFY_SENT,
+       STATE_CIPHERSPEC_CHANGED_OUT,
+       STATE_FINISHED_SENT,
+       STATE_CIPHERSPEC_CHANGED_IN,
+       STATE_COMPLETE,
+} peer_state_t;
+
+/**
+ * Private data of an tls_peer_t object.
+ */
+struct private_tls_peer_t {
+
+       /**
+        * Public tls_peer_t interface.
+        */
+       tls_peer_t public;
+
+       /**
+        * TLS stack
+        */
+       tls_t *tls;
+
+       /**
+        * TLS crypto context
+        */
+       tls_crypto_t *crypto;
+
+       /**
+        * Peer identity
+        */
+       identification_t *peer;
+
+       /**
+        * Server identity
+        */
+       identification_t *server;
+
+       /**
+        * State we are in
+        */
+       peer_state_t state;
+
+       /**
+        * Hello random data selected by client
+        */
+       char client_random[32];
+
+       /**
+        * Hello random data selected by server
+        */
+       char server_random[32];
+
+       /**
+        * Auth helper for peer authentication
+        */
+       auth_cfg_t *peer_auth;
+
+       /**
+        * Auth helper for server authentication
+        */
+       auth_cfg_t *server_auth;
+
+       /**
+        * Peer private key
+        */
+       private_key_t *private;
+};
+
+/**
+ * Process a server hello message
+ */
+static status_t process_server_hello(private_tls_peer_t *this,
+                                                                        tls_reader_t *reader)
+{
+       u_int8_t compression;
+       u_int16_t version, cipher;
+       chunk_t random, session, ext = chunk_empty;
+       tls_cipher_suite_t suite;
+
+       this->crypto->append_handshake(this->crypto,
+                                                                  TLS_SERVER_HELLO, reader->peek(reader));
+
+       if (!reader->read_uint16(reader, &version) ||
+               !reader->read_data(reader, sizeof(this->server_random), &random) ||
+               !reader->read_data8(reader, &session) ||
+               !reader->read_uint16(reader, &cipher) ||
+               !reader->read_uint8(reader, &compression) ||
+               (reader->remaining(reader) && !reader->read_data16(reader, &ext)))
+       {
+               DBG1(DBG_IKE, "received invalid ServerHello");
+               return FAILED;
+       }
+
+       memcpy(this->server_random, random.ptr, sizeof(this->server_random));
+
+       if (version < this->tls->get_version(this->tls))
+       {
+               this->tls->set_version(this->tls, version);
+       }
+       suite = cipher;
+       if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1))
+       {
+               DBG1(DBG_IKE, "received cipher suite inacceptable");
+               return FAILED;
+       }
+       this->state = STATE_HELLO_RECEIVED;
+       return NEED_MORE;
+}
+
+/**
+ * Process a Certificate message
+ */
+static status_t process_certificate(private_tls_peer_t *this,
+                                                                       tls_reader_t *reader)
+{
+       certificate_t *cert;
+       tls_reader_t *certs;
+       chunk_t data;
+       bool first = TRUE;
+
+       this->crypto->append_handshake(this->crypto,
+                                                                  TLS_CERTIFICATE, reader->peek(reader));
+
+       if (!reader->read_data24(reader, &data))
+       {
+               return FAILED;
+       }
+       certs = tls_reader_create(data);
+       while (certs->remaining(certs))
+       {
+               if (!certs->read_data24(certs, &data))
+               {
+                       certs->destroy(certs);
+                       return FAILED;
+               }
+               cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                                                 BUILD_BLOB_ASN1_DER, data, BUILD_END);
+               if (cert)
+               {
+                       if (first)
+                       {
+                               this->server_auth->add(this->server_auth,
+                                                                          AUTH_HELPER_SUBJECT_CERT, cert);
+                               DBG1(DBG_IKE, "received TLS server certificate '%Y'",
+                                        cert->get_subject(cert));
+                               first = FALSE;
+                       }
+                       else
+                       {
+                               DBG1(DBG_IKE, "received TLS intermediate certificate '%Y'",
+                                        cert->get_subject(cert));
+                               this->server_auth->add(this->server_auth,
+                                                                          AUTH_HELPER_IM_CERT, cert);
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "parsing TLS certificate failed, skipped");
+               }
+       }
+       certs->destroy(certs);
+       this->state = STATE_CERT_RECEIVED;
+       return NEED_MORE;
+}
+
+/**
+ * Process a Certificate message
+ */
+static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
+{
+       chunk_t types, hashsig, data;
+       tls_reader_t *authorities;
+       identification_t *id;
+       certificate_t *cert;
+
+       this->crypto->append_handshake(this->crypto,
+                                                               TLS_CERTIFICATE_REQUEST, reader->peek(reader));
+
+       if (!reader->read_data8(reader, &types))
+       {
+               return FAILED;
+       }
+       if (this->tls->get_version(this->tls) >= TLS_1_2)
+       {
+               if (!reader->read_data16(reader, &hashsig))
+               {
+                       return FAILED;
+               }
+               /* TODO: store supported hashsig algorithms */
+       }
+       if (!reader->read_data16(reader, &data))
+       {
+               return FAILED;
+       }
+       authorities = tls_reader_create(data);
+       while (authorities->remaining(authorities))
+       {
+               if (!authorities->read_data16(authorities, &data))
+               {
+                       authorities->destroy(authorities);
+                       return FAILED;
+               }
+               id = identification_create_from_encoding(ID_DER_ASN1_DN, data);
+               cert = lib->credmgr->get_cert(lib->credmgr,
+                                                                         CERT_X509, KEY_ANY, id, TRUE);
+               if (cert)
+               {
+                       DBG1(DBG_IKE, "received cert request for '%Y", id);
+                       this->peer_auth->add(this->peer_auth, AUTH_RULE_CA_CERT, cert);
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "received cert request for unknown CA '%Y'", id);
+               }
+               id->destroy(id);
+       }
+       authorities->destroy(authorities);
+       this->state = STATE_CERTREQ_RECEIVED;
+       return NEED_MORE;
+}
+
+/**
+ * Process Hello Done message
+ */
+static status_t process_hello_done(private_tls_peer_t *this,
+                                                                  tls_reader_t *reader)
+{
+       this->crypto->append_handshake(this->crypto,
+                                                                  TLS_SERVER_HELLO_DONE, reader->peek(reader));
+       this->state = STATE_HELLO_DONE;
+       return NEED_MORE;
+}
+
+/**
+ * Process finished message
+ */
+static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
+{
+       chunk_t received;
+       char buf[12];
+
+       if (!reader->read_data(reader, sizeof(buf), &received))
+       {
+               DBG1(DBG_IKE, "received server finished too short");
+               return FAILED;
+       }
+       if (!this->crypto->calculate_finished(this->crypto, "server finished", buf))
+       {
+               DBG1(DBG_IKE, "calculating server finished failed");
+               return FAILED;
+       }
+       if (!chunk_equals(received, chunk_from_thing(buf)))
+       {
+               DBG1(DBG_IKE, "received server finished invalid");
+               return FAILED;
+       }
+       this->state = STATE_COMPLETE;
+       this->crypto->derive_eap_msk(this->crypto,
+                                                                chunk_from_thing(this->client_random),
+                                                                chunk_from_thing(this->server_random));
+       return NEED_MORE;
+}
+
+METHOD(tls_handshake_t, process, status_t,
+       private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
+{
+       tls_handshake_type_t expected;
+
+       switch (this->state)
+       {
+               case STATE_HELLO_SENT:
+                       if (type == TLS_SERVER_HELLO)
+                       {
+                               return process_server_hello(this, reader);
+                       }
+                       expected = TLS_SERVER_HELLO;
+                       break;
+               case STATE_HELLO_RECEIVED:
+                       if (type == TLS_CERTIFICATE)
+                       {
+                               return process_certificate(this, reader);
+                       }
+                       expected = TLS_CERTIFICATE;
+                       break;
+               case STATE_CERT_RECEIVED:
+                       if (type == TLS_CERTIFICATE_REQUEST)
+                       {
+                               return process_certreq(this, reader);
+                       }
+                       expected = TLS_CERTIFICATE_REQUEST;
+                       break;
+               case STATE_CERTREQ_RECEIVED:
+                       if (type == TLS_SERVER_HELLO_DONE)
+                       {
+                               return process_hello_done(this, reader);
+                       }
+                       expected = TLS_SERVER_HELLO_DONE;
+                       break;
+               case STATE_CIPHERSPEC_CHANGED_IN:
+                       if (type == TLS_FINISHED)
+                       {
+                               return process_finished(this, reader);
+                       }
+                       expected = TLS_FINISHED;
+                       break;
+               default:
+                       DBG1(DBG_IKE, "TLS %N not expected in current state",
+                                tls_handshake_type_names, type);
+                       return FAILED;
+       }
+       DBG1(DBG_IKE, "TLS %N expected, but received %N",
+                tls_handshake_type_names, expected, tls_handshake_type_names, type);
+       return FAILED;
+}
+
+/**
+ * Send a client hello
+ */
+static status_t send_client_hello(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       tls_cipher_suite_t *suite;
+       int count, i;
+       rng_t *rng;
+
+       htoun32(&this->client_random, time(NULL));
+       rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+       if (!rng)
+       {
+               return FAILED;
+       }
+       rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4);
+       rng->destroy(rng);
+
+       writer->write_uint16(writer, this->tls->get_version(this->tls));
+       writer->write_data(writer, chunk_from_thing(this->client_random));
+       /* session identifier => none */
+       writer->write_data8(writer, chunk_empty);
+
+       count = this->crypto->get_cipher_suites(this->crypto, &suite);
+       writer->write_uint16(writer, count * 2);
+       for (i = 0; i < count; i++)
+       {
+               writer->write_uint16(writer, suite[i]);
+       }
+       /* NULL compression only */
+       writer->write_uint8(writer, 1);
+       writer->write_uint8(writer, 0);
+
+       *type = TLS_CLIENT_HELLO;
+       this->state = STATE_HELLO_SENT;
+       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send Certificate
+ */
+static status_t send_certificate(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       enumerator_t *enumerator;
+       certificate_t *cert;
+       auth_rule_t rule;
+       tls_writer_t *certs;
+       chunk_t data;
+
+       this->private = lib->credmgr->get_private(lib->credmgr,
+                                                                               KEY_ANY, this->peer, this->peer_auth);
+       if (!this->private)
+       {
+               DBG1(DBG_IKE, "no TLS peer certificate found for '%Y'", this->peer);
+               return FAILED;
+       }
+
+       /* generate certificate payload */
+       certs = tls_writer_create(256);
+       cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
+       if (cert)
+       {
+               if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
+               {
+                       DBG1(DBG_IKE, "sending TLS peer certificate '%Y'",
+                                cert->get_subject(cert));
+                       certs->write_data24(certs, data);
+                       free(data.ptr);
+               }
+       }
+       enumerator = this->peer_auth->create_enumerator(this->peer_auth);
+       while (enumerator->enumerate(enumerator, &rule, &cert))
+       {
+               if (rule == AUTH_RULE_IM_CERT)
+               {
+                       if (cert->get_encoding(cert, CERT_ASN1_DER, &data))
+                       {
+                               DBG1(DBG_IKE, "sending TLS intermediate certificate '%Y'",
+                                        cert->get_subject(cert));
+                               certs->write_data24(certs, data);
+                               free(data.ptr);
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       writer->write_data24(writer, certs->get_buf(certs));
+       certs->destroy(certs);
+
+       *type = TLS_CERTIFICATE;
+       this->state = STATE_CERT_SENT;
+       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send client key exchange
+ */
+static status_t send_key_exchange(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       public_key_t *public = NULL, *current;
+       enumerator_t *enumerator;
+       auth_cfg_t *auth;
+       rng_t *rng;
+       char premaster[48];
+       chunk_t encrypted;
+
+       rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+       if (!rng)
+       {
+               DBG1(DBG_IKE, "no suitable RNG found for TLS premaster secret");
+               return FAILED;
+       }
+       rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
+       rng->destroy(rng);
+       htoun16(premaster, TLS_1_2);
+
+       this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+                                                                chunk_from_thing(this->client_random),
+                                                                chunk_from_thing(this->server_random));
+
+       enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
+                                                                       KEY_ANY, this->server, this->server_auth);
+       while (enumerator->enumerate(enumerator, &current, &auth))
+       {
+               public = current->get_ref(current);
+               break;
+       }
+       enumerator->destroy(enumerator);
+
+       if (!public)
+       {
+               DBG1(DBG_IKE, "no TLS public key found for server '%Y'", this->server);
+               return FAILED;
+       }
+       if (!public->encrypt(public, chunk_from_thing(premaster), &encrypted))
+       {
+               public->destroy(public);
+               DBG1(DBG_IKE, "encrypting TLS premaster secret failed");
+               return FAILED;
+       }
+
+       public->destroy(public);
+
+       writer->write_data16(writer, encrypted);
+       free(encrypted.ptr);
+
+       *type = TLS_CLIENT_KEY_EXCHANGE;
+       this->state = STATE_KEY_EXCHANGE_SENT;
+       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send certificate verify
+ */
+static status_t send_certificate_verify(private_tls_peer_t *this,
+                                                       tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       if (!this->private ||
+               !this->crypto->sign_handshake(this->crypto, this->private, writer))
+       {
+               DBG1(DBG_IKE, "creating TLS Certificate Verify signature failed");
+               return FAILED;
+       }
+
+       *type = TLS_CERTIFICATE_VERIFY;
+       this->state = STATE_VERIFY_SENT;
+       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+/**
+ * Send Finished
+ */
+static status_t send_finished(private_tls_peer_t *this,
+                                                         tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       char buf[12];
+
+       if (!this->crypto->calculate_finished(this->crypto, "client finished", buf))
+       {
+               DBG1(DBG_IKE, "calculating client finished data failed");
+               return FAILED;
+       }
+
+       writer->write_data(writer, chunk_from_thing(buf));
+
+       *type = TLS_FINISHED;
+       this->state = STATE_FINISHED_SENT;
+       this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+       return NEED_MORE;
+}
+
+METHOD(tls_handshake_t, build, status_t,
+       private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
+{
+       switch (this->state)
+       {
+               case STATE_INIT:
+                       return send_client_hello(this, type, writer);
+               case STATE_HELLO_DONE:
+                       return send_certificate(this, type, writer);
+               case STATE_CERT_SENT:
+                       return send_key_exchange(this, type, writer);
+               case STATE_KEY_EXCHANGE_SENT:
+                       return send_certificate_verify(this, type, writer);
+               case STATE_CIPHERSPEC_CHANGED_OUT:
+                       return send_finished(this, type, writer);
+               default:
+                       return INVALID_STATE;
+       }
+}
+
+METHOD(tls_handshake_t, cipherspec_changed, bool,
+       private_tls_peer_t *this)
+{
+       if (this->state == STATE_VERIFY_SENT)
+       {
+               this->crypto->change_cipher(this->crypto, FALSE);
+               this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(tls_handshake_t, change_cipherspec, bool,
+       private_tls_peer_t *this)
+{
+       if (this->state == STATE_FINISHED_SENT)
+       {
+               this->crypto->change_cipher(this->crypto, TRUE);
+               this->state = STATE_CIPHERSPEC_CHANGED_IN;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(tls_handshake_t, destroy, void,
+       private_tls_peer_t *this)
+{
+       DESTROY_IF(this->private);
+       this->peer_auth->destroy(this->peer_auth);
+       this->server_auth->destroy(this->server_auth);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *peer, identification_t *server)
+{
+       private_tls_peer_t *this;
+
+       INIT(this,
+               .public.handshake = {
+                       .process = _process,
+                       .build = _build,
+                       .cipherspec_changed = _cipherspec_changed,
+                       .change_cipherspec = _change_cipherspec,
+                       .destroy = _destroy,
+               },
+               .state = STATE_INIT,
+               .tls = tls,
+               .crypto = crypto,
+               .peer = peer,
+               .server = server,
+               .peer_auth = auth_cfg_create(),
+               .server_auth = auth_cfg_create(),
+       );
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_peer.h b/src/libtls/tls_peer.h
new file mode 100644 (file)
index 0000000..eb97c97
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 libtls
+ */
+
+#ifndef TLS_PEER_H_
+#define TLS_PEER_H_
+
+typedef struct tls_peer_t tls_peer_t;
+
+#include "tls_handshake.h"
+#include "tls_crypto.h"
+
+#include <library.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(tls_t *tls, tls_crypto_t *crypto,
+                                                       identification_t *peer, identification_t *server);
+
+#endif /** TLS_PEER_H_ @}*/
diff --git a/src/libtls/tls_prf.c b/src/libtls/tls_prf.c
new file mode 100644 (file)
index 0000000..f181d01
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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_prf.h"
+
+typedef struct private_tls_prf12_t private_tls_prf12_t;
+
+/**
+ * Private data of an tls_prf_t object.
+ */
+struct private_tls_prf12_t {
+
+       /**
+        * Public tls_prf_t interface.
+        */
+       tls_prf_t public;
+
+       /**
+        * Underlying primitive PRF
+        */
+       prf_t *prf;
+};
+
+METHOD(tls_prf_t, set_key12, void,
+       private_tls_prf12_t *this, chunk_t key)
+{
+       this->prf->set_key(this->prf, key);
+}
+
+/**
+ * The P_hash function as in TLS 1.0/1.2
+ */
+static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size,
+                                  size_t bytes, char *out)
+{
+       char buf[block_size], abuf[block_size];
+       chunk_t a;
+
+       /* seed = label + seed */
+       seed = chunk_cata("cc", chunk_create(label, strlen(label)), seed);
+       /* A(0) = seed */
+       a = seed;
+
+       while (TRUE)
+       {
+               /* A(i) = HMAC_hash(secret, A(i-1)) */
+               prf->get_bytes(prf, a, abuf);
+               a = chunk_from_thing(abuf);
+               /* HMAC_hash(secret, A(i) + seed) */
+               prf->get_bytes(prf, a, NULL);
+               prf->get_bytes(prf, seed, buf);
+
+               if (bytes <= block_size)
+               {
+                       memcpy(out, buf, bytes);
+                       break;
+               }
+               memcpy(out, buf, block_size);
+               out += block_size;
+               bytes -= block_size;
+       }
+}
+
+METHOD(tls_prf_t, get_bytes12, void,
+       private_tls_prf12_t *this, char *label, chunk_t seed,
+       size_t bytes, char *out)
+{
+       p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf),
+                  bytes, out);
+}
+
+METHOD(tls_prf_t, destroy12, void,
+       private_tls_prf12_t *this)
+{
+       this->prf->destroy(this->prf);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf)
+{
+       private_tls_prf12_t *this;
+
+       INIT(this,
+               .public = {
+                       .set_key = _set_key12,
+                       .get_bytes = _get_bytes12,
+                       .destroy = _destroy12,
+               },
+               .prf = lib->crypto->create_prf(lib->crypto, prf),
+       );
+       if (!this->prf)
+       {
+               free(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+
+typedef struct private_tls_prf10_t private_tls_prf10_t;
+
+/**
+ * Private data of an tls_prf_t object.
+ */
+struct private_tls_prf10_t {
+
+       /**
+        * Public tls_prf_t interface.
+        */
+       tls_prf_t public;
+
+       /**
+        * Underlying MD5 PRF
+        */
+       prf_t *md5;
+
+       /**
+        * Underlying SHA1 PRF
+        */
+       prf_t *sha1;
+};
+
+METHOD(tls_prf_t, set_key10, void,
+       private_tls_prf10_t *this, chunk_t key)
+{
+       size_t len = key.len / 2 + key.len % 2;
+
+       this->md5->set_key(this->md5, chunk_create(key.ptr, len));
+       this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, len));
+}
+
+METHOD(tls_prf_t, get_bytes10, void,
+       private_tls_prf10_t *this, char *label, chunk_t seed,
+       size_t bytes, char *out)
+{
+       char buf[bytes];
+
+       p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5),
+                  bytes, out);
+       p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1),
+                  bytes, buf);
+       memxor(out, buf, bytes);
+}
+
+METHOD(tls_prf_t, destroy10, void,
+       private_tls_prf10_t *this)
+{
+       DESTROY_IF(this->md5);
+       DESTROY_IF(this->sha1);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_prf_t *tls_prf_create_10(pseudo_random_function_t prf)
+{
+       private_tls_prf10_t *this;
+
+       INIT(this,
+               .public = {
+                       .set_key = _set_key10,
+                       .get_bytes = _get_bytes10,
+                       .destroy = _destroy10,
+               },
+               .md5 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_MD5),
+               .sha1 = lib->crypto->create_prf(lib->crypto, PRF_HMAC_SHA1),
+       );
+       if (!this->md5 || !this->sha1)
+       {
+               destroy10(this);
+               return NULL;
+       }
+       return &this->public;
+}
diff --git a/src/libtls/tls_prf.h b/src/libtls/tls_prf.h
new file mode 100644 (file)
index 0000000..811ce2d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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_prf tls_prf
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_PRF_H_
+#define TLS_PRF_H_
+
+typedef struct tls_prf_t tls_prf_t;
+
+#include <crypto/prfs/prf.h>
+
+/**
+ * The PRF function specified on TLS, based on HMAC.
+ */
+struct tls_prf_t {
+
+       /**
+        * Set the key of the PRF function.
+        *
+        * @param key           key to set
+        */
+       void (*set_key)(tls_prf_t *this, chunk_t key);
+
+       /**
+        * Generate a series of bytes using a label and a seed.
+        *
+        * @param label         ASCII input label
+        * @param seed          seed input value
+        * @param bytes         number of bytes to get
+        * @param out           buffer receiving bytes
+        */
+       void (*get_bytes)(tls_prf_t *this, char *label, chunk_t seed,
+                                         size_t bytes, char *out);
+
+       /**
+        * Destroy a tls_prf_t.
+        */
+       void (*destroy)(tls_prf_t *this);
+};
+
+/**
+ * Create a tls_prf instance with specific algorithm as in TLS 1.2.
+ *
+ * @param hash                 underlying PRF function to use
+ * @return                             TLS PRF algorithm
+ */
+tls_prf_t *tls_prf_create_12(pseudo_random_function_t prf);
+
+/**
+ * Create a tls_prf instance with XOred SHA1/MD5 as in TLS 1.0/1.1.
+ *
+ * @return                             TLS PRF algorithm
+ */
+tls_prf_t *tls_prf_create_10();
+
+#endif /** TLS_PRF_H_ @}*/
diff --git a/src/libtls/tls_protection.c b/src/libtls/tls_protection.c
new file mode 100644 (file)
index 0000000..5ea0a83
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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_protection.h"
+
+#include <debug.h>
+
+typedef struct private_tls_protection_t private_tls_protection_t;
+
+/**
+ * Private data of an tls_protection_t object.
+ */
+struct private_tls_protection_t {
+
+       /**
+        * Public tls_protection_t interface.
+        */
+       tls_protection_t public;
+
+       /**
+        * TLS context
+        */
+       tls_t *tls;
+
+       /**
+        * Upper layer, TLS record compression
+        */
+       tls_compression_t *compression;
+
+       /**
+        * RNG if we generate IVs ourself
+        */
+       rng_t *rng;
+
+       /**
+        * Sequence number of incoming records
+        */
+       u_int32_t seq_in;
+
+       /**
+        * Sequence number for outgoing records
+        */
+       u_int32_t seq_out;
+
+       /**
+        * Signer instance for inbound traffic
+        */
+       signer_t *signer_in;
+
+       /**
+        * Signer instance for outbound traffic
+        */
+       signer_t *signer_out;
+
+       /**
+        * Crypter instance for inbound traffic
+        */
+       crypter_t *crypter_in;
+
+       /**
+        * Crypter instance for outbound traffic
+        */
+       crypter_t *crypter_out;
+
+       /**
+        * Current IV for input decryption
+        */
+       chunk_t iv_in;
+
+       /**
+        * Current IV for output decryption
+        */
+       chunk_t iv_out;
+};
+
+/**
+ * Create the header to append to the record data to create the MAC
+ */
+static chunk_t sigheader(u_int32_t seq, u_int8_t type,
+                                                u_int16_t version, u_int16_t length)
+{
+       /* we only support 32 bit sequence numbers, but TLS uses 64 bit */
+       u_int32_t seq_high = 0;
+
+       seq = htonl(seq);
+       version = htons(version);
+       length = htons(length);
+
+       return chunk_cat("ccccc", chunk_from_thing(seq_high),
+                                       chunk_from_thing(seq), chunk_from_thing(type),
+                                       chunk_from_thing(version), chunk_from_thing(length));
+}
+
+METHOD(tls_protection_t, process, status_t,
+       private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
+{
+       if (this->crypter_in)
+       {
+               chunk_t iv, next_iv = chunk_empty;
+               u_int8_t bs, padding_length;
+
+               bs = this->crypter_in->get_block_size(this->crypter_in);
+               if (data.len < bs || data.len % bs)
+               {
+                       DBG1(DBG_IKE, "encrypted TLS record not multiple of block size");
+                       return FAILED;
+               }
+               if (this->iv_in.len)
+               {       /* < TLSv1.1 uses IV from key derivation/last block */
+                       iv = this->iv_in;
+                       next_iv = chunk_clone(chunk_create(data.ptr + data.len - bs, bs));
+               }
+               else
+               {       /* TLSv1.1 uses random IVs, prepended to record */
+                       iv = chunk_create(data.ptr, bs);
+                       data = chunk_skip(data, bs);
+                       if (data.len < bs)
+                       {
+                               DBG1(DBG_IKE, "TLS record too short to decrypt");
+                               return FAILED;
+                       }
+               }
+               this->crypter_in->decrypt(this->crypter_in, data, iv, NULL);
+
+               if (next_iv.len)
+               {       /* next record IV is last ciphertext block of this record */
+                       memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
+                       free(next_iv.ptr);
+               }
+
+               padding_length = data.ptr[data.len - 1];
+               if (padding_length >= data.len)
+               {
+                       DBG1(DBG_IKE, "invalid TLS record padding");
+                       return FAILED;
+               }
+               data.len -= padding_length + 1;
+       }
+       if (this->signer_in)
+       {
+               chunk_t mac, macdata, header;
+               u_int8_t bs;
+
+               bs = this->signer_in->get_block_size(this->signer_in);
+               if (data.len <= bs)
+               {
+                       DBG1(DBG_IKE, "TLS record too short to verify MAC");
+                       return FAILED;
+               }
+               mac = chunk_skip(data, data.len - bs);
+               data.len -= bs;
+
+               header = sigheader(this->seq_in, type,
+                                                  this->tls->get_version(this->tls), data.len);
+               macdata = chunk_cat("mc", header, data);
+               if (!this->signer_in->verify_signature(this->signer_in, macdata, mac))
+               {
+                       DBG1(DBG_IKE, "TLS record MAC verification failed");
+                       free(macdata.ptr);
+                       return FAILED;
+               }
+               free(macdata.ptr);
+       }
+
+       if (type == TLS_CHANGE_CIPHER_SPEC)
+       {
+               this->seq_in = 0;
+       }
+       else
+       {
+               this->seq_in++;
+       }
+       return this->compression->process(this->compression, type, data);
+}
+
+METHOD(tls_protection_t, build, status_t,
+       private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
+{
+       status_t status;
+
+       status = this->compression->build(this->compression, type, data);
+       if (*type == TLS_CHANGE_CIPHER_SPEC)
+       {
+               this->seq_out = 0;
+               return status;
+       }
+
+       if (status == NEED_MORE)
+       {
+               if (this->signer_out)
+               {
+                       chunk_t mac, header;
+
+                       header = sigheader(this->seq_out, *type,
+                                                          this->tls->get_version(this->tls), data->len);
+                       this->signer_out->get_signature(this->signer_out, header, NULL);
+                       free(header.ptr);
+                       this->signer_out->allocate_signature(this->signer_out, *data, &mac);
+                       if (this->crypter_out)
+                       {
+                               chunk_t padding, iv;
+                               u_int8_t bs, padding_length;
+
+                               bs = this->crypter_out->get_block_size(this->crypter_out);
+                               padding_length = bs - ((data->len + mac.len + 1) % bs);
+
+                               padding = chunk_alloca(padding_length);
+                               memset(padding.ptr, padding_length, padding.len);
+
+                               if (this->iv_out.len)
+                               {       /* < TLSv1.1 uses IV from key derivation/last block */
+                                       iv = this->iv_out;
+                               }
+                               else
+                               {       /* TLSv1.1 uses random IVs, prepended to record */
+                                       if (!this->rng)
+                                       {
+                                               DBG1(DBG_IKE, "no RNG supported to generate TLS IV");
+                                               free(data->ptr);
+                                               return FAILED;
+                                       }
+                                       this->rng->allocate_bytes(this->rng, bs, &iv);
+                               }
+
+                               *data = chunk_cat("mmcc", *data, mac, padding,
+                                                                 chunk_from_thing(padding_length));
+                               /* encrypt inline */
+                               this->crypter_out->encrypt(this->crypter_out, *data, iv, NULL);
+
+                               if (this->iv_out.len)
+                               {       /* next record IV is last ciphertext block of this record */
+                                       memcpy(this->iv_out.ptr, data->ptr - this->iv_out.len,
+                                                  this->iv_out.len);
+                               }
+                               else
+                               {       /* prepend IV */
+                                       *data = chunk_cat("mm", iv, *data);
+                               }
+                       }
+                       else
+                       {       /* NULL encryption */
+                               *data = chunk_cat("mm", *data, mac);
+                       }
+               }
+       }
+       this->seq_out++;
+       return status;
+}
+
+METHOD(tls_protection_t, set_cipher, void,
+       private_tls_protection_t *this, bool inbound, signer_t *signer,
+       crypter_t *crypter, chunk_t iv)
+{
+       if (inbound)
+       {
+               this->signer_in = signer;
+               this->crypter_in = crypter;
+               this->iv_in = iv;
+       }
+       else
+       {
+               this->signer_out = signer;
+               this->crypter_out = crypter;
+               this->iv_out = iv;
+               if (!iv.len)
+               {       /* generate IVs if none given */
+                       this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+               }
+       }
+}
+
+METHOD(tls_protection_t, destroy, void,
+       private_tls_protection_t *this)
+{
+       DESTROY_IF(this->rng);
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_protection_t *tls_protection_create(tls_t *tls,
+                                                                               tls_compression_t *compression)
+{
+       private_tls_protection_t *this;
+
+       INIT(this,
+               .public = {
+                       .process = _process,
+                       .build = _build,
+                       .set_cipher = _set_cipher,
+                       .destroy = _destroy,
+               },
+               .tls = tls,
+               .compression = compression,
+       );
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_protection.h b/src/libtls/tls_protection.h
new file mode 100644 (file)
index 0000000..aa7681b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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_protection tls_protection
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_PROTECTION_H_
+#define TLS_PROTECTION_H_
+
+typedef struct tls_protection_t tls_protection_t;
+
+#include <library.h>
+
+#include "tls.h"
+#include "tls_compression.h"
+
+/**
+ * TLS record protocol protection layer.
+ */
+struct tls_protection_t {
+
+       /**
+        * Process a protected TLS record, pass it to upper layers.
+        *
+        * @param type          type of the TLS record to process
+        * @param data          associated TLS record data
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if more invocations to process/build needed
+        */
+       status_t (*process)(tls_protection_t *this,
+                                               tls_content_type_t type, chunk_t data);
+
+       /**
+        * Query upper layer for TLS record, build protected record.
+        *
+        * @param type          type of the built TLS record
+        * @param data          allocated data of the built TLS record
+        * @return
+        *                                      - SUCCESS if TLS negotiation complete
+        *                                      - FAILED if TLS handshake failed
+        *                                      - NEED_MORE if upper layers have more records to send
+        *                                      - INVALID_STATE if more input records required
+        */
+       status_t (*build)(tls_protection_t *this,
+                                         tls_content_type_t *type, chunk_t *data);
+
+       /**
+        * Set a new cipher, including encryption and integrity algorithms.
+        *
+        * @param inbound       TRUE to use cipher for inbound data, FALSE for outbound
+        * @param signer        new signer to use, gets owned by protection layer
+        * @param crypter       new crypter to use, gets owned by protection layer
+        * @param iv            initial IV for crypter, gets owned by protection layer
+        */
+       void (*set_cipher)(tls_protection_t *this, bool inbound, signer_t *signer,
+                                          crypter_t *crypter, chunk_t iv);
+
+       /**
+        * Destroy a tls_protection_t.
+        */
+       void (*destroy)(tls_protection_t *this);
+};
+
+/**
+ * Create a tls_protection instance.
+ *
+ * @param tls                          TLS context
+ * @param compression          compression layer of TLS stack
+ * @return                                     TLS protection layer.
+ */
+tls_protection_t *tls_protection_create(tls_t *tls,
+                                                                               tls_compression_t *compression);
+
+#endif /** TLS_PROTECTION_H_ @}*/
diff --git a/src/libtls/tls_reader.c b/src/libtls/tls_reader.c
new file mode 100644 (file)
index 0000000..ee537be
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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_reader.h"
+
+#include <debug.h>
+
+typedef struct private_tls_reader_t private_tls_reader_t;
+
+/**
+ * Private data of an tls_reader_t object.
+ */
+struct private_tls_reader_t {
+
+       /**
+        * Public tls_reader_t interface.
+        */
+       tls_reader_t public;
+
+       /**
+        * Remaining data to process
+        */
+       chunk_t buf;
+};
+
+METHOD(tls_reader_t, remaining, u_int32_t,
+       private_tls_reader_t *this)
+{
+       return this->buf.len;
+}
+
+METHOD(tls_reader_t, peek, chunk_t,
+       private_tls_reader_t *this)
+{
+       return this->buf;
+}
+
+METHOD(tls_reader_t, read_uint8, bool,
+       private_tls_reader_t *this, u_int8_t *res)
+{
+       if (this->buf.len < 1)
+       {
+               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
+                        this->buf.len, 8);
+               return FALSE;
+       }
+       *res = this->buf.ptr[0];
+       this->buf = chunk_skip(this->buf, 1);
+       return TRUE;
+}
+
+METHOD(tls_reader_t, read_uint16, bool,
+       private_tls_reader_t *this, u_int16_t *res)
+{
+       if (this->buf.len < 2)
+       {
+               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
+                        this->buf.len, 16);
+               return FALSE;
+       }
+       *res = untoh16(this->buf.ptr);
+       this->buf = chunk_skip(this->buf, 2);
+       return TRUE;
+}
+
+METHOD(tls_reader_t, read_uint24, bool,
+       private_tls_reader_t *this, u_int32_t *res)
+{
+       if (this->buf.len < 3)
+       {
+               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
+                        this->buf.len, 24);
+               return FALSE;
+       }
+       *res = untoh32(this->buf.ptr) >> 8;
+       this->buf = chunk_skip(this->buf, 3);
+       return TRUE;
+}
+
+METHOD(tls_reader_t, read_uint32, bool,
+       private_tls_reader_t *this, u_int32_t *res)
+{
+       if (this->buf.len < 4)
+       {
+               DBG1(DBG_IKE, "%d bytes insufficient to parse uint%d TLS data",
+                        this->buf.len, 32);
+               return FALSE;
+       }
+       *res = untoh32(this->buf.ptr);
+       this->buf = chunk_skip(this->buf, 4);
+       return TRUE;
+}
+
+METHOD(tls_reader_t, read_data, bool,
+       private_tls_reader_t *this, u_int32_t len, chunk_t *res)
+{
+       if (this->buf.len < len)
+       {
+               DBG1(DBG_IKE, "%d bytes insufficient to parse %d bytes TLS data",
+                        this->buf.len, len);
+               return FALSE;
+       }
+       *res = chunk_create(this->buf.ptr, len);
+       this->buf = chunk_skip(this->buf, len);
+       return TRUE;
+}
+
+METHOD(tls_reader_t, read_data8, bool,
+       private_tls_reader_t *this, chunk_t *res)
+{
+       u_int8_t len;
+
+       if (!read_uint8(this, &len))
+       {
+               return FALSE;
+       }
+       return read_data(this, len, res);
+}
+
+METHOD(tls_reader_t, read_data16, bool,
+       private_tls_reader_t *this, chunk_t *res)
+{
+       u_int16_t len;
+
+       if (!read_uint16(this, &len))
+       {
+               return FALSE;
+       }
+       return read_data(this, len, res);
+}
+
+METHOD(tls_reader_t, read_data24, bool,
+       private_tls_reader_t *this, chunk_t *res)
+{
+       u_int32_t len;
+
+       if (!read_uint24(this, &len))
+       {
+               return FALSE;
+       }
+       return read_data(this, len, res);
+}
+
+METHOD(tls_reader_t, read_data32, bool,
+       private_tls_reader_t *this, chunk_t *res)
+{
+       u_int32_t len;
+
+       if (!read_uint32(this, &len))
+       {
+               return FALSE;
+       }
+       return read_data(this, len, res);
+}
+
+METHOD(tls_reader_t, destroy, void,
+       private_tls_reader_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_reader_t *tls_reader_create(chunk_t data)
+{
+       private_tls_reader_t *this;
+
+       INIT(this,
+               .public = {
+                       .remaining = _remaining,
+                       .peek = _peek,
+                       .read_uint8 = _read_uint8,
+                       .read_uint16 = _read_uint16,
+                       .read_uint24 = _read_uint24,
+                       .read_uint32 = _read_uint32,
+                       .read_data = _read_data,
+                       .read_data8 = _read_data8,
+                       .read_data16 = _read_data16,
+                       .read_data24 = _read_data24,
+                       .read_data32 = _read_data32,
+                       .destroy = _destroy,
+               },
+               .buf = data,
+       );
+
+       return &this->public;
+}
diff --git a/src/libtls/tls_reader.h b/src/libtls/tls_reader.h
new file mode 100644 (file)
index 0000000..a8978b4
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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_reader tls_reader
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_READER_H_
+#define TLS_READER_H_
+
+typedef struct tls_reader_t tls_reader_t;
+
+#include <library.h>
+
+/**
+ * TLS record parser.
+ */
+struct tls_reader_t {
+
+       /**
+        * Get the number of remaining bytes.
+        *
+        * @return                      number of remaining bytes in buffer
+        */
+       u_int32_t (*remaining)(tls_reader_t *this);
+
+       /**
+        * Peek the remaining data, not consuming any bytes.
+        *
+        * @return                      remaining data
+        */
+       chunk_t (*peek)(tls_reader_t *this);
+
+       /**
+        * Read a 8-bit integer from the buffer, advance.
+        *
+        * @param res           pointer to result
+        * @return                      TRUE if integer read successfully
+        */
+       bool (*read_uint8)(tls_reader_t *this, u_int8_t *res);
+
+       /**
+        * Read a 16-bit integer from the buffer, advance.
+        *
+        * @param res           pointer to result
+        * @return                      TRUE if integer read successfully
+        */
+       bool (*read_uint16)(tls_reader_t *this, u_int16_t *res);
+
+       /**
+        * Read a 24-bit integer from the buffer, advance.
+        *
+        * @param res           pointer to result
+        * @return                      TRUE if integer read successfully
+        */
+       bool (*read_uint24)(tls_reader_t *this, u_int32_t *res);
+
+       /**
+        * Read a 32-bit integer from the buffer, advance.
+        *
+        * @param res           pointer to result
+        * @return                      TRUE if integer read successfully
+        */
+       bool (*read_uint32)(tls_reader_t *this, u_int32_t *res);
+
+       /**
+        * Read a chunk of len bytes, advance.
+        *
+        * @param len           number of bytes to read
+        * @param res           pointer to result, not cloned
+        * @return                      TRUE if data read successfully
+        */
+       bool (*read_data)(tls_reader_t *this, u_int32_t len, chunk_t *res);
+
+       /**
+        * Read a chunk of bytes with a 8-bit length header, advance.
+        *
+        * @param res           pointer to result, not cloned
+        * @return                      TRUE if data read successfully
+        */
+       bool (*read_data8)(tls_reader_t *this, chunk_t *res);
+
+       /**
+        * Read a chunk of bytes with a 16-bit length header, advance.
+        *
+        * @param res           pointer to result, not cloned
+        * @return                      TRUE if data read successfully
+        */
+       bool (*read_data16)(tls_reader_t *this, chunk_t *res);
+
+       /**
+        * Read a chunk of bytes with a 24-bit length header, advance.
+        *
+        * @param res           pointer to result, not cloned
+        * @return                      TRUE if data read successfully
+        */
+       bool (*read_data24)(tls_reader_t *this, chunk_t *res);
+
+       /**
+        * Read a chunk of bytes with a 32-bit length header, advance.
+        *
+        * @param res           pointer to result, not cloned
+        * @return                      TRUE if data read successfully
+        */
+       bool (*read_data32)(tls_reader_t *this, chunk_t *res);
+
+       /**
+        * Destroy a tls_reader_t.
+        */
+       void (*destroy)(tls_reader_t *this);
+};
+
+/**
+ * Create a tls_reader instance.
+ */
+tls_reader_t *tls_reader_create(chunk_t data);
+
+#endif /** tls_reader_H_ @}*/
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
new file mode 100644 (file)
index 0000000..c0c0cc4
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * 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