aboutsummaryrefslogtreecommitdiffstats
path: root/src/charon/plugins/eap_tls
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2010-02-01 15:12:18 +0100
committerMartin Willi <martin@revosec.ch>2010-08-03 15:39:24 +0200
commit3a1640dea1dda9a6fe79a69428c7b4e24724a1cd (patch)
treec76223386576aa343044cc6b96f74ccc7cd26e90 /src/charon/plugins/eap_tls
parent4ef946dd64876df4ffabf49d4d7cbf42c6958008 (diff)
downloadstrongswan-3a1640dea1dda9a6fe79a69428c7b4e24724a1cd.tar.bz2
strongswan-3a1640dea1dda9a6fe79a69428c7b4e24724a1cd.tar.xz
Implemented a tls_writer class to simplify TLS data generation
Diffstat (limited to 'src/charon/plugins/eap_tls')
-rw-r--r--src/charon/plugins/eap_tls/Makefile.am1
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_fragmentation.c68
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_handshake.h5
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_peer.c76
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_server.c2
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_writer.c237
-rw-r--r--src/charon/plugins/eap_tls/tls/tls_writer.h136
7 files changed, 451 insertions, 74 deletions
diff --git a/src/charon/plugins/eap_tls/Makefile.am b/src/charon/plugins/eap_tls/Makefile.am
index f5870faaf..75e9cfbaa 100644
--- a/src/charon/plugins/eap_tls/Makefile.am
+++ b/src/charon/plugins/eap_tls/Makefile.am
@@ -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
diff --git a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
index e23b96fea..b9d3a75a3 100644
--- a/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
+++ b/src/charon/plugins/eap_tls/tls/tls_fragmentation.c
@@ -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;
};
/**
@@ -63,15 +68,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
*/
static status_t process_handshake(private_tls_fragmentation_t *this,
@@ -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);
}
diff --git a/src/charon/plugins/eap_tls/tls/tls_handshake.h b/src/charon/plugins/eap_tls/tls/tls_handshake.h
index cfdeae5d7..7031158d4 100644
--- a/src/charon/plugins/eap_tls/tls/tls_handshake.h
+++ b/src/charon/plugins/eap_tls/tls/tls_handshake.h
@@ -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.
diff --git a/src/charon/plugins/eap_tls/tls/tls_peer.c b/src/charon/plugins/eap_tls/tls/tls_peer.c
index bd84ff81c..3828ead29 100644
--- a/src/charon/plugins/eap_tls/tls/tls_peer.c
+++ b/src/charon/plugins/eap_tls/tls/tls_peer.c
@@ -186,81 +186,53 @@ METHOD(tls_handshake_t, process, status_t,
}
/**
- * 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;
}
diff --git a/src/charon/plugins/eap_tls/tls/tls_server.c b/src/charon/plugins/eap_tls/tls/tls_server.c
index 3a5d00334..0828e81a1 100644
--- a/src/charon/plugins/eap_tls/tls/tls_server.c
+++ b/src/charon/plugins/eap_tls/tls/tls_server.c
@@ -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
index 000000000..f1d9d790e
--- /dev/null
+++ b/src/charon/plugins/eap_tls/tls/tls_writer.c
@@ -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
index 000000000..ce8ba6a6e
--- /dev/null
+++ b/src/charon/plugins/eap_tls/tls/tls_writer.h
@@ -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_ @}*/