added generic TLS application data handler and specific EAP-TTLS instantiation
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 12 Aug 2010 21:56:44 +0000 (23:56 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 12 Aug 2010 21:58:54 +0000 (23:58 +0200)
14 files changed:
src/libcharon/plugins/eap_tls/eap_tls.c
src/libcharon/plugins/eap_ttls/Makefile.am
src/libcharon/plugins/eap_ttls/eap_ttls.c
src/libcharon/plugins/eap_ttls/eap_ttls_peer.c [new file with mode: 0644]
src/libcharon/plugins/eap_ttls/eap_ttls_peer.h [new file with mode: 0644]
src/libtls/Makefile.am
src/libtls/tls.c
src/libtls/tls.h
src/libtls/tls_application.h [new file with mode: 0644]
src/libtls/tls_fragmentation.c
src/libtls/tls_fragmentation.h
src/libtls/tls_handshake.h
src/libtls/tls_peer.c
src/libtls/tls_server.c

index a2407e5..e4f12d7 100644 (file)
@@ -433,7 +433,8 @@ static eap_tls_t *eap_tls_create(identification_t *server,
                .is_server = is_server,
        );
        /* MSK PRF ASCII constant label according to EAP-TLS RFC 5216 */
-       this->tls = tls_create(is_server, server, peer, "client EAP encryption");
+       this->tls = tls_create(is_server, server, peer, "client EAP encryption",
+                                                  NULL);
 
        return &this->public;
 }
index fdd4606..47be979 100644 (file)
@@ -12,6 +12,7 @@ libstrongswan_eap_ttls_la_LIBADD = $(top_builddir)/src/libtls/libtls.la
 endif
 
 libstrongswan_eap_ttls_la_SOURCES = \
-       eap_ttls_plugin.h eap_ttls_plugin.c eap_ttls.h eap_ttls.c
+       eap_ttls_plugin.h eap_ttls_plugin.c eap_ttls.h eap_ttls.c \
+       eap_ttls_peer.h eap_ttls_peer.c
 
 libstrongswan_eap_ttls_la_LDFLAGS = -module -avoid-version
index 1139a3f..04ae138 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "eap_ttls.h"
+#include "eap_ttls_peer.h"
 
 #include <tls.h>
 
@@ -423,7 +424,8 @@ METHOD(eap_method_t, destroy, void,
  * Generic private constructor
  */
 static eap_ttls_t *eap_ttls_create(identification_t *server,
-                                                                identification_t *peer, bool is_server)
+                                                                identification_t *peer, bool is_server,
+                                                                tls_application_t *application)
 {
        private_eap_ttls_t *this;
 
@@ -439,19 +441,20 @@ static eap_ttls_t *eap_ttls_create(identification_t *server,
                .is_server = is_server,
        );
        /* MSK PRF ASCII constant label according to EAP-TTLS RFC 5281 */
-       this->tls = tls_create(is_server, server, peer, "ttls keying material");
-
+       this->tls = tls_create(is_server, server, peer, "ttls keying material",
+                                                  application);
        return &this->public;
 }
 
 eap_ttls_t *eap_ttls_create_server(identification_t *server,
                                                                 identification_t *peer)
 {
-       return eap_ttls_create(server, peer, TRUE);
+       return eap_ttls_create(server, peer, TRUE, NULL);
 }
 
 eap_ttls_t *eap_ttls_create_peer(identification_t *server,
                                                           identification_t *peer)
 {
-       return eap_ttls_create(server, peer, FALSE);
+       return eap_ttls_create(server, peer, FALSE,
+                                                  &eap_ttls_peer_create(peer)->application);
 }
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c
new file mode 100644 (file)
index 0000000..0e4d70f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_ttls_peer.h"
+
+#include <debug.h>
+
+#define AVP_EAP_MESSAGE                79
+
+typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t;
+
+/**
+ * Private data of an eap_ttls_peer_t object.
+ */
+struct private_eap_ttls_peer_t {
+
+       /**
+        * Public eap_ttls_peer_t interface.
+        */
+       eap_ttls_peer_t public;
+
+       /**
+        * Peer identity
+        */
+       identification_t *peer;
+
+       /**
+        * EAP-TTLS state information
+        */
+       bool start_phase2;
+};
+
+
+METHOD(tls_application_t, process, status_t,
+       private_eap_ttls_peer_t *this, tls_reader_t *reader)
+{
+       return NEED_MORE;
+}
+
+METHOD(tls_application_t, build, status_t,
+       private_eap_ttls_peer_t *this, tls_writer_t *writer)
+{
+       if (this->start_phase2)
+       {
+               chunk_t data = chunk_from_chars(
+                       0x02, 0x00, 0x00, 10, 0x01, 'c', 'a', 'r', 'o', 'l', 0x00, 0x00);
+               u_int8_t avp_flags = 0x40;
+               u_int32_t avp_len;
+
+               avp_len = 8 + data.len - 2;
+               writer->write_uint32(writer, AVP_EAP_MESSAGE);
+               writer->write_uint8(writer, avp_flags);
+               writer->write_uint24(writer, avp_len);
+               writer->write_data(writer, data);
+               this->start_phase2 = FALSE;
+       }
+       return INVALID_STATE;
+}
+
+METHOD(tls_application_t, destroy, void,
+       private_eap_ttls_peer_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+eap_ttls_peer_t *eap_ttls_peer_create(identification_t *peer)
+{
+       private_eap_ttls_peer_t *this;
+
+       INIT(this,
+               .public.application = {
+                       .process = _process,
+                       .build = _build,
+                       .destroy = _destroy,
+               },
+               .peer = peer,
+               .start_phase2 = TRUE,
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h
new file mode 100644 (file)
index 0000000..0338f26
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tls_peer tls_peer
+ * @{ @ingroup libtls
+ */
+
+#ifndef EAP_TTLS_PEER_H_
+#define EAP_TTLS_PEER_H_
+
+typedef struct eap_ttls_peer_t eap_ttls_peer_t;
+
+#include "tls_application.h"
+
+#include <library.h>
+
+/**
+ * TLS application data handler as peer.
+ */
+struct eap_ttls_peer_t {
+
+       /**
+        * Implements the TLS application data handler.
+        */
+       tls_application_t application;
+};
+
+/**
+ * Create an eap_ttls_peer instance.
+ */
+eap_ttls_peer_t *eap_ttls_peer_create(identification_t *peer);
+
+#endif /** EAP_TTLS_PEER_H_ @}*/
index d61cd84..5e112f6 100644 (file)
@@ -12,4 +12,4 @@ libtls_la_SOURCES = \
        tls_writer.h tls_writer.c \
        tls_peer.h tls_peer.c \
        tls_server.h tls_server.c \
-       tls_handshake.h tls.h tls.c
+       tls_handshake.h tls_application.h tls.h tls.c
index f8f7e84..24f442c 100644 (file)
@@ -110,6 +110,11 @@ struct private_tls_t {
         * TLS handshake protocol handler
         */
        tls_handshake_t *handshake;
+
+       /**
+        * TLS application data handler
+        */
+       tls_application_t *application;
 };
 
 METHOD(tls_t, process, status_t,
@@ -164,6 +169,7 @@ METHOD(tls_t, destroy, void,
        this->handshake->destroy(this->handshake);
        this->peer->destroy(this->peer);
        this->server->destroy(this->server);
+       DESTROY_IF(this->application);
 
        free(this);
 }
@@ -172,7 +178,8 @@ METHOD(tls_t, destroy, void,
  * See header
  */
 tls_t *tls_create(bool is_server, identification_t *server,
-                                 identification_t *peer, char *msk_label)
+                                 identification_t *peer, char *msk_label,
+                                 tls_application_t *application)
 {
        private_tls_t *this;
 
@@ -191,6 +198,7 @@ tls_t *tls_create(bool is_server, identification_t *server,
                .version = TLS_1_2,
                .server = server->clone(server),
                .peer = peer->clone(peer),
+               .application = application,
        );
 
        this->crypto = tls_crypto_create(&this->public, msk_label);
@@ -204,7 +212,8 @@ tls_t *tls_create(bool is_server, identification_t *server,
                this->handshake = &tls_peer_create(&this->public, this->crypto,
                                                                                this->peer, this->server)->handshake;
        }
-       this->fragmentation = tls_fragmentation_create(this->handshake);
+       this->fragmentation = tls_fragmentation_create(this->handshake,
+                                                                                                  this->application);
        this->compression = tls_compression_create(this->fragmentation);
        this->protection = tls_protection_create(&this->public, this->compression);
        this->crypto->set_protection(this->crypto, this->protection);
index 923c87a..ea66b76 100644 (file)
@@ -33,6 +33,8 @@ typedef struct tls_t tls_t;
 
 #include <library.h>
 
+#include "tls_application.h"
+
 /**
  * TLS/SSL version numbers
  */
@@ -163,9 +165,11 @@ struct tls_t {
  * @param server               server identity
  * @param peer                 peer identity
  * @param msk_label            ASCII string constant used as seed for MSK PRF
+ * @param application  higher layer application or NULL if none
  * @return                             TLS stack
  */
 tls_t *tls_create(bool is_server, identification_t *server,
-                                 identification_t *peer, char *msk_label);
+                                 identification_t *peer, char *msk_label,
+                                 tls_application_t *application);
 
 #endif /** TLS_H_ @}*/
diff --git a/src/libtls/tls_application.h b/src/libtls/tls_application.h
new file mode 100644 (file)
index 0000000..dacd10e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tls_handshake tls_handshake
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_APPLICATION_H_
+#define TLS_APPLICATION_H_
+
+typedef struct tls_application_t tls_application_t;
+
+#include "tls.h"
+#include "tls_reader.h"
+#include "tls_writer.h"
+
+/**
+ * TLS application data interface.
+ */
+struct tls_application_t {
+
+       /**
+        * Process received TLS application data.
+        *
+        * @param reader        TLS data buffer
+        * @return
+        *                                      - SUCCESS if application completed
+        *                                      - FAILED if application data processing failed
+        *                                      - NEED_MORE if another invocation of process/build needed
+        */
+       status_t (*process)(tls_application_t *this, tls_reader_t *reader);
+
+       /**
+        * Build TLS application data to send out.
+        *
+        * @param writer        TLS data buffer to write to
+        * @return
+        *                                      - SUCCESS if application completed
+        *                                      - FAILED if application data build failed
+        *                                      - NEED_MORE if more data ready for delivery
+        *                                      - INVALID_STATE if more input to process() required
+        */
+       status_t (*build)(tls_application_t *this, tls_writer_t *writer);
+
+       /**
+        * Destroy a tls_application_t.
+        */
+       void (*destroy)(tls_application_t *this);
+};
+
+#endif /** TLS_APPLICATION_H_ @}*/
index f95fe4f..835a3c9 100644 (file)
@@ -55,6 +55,11 @@ struct private_tls_fragmentation_t {
         * Handshake output buffer
         */
        chunk_t output;
+
+       /**
+        * Upper layer application data protocol
+        */
+       tls_application_t *application;
 };
 
 /**
@@ -133,6 +138,33 @@ static status_t process_handshake(private_tls_fragmentation_t *this,
        return NEED_MORE;
 }
 
+/**
+ * Process TLS application data
+ */
+static status_t process_application(private_tls_fragmentation_t *this,
+                                                                       tls_reader_t *reader)
+{
+       while (reader->remaining(reader))
+       {
+               u_int32_t len;
+               chunk_t data;
+
+               if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
+               {
+                       DBG1(DBG_IKE, "TLS fragment has invalid length");
+                       return FAILED;
+               }
+
+               len = reader->remaining(reader);
+               if (!reader->read_data(reader, len, &data))
+               {
+                       return FAILED;
+               }
+               DBG1(DBG_IKE, "received TLS application data: %B", &data);
+       }
+       return NEED_MORE;
+}
+
 METHOD(tls_fragmentation_t, process, status_t,
        private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
 {
@@ -158,8 +190,7 @@ METHOD(tls_fragmentation_t, process, status_t,
                        status = process_handshake(this, reader);
                        break;
                case TLS_APPLICATION_DATA:
-                       /* skip application data */
-                       status = NEED_MORE;
+                       status = process_application(this, reader);
                        break;
                default:
                        DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type);
@@ -175,7 +206,7 @@ METHOD(tls_fragmentation_t, build, status_t,
 {
        tls_handshake_type_t hs_type;
        tls_writer_t *writer, *msg;
-       status_t status;
+       status_t status = INVALID_STATE;
 
        if (this->handshake->cipherspec_changed(this->handshake))
        {
@@ -187,27 +218,47 @@ METHOD(tls_fragmentation_t, build, status_t,
        if (!this->output.len)
        {
                msg = tls_writer_create(64);
-               do
+
+               if (this->handshake->finished(this->handshake))
                {
-                       writer = tls_writer_create(64);
-                       status = this->handshake->build(this->handshake, &hs_type, writer);
-                       switch (status)
+                       if (this->application)
                        {
-                               case NEED_MORE:
-                                       DBG2(DBG_IKE, "sending TLS %N message",
-                                                                  tls_handshake_type_names, hs_type);
-                                       msg->write_uint8(msg, hs_type);
-                                       msg->write_data24(msg, writer->get_buf(writer));
-                                       break;
-                               case INVALID_STATE:
+                               status = this->application->build(this->application, msg);
+                               if (status == INVALID_STATE)
+                               {
                                        this->output = chunk_clone(msg->get_buf(msg));
-                                       break;
-                               default:
-                                       break;
+                                       if (this->output.len)
+                                       {
+                                               DBG2(DBG_IKE, "sending TLS application data: %B",
+                                                                          &this->output);
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       do
+                       {
+                               writer = tls_writer_create(64);
+                               status = this->handshake->build(this->handshake, &hs_type, writer);
+                               switch (status)
+                               {
+                                       case NEED_MORE:
+                                               DBG2(DBG_IKE, "sending TLS %N message",
+                                                                          tls_handshake_type_names, hs_type);
+                                               msg->write_uint8(msg, hs_type);
+                                               msg->write_data24(msg, writer->get_buf(writer));
+                                               break;
+                                       case INVALID_STATE:
+                                               this->output = chunk_clone(msg->get_buf(msg));
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               writer->destroy(writer);
                        }
-                       writer->destroy(writer);
+                       while (status == NEED_MORE);
                }
-               while (status == NEED_MORE);
 
                msg->destroy(msg);
                if (status != INVALID_STATE)
@@ -218,7 +269,8 @@ METHOD(tls_fragmentation_t, build, status_t,
 
        if (this->output.len)
        {
-               *type = TLS_HANDSHAKE;
+               *type = this->handshake->finished(this->handshake) ?
+                                       TLS_APPLICATION_DATA : TLS_HANDSHAKE;
                if (this->output.len <= MAX_TLS_FRAGMENT_LEN)
                {
                        *data = this->output;
@@ -243,7 +295,8 @@ METHOD(tls_fragmentation_t, destroy, void,
 /**
  * See header
  */
-tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
+                                                                                         tls_application_t *application)
 {
        private_tls_fragmentation_t *this;
 
@@ -254,6 +307,7 @@ tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
                        .destroy = _destroy,
                },
                .handshake = handshake,
+               .application = application,
        );
 
        return &this->public;
index e141a33..6adbc36 100644 (file)
@@ -27,6 +27,7 @@ typedef struct tls_fragmentation_t tls_fragmentation_t;
 
 #include "tls.h"
 #include "tls_handshake.h"
+#include "tls_handshake.h"
 
 /**
  * TLS record protocol fragmentation layer.
@@ -70,8 +71,10 @@ struct tls_fragmentation_t {
  * Create a tls_fragmentation instance.
  *
  * @param handshake                    upper layer handshake protocol
+ * @param application          upper layer application data or NULL
  * @return                                     TLS fragmentation layer.
  */
-tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake);
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake,
+                                                                                         tls_application_t *application);
 
 #endif /** TLS_FRAGMENTATION_H_ @}*/
index c079862..3aab3c5 100644 (file)
@@ -74,6 +74,13 @@ struct tls_handshake_t {
        bool (*change_cipherspec)(tls_handshake_t *this);
 
        /**
+        * Check if the finished message was decoded successfully.
+        *
+        * @return                      TRUE if finished message was decoded successfully
+        */
+       bool (*finished)(tls_handshake_t *this);
+
+       /**
         * Destroy a tls_handshake_t.
         */
        void (*destroy)(tls_handshake_t *this);
index 221b629..79f97ae 100644 (file)
@@ -621,6 +621,12 @@ METHOD(tls_handshake_t, change_cipherspec, bool,
        return FALSE;
 }
 
+METHOD(tls_handshake_t, finished, bool,
+       private_tls_peer_t *this)
+{
+       return this->state == STATE_COMPLETE;
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_peer_t *this)
 {
@@ -644,6 +650,7 @@ tls_peer_t *tls_peer_create(tls_t *tls, tls_crypto_t *crypto,
                        .build = _build,
                        .cipherspec_changed = _cipherspec_changed,
                        .change_cipherspec = _change_cipherspec,
+                       .finished = _finished,
                        .destroy = _destroy,
                },
                .state = STATE_INIT,
index 8d2c961..673b201 100644 (file)
@@ -583,6 +583,12 @@ METHOD(tls_handshake_t, change_cipherspec, bool,
        return FALSE;
 }
 
+METHOD(tls_handshake_t, finished, bool,
+       private_tls_server_t *this)
+{
+       return this->state == STATE_FINISHED_SENT;
+}
+
 METHOD(tls_handshake_t, destroy, void,
        private_tls_server_t *this)
 {
@@ -606,6 +612,7 @@ tls_server_t *tls_server_create(tls_t *tls, tls_crypto_t *crypto,
                        .build = _build,
                        .cipherspec_changed = _cipherspec_changed,
                        .change_cipherspec = _change_cipherspec,
+                       .finished = _finished,
                        .destroy = _destroy,
                },
                .tls = tls,