]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Added stubs for handshake handling, server and peer variants
authorMartin Willi <martin@revosec.ch>
Mon, 25 Jan 2010 09:44:35 +0000 (10:44 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 3 Aug 2010 13:39:24 +0000 (15:39 +0200)
src/charon/plugins/eap_tls/Makefile.am
src/charon/plugins/eap_tls/tls/tls.c
src/charon/plugins/eap_tls/tls/tls_fragmentation.c
src/charon/plugins/eap_tls/tls/tls_fragmentation.h
src/charon/plugins/eap_tls/tls/tls_handshake.h [new file with mode: 0644]
src/charon/plugins/eap_tls/tls/tls_peer.c [new file with mode: 0644]
src/charon/plugins/eap_tls/tls/tls_peer.h [new file with mode: 0644]
src/charon/plugins/eap_tls/tls/tls_server.c [new file with mode: 0644]
src/charon/plugins/eap_tls/tls/tls_server.h [new file with mode: 0644]

index 25afad2e2b8afff9242c2e21877975fa682bfae4..a69f8857c2fe6e98cc6f0c6b961150d1763f9157 100644 (file)
@@ -9,5 +9,8 @@ libstrongswan_eap_tls_la_SOURCES = eap_tls_plugin.h eap_tls_plugin.c \
        eap_tls.h eap_tls.c tls/tls.h tls/tls.c \
        tls/tls_protection.h tls/tls_protection.c \
        tls/tls_compression.h tls/tls_compression.c \
-       tls/tls_fragmentation.h tls/tls_fragmentation.c
+       tls/tls_fragmentation.h tls/tls_fragmentation.c \
+       tls/tls_peer.h tls/tls_peer.c \
+       tls/tls_server.h tls/tls_server.c \
+       tls/tls_handshake.h
 libstrongswan_eap_tls_la_LDFLAGS = -module -avoid-version
index 5bba59792aad07620ffaab51c099552f9eff3edc..9c11bc796cf9cd7329dbb729b76fdab155a24a27 100644 (file)
@@ -18,6 +18,8 @@
 #include "tls_protection.h"
 #include "tls_compression.h"
 #include "tls_fragmentation.h"
+#include "tls_server.h"
+#include "tls_peer.h"
 
 #include <daemon.h>
 
@@ -83,6 +85,11 @@ struct private_tls_t {
         * TLS record fragmentation layer
         */
        tls_fragmentation_t *fragmentation;
+
+       /**
+        * TLS handshake protocol handler
+        */
+       tls_handshake_t *handshake;
 };
 
 METHOD(tls_t, process, status_t,
@@ -103,6 +110,7 @@ METHOD(tls_t, destroy, void,
        this->protection->destroy(this->protection);
        this->compression->destroy(this->compression);
        this->fragmentation->destroy(this->fragmentation);
+       this->handshake->destroy(this->handshake);
 
        free(this);
 }
@@ -123,7 +131,15 @@ tls_t *tls_create(bool is_server)
                .is_server = is_server,
        );
 
-       this->fragmentation = tls_fragmentation_create();
+       if (is_server)
+       {
+               this->handshake = &tls_server_create()->handshake;
+       }
+       else
+       {
+               this->handshake = &tls_peer_create()->handshake;
+       }
+       this->fragmentation = tls_fragmentation_create(this->handshake);
        this->compression = tls_compression_create(this->fragmentation);
        this->protection = tls_protection_create(this->compression);
 
index c1cfa0559374c4d8f4fad3c744a3fa95e660d3db..0d38e48902fe0e6f2c943071b95a5166c1e7071c 100644 (file)
@@ -28,30 +28,157 @@ struct private_tls_fragmentation_t {
         * Public tls_fragmentation_t interface.
         */
        tls_fragmentation_t public;
+
+       /**
+        * Upper layer handshake protocol
+        */
+       tls_handshake_t *handshake;
+
+       /**
+        * Handshake input buffer
+        */
+       chunk_t input;
+
+       /**
+        * Position in input buffer
+        */
+       size_t inpos;
+
+       /**
+        * Currently processed handshake message type
+        */
+       tls_handshake_type_t type;
 };
 
+/**
+ * Maximum size of a TLS fragment
+ */
+#define MAX_TLS_FRAGMENT_LEN 16384
+
+/**
+ * Maximum size of a TLS handshake message we accept
+ */
+#define MAX_TLS_HANDSHAKE_LEN 65536
+
+/**
+ * TLS handshake message header
+ */
+typedef union  {
+       u_int8_t type;
+       /* 24bit length field */
+       u_int32_t length;
+} tls_handshake_header_t;
+
+/**
+ * Process TLS handshake protocol data
+ */
+static status_t process_handshake(private_tls_fragmentation_t *this,
+                                                                 chunk_t data)
+{
+       while (data.len)
+       {
+               u_int32_t len;
+               status_t status;
+               tls_handshake_header_t *hdr;
+
+               if (data.len == 0 || data.len > MAX_TLS_FRAGMENT_LEN)
+               {
+                       DBG1(DBG_IKE, "TLS fragment has invalid length");
+                       return FAILED;
+               }
+
+               if (this->input.len == 0)
+               {       /* new handshake message */
+                       if (data.len < sizeof(tls_handshake_header_t))
+                       {
+                               DBG1(DBG_IKE, "initial TLS fragment too short %B", &data);
+                               return FAILED;
+                       }
+                       hdr = (tls_handshake_header_t*)data.ptr;
+                       len = untoh32(&hdr->length) & 0x00FFFFFF;
+                       this->type = hdr->type;
+                       if (len > MAX_TLS_HANDSHAKE_LEN)
+                       {
+                               DBG1(DBG_IKE, "TLS handshake message exceeds maximum length");
+                               return FAILED;
+                       }
+                       this->input = len ? chunk_alloc(len) : chunk_empty;
+                       this->inpos = 0;
+                       data = chunk_skip(data, sizeof(tls_handshake_header_t));
+               }
+
+               len = min(this->input.len - this->inpos, data.len);
+               memcpy(this->input.ptr + this->inpos, data.ptr, len);
+               this->inpos += len;
+               data = chunk_skip(data, len);
+
+               if (this->input.len == this->inpos)
+               {       /* message completely defragmented, process */
+                       status = this->handshake->process(this->handshake,
+                                                                                         this->type, this->input);
+                       chunk_free(&this->input);
+                       if (status != NEED_MORE)
+                       {
+                               return status;
+                       }
+               }
+       }
+       return NEED_MORE;
+}
+
 METHOD(tls_fragmentation_t, process, status_t,
        private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
 {
-       return NEED_MORE;
+       switch (type)
+       {
+               case TLS_CHANGE_CIPHER_SPEC:
+                       /* TODO: handle ChangeCipherSpec */
+                       return FAILED;
+               case TLS_ALERT:
+                       /* TODO: handle Alert */
+                       return FAILED;
+               case TLS_HANDSHAKE:
+                       return process_handshake(this, data);
+               case TLS_APPLICATION_DATA:
+                       /* skip application data */
+                       return NEED_MORE;
+               default:
+                       DBG1(DBG_IKE, "received unknown TLS content type %d, ignored", type);
+                       return NEED_MORE;
+       }
 }
 
 METHOD(tls_fragmentation_t, build, status_t,
        private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
 {
-       return INVALID_STATE;
+       tls_handshake_header_t header;
+       tls_handshake_type_t hs_type;
+       chunk_t hs_data;
+       status_t status;
+
+       status = this->handshake->build(this->handshake, &hs_type, &hs_data);
+       if (status != NEED_MORE)
+       {
+               return status;
+       }
+       htoun32(&header.length, hs_data.len);
+       header.type |= hs_type;
+       *data = chunk_cat("cm", chunk_from_thing(header), hs_data);
+       *type = TLS_HANDSHAKE;
+       return NEED_MORE;
 }
 
 METHOD(tls_fragmentation_t, destroy, void,
        private_tls_fragmentation_t *this)
 {
+       free(this->input.ptr);
        free(this);
 }
 
 /**
  * See header
  */
-tls_fragmentation_t *tls_fragmentation_create()
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake)
 {
        private_tls_fragmentation_t *this;
 
@@ -61,6 +188,7 @@ tls_fragmentation_t *tls_fragmentation_create()
                        .build = _build,
                        .destroy = _destroy,
                },
+               .handshake = handshake,
        );
 
        return &this->public;
index 866a9708b4964fe238399f044875a88778ff8145..61bf5488e248744ed99e33476a9c2fe630916ed7 100644 (file)
@@ -26,6 +26,7 @@ typedef struct tls_fragmentation_t tls_fragmentation_t;
 #include <library.h>
 
 #include "tls.h"
+#include "tls_handshake.h"
 
 /**
  * TLS record protocol fragmentation layer.
@@ -68,8 +69,9 @@ struct tls_fragmentation_t {
 /**
  * Create a tls_fragmentation instance.
  *
+ * @param handshake                    upper layer handshake protocol
  * @return                                     TLS fragmentation layer.
  */
-tls_fragmentation_t *tls_fragmentation_create();
+tls_fragmentation_t *tls_fragmentation_create(tls_handshake_t *handshake);
 
 #endif /** TLS_FRAGMENTATION_H_ @}*/
diff --git a/src/charon/plugins/eap_tls/tls/tls_handshake.h b/src/charon/plugins/eap_tls/tls/tls_handshake.h
new file mode 100644 (file)
index 0000000..28174cf
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tls_handshake tls_handshake
+ * @{ @ingroup tls
+ */
+
+#ifndef TLS_HANDSHAKE_H_
+#define TLS_HANDSHAKE_H_
+
+typedef struct tls_handshake_t tls_handshake_t;
+
+#include "tls.h"
+
+/**
+ * TLS handshake state machine interface.
+ */
+struct tls_handshake_t {
+
+       /**
+        * Process received TLS handshake message.
+        *
+        * @param type          TLS handshake message type
+        * @param data          TLS handshake data
+        * @return
+        *                                      - SUCCESS if handshake complete
+        *                                      - FAILED if handshake failed
+        *                                      - NEED_MORE if another invocation of process/build needed
+        */
+       status_t (*process)(tls_handshake_t *this,
+                                               tls_handshake_type_t type, chunk_t data);
+
+       /**
+        * Build TLS handshake messages to send out.
+        *
+        * @param type          type of created handshake message
+        * @param data          allocated TLS handshake message data
+        * @return
+        *                                      - SUCCESS if handshake complete
+        *                                      - FAILED if handshake failed
+        *                                      - NEED_MORE if more messages ready for delivery
+        *                                      - INVALID_STATE if more input to process() required
+        */
+       status_t (*build)(tls_handshake_t *this,
+                                         tls_handshake_type_t *type, chunk_t *data);
+
+       /**
+        * Destroy a tls_handshake_t.
+        */
+       void (*destroy)(tls_handshake_t *this);
+};
+
+#endif /** TLS_HANDSHAKE_H_ @}*/
diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.c b/src/charon/plugins/eap_tls/tls/tls_peer.c
new file mode 100644 (file)
index 0000000..3fc3d6a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "tls_peer.h"
+
+#include <daemon.h>
+
+#include <time.h>
+
+typedef struct private_tls_peer_t private_tls_peer_t;
+
+/**
+ * Private data of an tls_peer_t object.
+ */
+struct private_tls_peer_t {
+
+       /**
+        * Public tls_peer_t interface.
+        */
+       tls_peer_t public;
+};
+
+METHOD(tls_handshake_t, process, status_t,
+       private_tls_peer_t *this, tls_handshake_type_t type, chunk_t data)
+{
+       return NEED_MORE;
+}
+
+METHOD(tls_handshake_t, build, status_t,
+       private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data)
+{
+       return INVALID_STATE;
+}
+
+METHOD(tls_handshake_t, destroy, void,
+       private_tls_peer_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_peer_t *tls_peer_create()
+{
+       private_tls_peer_t *this;
+
+       INIT(this,
+               .public.handshake = {
+                       .process = _process,
+                       .build = _build,
+                       .destroy = _destroy,
+               },
+       );
+
+       return &this->public;
+}
diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.h b/src/charon/plugins/eap_tls/tls/tls_peer.h
new file mode 100644 (file)
index 0000000..036e418
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tls_peer tls_peer
+ * @{ @ingroup tls
+ */
+
+#ifndef TLS_PEER_H_
+#define TLS_PEER_H_
+
+typedef struct tls_peer_t tls_peer_t;
+
+#include "tls_handshake.h"
+
+/**
+ * TLS handshake protocol handler as peer.
+ */
+struct tls_peer_t {
+
+       /**
+        * Implements the TLS handshake protocol handler.
+        */
+       tls_handshake_t handshake;
+};
+
+/**
+ * Create a tls_peer instance.
+ */
+tls_peer_t *tls_peer_create();
+
+#endif /** TLS_PEER_H_ @}*/
diff --git a/src/charon/plugins/eap_tls/tls/tls_server.c b/src/charon/plugins/eap_tls/tls/tls_server.c
new file mode 100644 (file)
index 0000000..63a1e00
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "tls_server.h"
+
+#include <daemon.h>
+
+typedef struct private_tls_server_t private_tls_server_t;
+
+/**
+ * Private data of an tls_server_t object.
+ */
+struct private_tls_server_t {
+
+       /**
+        * Public tls_server_t interface.
+        */
+       tls_server_t public;
+};
+
+
+METHOD(tls_handshake_t, process, status_t,
+       private_tls_server_t *this, tls_handshake_type_t type, chunk_t data)
+{
+       return NEED_MORE;
+}
+
+METHOD(tls_handshake_t, build, status_t,
+       private_tls_server_t *this, tls_handshake_type_t *type, chunk_t *data)
+{
+       return INVALID_STATE;
+}
+
+METHOD(tls_handshake_t, destroy, void,
+       private_tls_server_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+tls_server_t *tls_server_create()
+{
+       private_tls_server_t *this;
+
+       INIT(this,
+               .public.handshake = {
+                       .process = _process,
+                       .build = _build,
+                       .destroy = _destroy,
+               },
+       );
+
+       return &this->public;
+}
diff --git a/src/charon/plugins/eap_tls/tls/tls_server.h b/src/charon/plugins/eap_tls/tls/tls_server.h
new file mode 100644 (file)
index 0000000..12b822b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup tls_server tls_server
+ * @{ @ingroup tls
+ */
+
+#ifndef TLS_SERVER_H_
+#define TLS_SERVER_H_
+
+typedef struct tls_server_t tls_server_t;
+
+#include "tls_handshake.h"
+
+/**
+ * TLS handshake protocol handler as peer.
+ */
+struct tls_server_t {
+
+       /**
+        * Implements the TLS handshake protocol handler.
+        */
+       tls_handshake_t handshake;
+};
+
+/**
+ * Create a tls_server instance.
+ */
+tls_server_t *tls_server_create();
+
+#endif /** TLS_SERVER_H_ @}*/