]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Implemented a tls_writer class to simplify TLS data generation
authorMartin Willi <martin@revosec.ch>
Mon, 1 Feb 2010 14:12:18 +0000 (15:12 +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_fragmentation.c
src/charon/plugins/eap_tls/tls/tls_handshake.h
src/charon/plugins/eap_tls/tls/tls_peer.c
src/charon/plugins/eap_tls/tls/tls_server.c
src/charon/plugins/eap_tls/tls/tls_writer.c [new file with mode: 0644]
src/charon/plugins/eap_tls/tls/tls_writer.h [new file with mode: 0644]

index f5870faafa3fe23e3d432490d53292e212dfe7ca..75e9cfbaa07a7d179247a1818b8be2579ce4d100 100644 (file)
@@ -12,6 +12,7 @@ libstrongswan_eap_tls_la_SOURCES = eap_tls_plugin.h eap_tls_plugin.c \
        tls/tls_fragmentation.h tls/tls_fragmentation.c \
        tls/tls_crypto.h tls/tls_crypto.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
index e23b96feaf7afc6dcc2597678ae3bb9951833249..b9d3a75a39da579948aebcb59e8f03980dc8eab5 100644 (file)
@@ -50,6 +50,11 @@ struct private_tls_fragmentation_t {
         * Currently processed handshake message type
         */
        tls_handshake_type_t type;
+
+       /**
+        * Handshake output buffer
+        */
+       chunk_t output;
 };
 
 /**
@@ -62,15 +67,6 @@ struct private_tls_fragmentation_t {
  */
 #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
  */
@@ -171,27 +167,61 @@ METHOD(tls_fragmentation_t, process, status_t,
 METHOD(tls_fragmentation_t, build, status_t,
        private_tls_fragmentation_t *this, tls_content_type_t *type, chunk_t *data)
 {
-       tls_handshake_header_t header;
        tls_handshake_type_t hs_type;
-       chunk_t hs_data;
+       tls_writer_t *writer, *msg;
        status_t status;
 
-       status = this->handshake->build(this->handshake, &hs_type, &hs_data);
-       if (status != 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)
        {
-               return status;
+               *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;
        }
-       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;
+       return status;
 }
 
 METHOD(tls_fragmentation_t, destroy, void,
        private_tls_fragmentation_t *this)
 {
        free(this->input.ptr);
+       free(this->output.ptr);
        free(this);
 }
 
index cfdeae5d7924a47c47d26e0ab56f2a531d78070c..7031158d4aa80cca6a49c3847a5dfde03fb90b3e 100644 (file)
@@ -25,6 +25,7 @@ typedef struct tls_handshake_t tls_handshake_t;
 
 #include "tls.h"
 #include "tls_reader.h"
+#include "tls_writer.h"
 
 /**
  * TLS handshake state machine interface.
@@ -48,7 +49,7 @@ struct tls_handshake_t {
         * Build TLS handshake messages to send out.
         *
         * @param type          type of created handshake message
-        * @param data          allocated TLS handshake message data
+        * @param writer        TLS data buffer to write to
         * @return
         *                                      - SUCCESS if handshake complete
         *                                      - FAILED if handshake failed
@@ -56,7 +57,7 @@ struct tls_handshake_t {
         *                                      - INVALID_STATE if more input to process() required
         */
        status_t (*build)(tls_handshake_t *this,
-                                         tls_handshake_type_t *type, chunk_t *data);
+                                         tls_handshake_type_t *type, tls_writer_t *writer);
 
        /**
         * Destroy a tls_handshake_t.
index bd84ff81cf26828dc12234762e16864ad8d63e71..3828ead294a925925f91966d52beda4ddcc782e6 100644 (file)
@@ -185,82 +185,54 @@ METHOD(tls_handshake_t, process, status_t,
        return NEED_MORE;
 }
 
-/**
- * Build the Client Hello using a given set of ciphers
- */
-static chunk_t build_hello(private_tls_peer_t *this,
-                                                  int count, tls_cipher_suite_t *suite, rng_t *rng)
-{
-       int i;
-
-       struct __attribute__((packed)) {
-               u_int16_t version;
-               struct __attribute__((packed)) {
-                       u_int32_t gmt;
-                       u_int8_t bytes[28];
-               } random;
-               struct __attribute__((packed)) {
-                       /* never send a session identifier */
-                       u_int8_t len;
-                       u_int8_t id[0];
-               } session;
-               struct __attribute__((packed)) {
-                       u_int16_t len;
-                       u_int16_t suite[count];
-               } cipher;
-               struct __attribute__((packed)) {
-                       /* currently NULL compression only */
-                       u_int8_t len;
-                       u_int8_t method[1];
-               } compression;
-               u_int8_t extensions[0];
-       } hello;
-
-       htoun16(&hello.session.len, 0);
-       htoun16(&hello.version, this->tls->get_version(this->tls));
-       htoun32(&hello.random.gmt, time(NULL));
-       rng->get_bytes(rng, sizeof(hello.random.bytes), (char*)&hello.random.bytes);
-       htoun16(&hello.cipher.len, count * 2);
-       for (i = 0; i < count; i++)
-       {
-               htoun16(&hello.cipher.suite[i], suite[i]);
-       }
-       hello.compression.len = 1;
-       hello.compression.method[0] = 0;
-       return chunk_clone(chunk_create((char*)&hello, sizeof(hello)));
-}
-
 /**
  * Send a client hello
  */
 static status_t send_hello(private_tls_peer_t *this,
-                                                  tls_handshake_type_t *type, chunk_t *data)
+                                                  tls_handshake_type_t *type, tls_writer_t *writer)
 {
        tls_cipher_suite_t *suite;
-       int count;
+       int count, i;
        rng_t *rng;
+       char random[28];
 
        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
        if (!rng)
        {
                return FAILED;
        }
+       rng->get_bytes(rng, sizeof(random), random);
+       rng->destroy(rng);
+
+       writer->write_uint16(writer, this->tls->get_version(this->tls));
+       writer->write_uint32(writer, time(NULL));
+       writer->write_data(writer, chunk_from_thing(random));
+       /* session identifier => none */
+       writer->write_data8(writer, chunk_empty);
+
        count = this->crypto->get_cipher_suites(this->crypto, &suite);
-       *data = build_hello(this, count, suite, rng);
-       *type = TLS_CLIENT_HELLO;
+       writer->write_uint16(writer, count * 2);
+       for (i = 0; i < count; i++)
+       {
+               writer->write_uint16(writer, suite[i]);
+       }
        free(suite);
-       rng->destroy(rng);
+       /* NULL compression only */
+       writer->write_uint8(writer, 1);
+       writer->write_uint8(writer, 0);
+
+       *type = TLS_CLIENT_HELLO;
        this->state = STATE_HELLO_SENT;
        return NEED_MORE;
 }
 
 METHOD(tls_handshake_t, build, status_t,
-       private_tls_peer_t *this, tls_handshake_type_t *type, chunk_t *data)
+       private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
 {
        switch (this->state)
        {
                case STATE_INIT:
-                       return send_hello(this, type, data);
+                       return send_hello(this, type, writer);
                default:
                        return INVALID_STATE;
        }
index 3a5d003342293ea20a2257308361dbf77e1aff68..0828e81a103708b1f934f2115135ad2b4d84111a 100644 (file)
@@ -48,7 +48,7 @@ METHOD(tls_handshake_t, process, status_t,
 }
 
 METHOD(tls_handshake_t, build, status_t,
-       private_tls_server_t *this, tls_handshake_type_t *type, chunk_t *data)
+       private_tls_server_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
 {
        return INVALID_STATE;
 }
diff --git a/src/charon/plugins/eap_tls/tls/tls_writer.c b/src/charon/plugins/eap_tls/tls/tls_writer.c
new file mode 100644 (file)
index 0000000..f1d9d79
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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/charon/plugins/eap_tls/tls/tls_writer.h b/src/charon/plugins/eap_tls/tls/tls_writer.h
new file mode 100644 (file)
index 0000000..ce8ba6a
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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_ @}*/