summaryrefslogtreecommitdiff
path: root/src/libtls
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
committerYves-Alexis Perez <corsac@corsac.net>2012-06-28 21:16:07 +0200
commitb34738ed08c2227300d554b139e2495ca5da97d6 (patch)
tree62f33b52820f2e49f0e53c0f8c636312037c8054 /src/libtls
parent0a9d51a49042a68daa15b0c74a2b7f152f52606b (diff)
downloadvyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.tar.gz
vyos-strongswan-b34738ed08c2227300d554b139e2495ca5da97d6.zip
Imported Upstream version 4.6.4
Diffstat (limited to 'src/libtls')
-rw-r--r--src/libtls/Makefile.am5
-rw-r--r--src/libtls/Makefile.in97
-rw-r--r--src/libtls/tls.c12
-rw-r--r--src/libtls/tls.h9
-rw-r--r--src/libtls/tls_alert.h2
-rw-r--r--src/libtls/tls_application.h8
-rw-r--r--src/libtls/tls_cache.c237
-rw-r--r--src/libtls/tls_cache.h78
-rw-r--r--src/libtls/tls_compression.h4
-rw-r--r--src/libtls/tls_crypto.c174
-rw-r--r--src/libtls/tls_crypto.h60
-rw-r--r--src/libtls/tls_fragmentation.c50
-rw-r--r--src/libtls/tls_fragmentation.h4
-rw-r--r--src/libtls/tls_handshake.h22
-rw-r--r--src/libtls/tls_peer.c169
-rw-r--r--src/libtls/tls_protection.c57
-rw-r--r--src/libtls/tls_protection.h4
-rw-r--r--src/libtls/tls_reader.c200
-rw-r--r--src/libtls/tls_reader.h131
-rw-r--r--src/libtls/tls_server.c209
-rw-r--r--src/libtls/tls_socket.c115
-rw-r--r--src/libtls/tls_socket.h22
-rw-r--r--src/libtls/tls_writer.c237
-rw-r--r--src/libtls/tls_writer.h136
24 files changed, 1012 insertions, 1030 deletions
diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am
index a58e783d7..4cc1a1bdb 100644
--- a/src/libtls/Makefile.am
+++ b/src/libtls/Makefile.am
@@ -1,7 +1,7 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan
-noinst_LTLIBRARIES = libtls.la
+ipseclib_LTLIBRARIES = libtls.la
libtls_la_SOURCES = \
tls_protection.h tls_protection.c \
tls_compression.h tls_compression.c \
@@ -9,10 +9,9 @@ libtls_la_SOURCES = \
tls_alert.h tls_alert.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_socket.h tls_socket.c \
tls_eap.h tls_eap.c \
+ tls_cache.h tls_cache.c \
tls_peer.h tls_peer.c \
tls_server.h tls_server.c \
tls_handshake.h tls_application.h tls.h tls.c
diff --git a/src/libtls/Makefile.in b/src/libtls/Makefile.in
index 5a1aa81c0..844b65156 100644
--- a/src/libtls/Makefile.in
+++ b/src/libtls/Makefile.in
@@ -51,12 +51,34 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
mkinstalldirs = $(install_sh) -d
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
-LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(ipseclibdir)"
+LTLIBRARIES = $(ipseclib_LTLIBRARIES)
libtls_la_LIBADD =
am_libtls_la_OBJECTS = tls_protection.lo tls_compression.lo \
tls_fragmentation.lo tls_alert.lo tls_crypto.lo tls_prf.lo \
- tls_reader.lo tls_writer.lo tls_socket.lo tls_eap.lo \
- tls_peer.lo tls_server.lo tls.lo
+ tls_socket.lo tls_eap.lo tls_cache.lo tls_peer.lo \
+ tls_server.lo tls.lo
libtls_la_OBJECTS = $(am_libtls_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -167,6 +189,9 @@ am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
+attest_plugins = @attest_plugins@
+axis2c_CFLAGS = @axis2c_CFLAGS@
+axis2c_LIBS = @axis2c_LIBS@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -175,6 +200,7 @@ build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
c_plugins = @c_plugins@
+clearsilver_LIBS = @clearsilver_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
dbusservicedir = @dbusservicedir@
@@ -191,11 +217,13 @@ host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
+imcvdir = @imcvdir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
ipsecgroup = @ipsecgroup@
+ipseclibdir = @ipseclibdir@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -239,6 +267,7 @@ sharedstatedir = @sharedstatedir@
soup_CFLAGS = @soup_CFLAGS@
soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
+starter_plugins = @starter_plugins@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
@@ -250,7 +279,7 @@ urandom_device = @urandom_device@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
INCLUDES = -I$(top_srcdir)/src/libstrongswan
-noinst_LTLIBRARIES = libtls.la
+ipseclib_LTLIBRARIES = libtls.la
libtls_la_SOURCES = \
tls_protection.h tls_protection.c \
tls_compression.h tls_compression.c \
@@ -258,10 +287,9 @@ libtls_la_SOURCES = \
tls_alert.h tls_alert.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_socket.h tls_socket.c \
tls_eap.h tls_eap.c \
+ tls_cache.h tls_cache.c \
tls_peer.h tls_peer.c \
tls_server.h tls_server.c \
tls_handshake.h tls_application.h tls.h tls.c
@@ -300,17 +328,39 @@ $(top_srcdir)/configure: $(am__configure_deps)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
+install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(ipseclibdir)" || $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)"
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \
+ }
+
+uninstall-ipseclibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \
+ done
-clean-noinstLTLIBRARIES:
- -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
- @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+clean-ipseclibLTLIBRARIES:
+ -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES)
+ @list='$(ipseclib_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
libtls.la: $(libtls_la_OBJECTS) $(libtls_la_DEPENDENCIES)
- $(LINK) $(libtls_la_OBJECTS) $(libtls_la_LIBADD) $(LIBS)
+ $(LINK) -rpath $(ipseclibdir) $(libtls_la_OBJECTS) $(libtls_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -320,6 +370,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_alert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_compression.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_crypto.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_eap.Plo@am__quote@
@@ -327,10 +378,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_peer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_prf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_protection.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_reader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_server.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_socket.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_writer.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -445,6 +494,9 @@ check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES)
installdirs:
+ for dir in "$(DESTDIR)$(ipseclibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
@@ -472,7 +524,7 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
-clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
@@ -493,7 +545,7 @@ info: info-am
info-am:
-install-data-am:
+install-data-am: install-ipseclibLTLIBRARIES
install-dvi: install-dvi-am
@@ -539,22 +591,23 @@ ps: ps-am
ps-am:
-uninstall-am:
+uninstall-am: uninstall-ipseclibLTLIBRARIES
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
- clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ clean-ipseclibLTLIBRARIES clean-libtool ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags uninstall uninstall-am
+ install-html-am install-info install-info-am \
+ install-ipseclibLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/libtls/tls.c b/src/libtls/tls.c
index ea527b122..2bcaffbc8 100644
--- a/src/libtls/tls.c
+++ b/src/libtls/tls.c
@@ -192,6 +192,14 @@ struct private_tls_t {
size_t headpos;
};
+/**
+ * Described in header.
+ */
+void libtls_init(void)
+{
+ /* empty */
+}
+
METHOD(tls_t, process, status_t,
private_tls_t *this, void *buf, size_t buflen)
{
@@ -429,7 +437,7 @@ METHOD(tls_t, destroy, void,
*/
tls_t *tls_create(bool is_server, identification_t *server,
identification_t *peer, tls_purpose_t purpose,
- tls_application_t *application)
+ tls_application_t *application, tls_cache_t *cache)
{
private_tls_t *this;
@@ -464,7 +472,7 @@ tls_t *tls_create(bool is_server, identification_t *server,
.purpose = purpose,
);
- this->crypto = tls_crypto_create(&this->public);
+ this->crypto = tls_crypto_create(&this->public, cache);
this->alert = tls_alert_create();
if (is_server)
{
diff --git a/src/libtls/tls.h b/src/libtls/tls.h
index 54b0621b5..e22b0facc 100644
--- a/src/libtls/tls.h
+++ b/src/libtls/tls.h
@@ -35,6 +35,7 @@ typedef struct tls_t tls_t;
#include <library.h>
#include "tls_application.h"
+#include "tls_cache.h"
/**
* TLS/SSL version numbers
@@ -228,6 +229,11 @@ struct tls_t {
};
/**
+ * Dummy libtls initialization function needed for integrity test
+ */
+void libtls_init(void);
+
+/**
* Create a tls instance.
*
* @param is_server TRUE to act as server, FALSE for client
@@ -235,10 +241,11 @@ struct tls_t {
* @param peer peer identity, NULL for no client authentication
* @param purpose purpose this TLS stack instance is used for
* @param application higher layer application or NULL if none
+ * @param cache session cache to use, or NULL
* @return TLS stack
*/
tls_t *tls_create(bool is_server, identification_t *server,
identification_t *peer, tls_purpose_t purpose,
- tls_application_t *application);
+ tls_application_t *application, tls_cache_t *cache);
#endif /** TLS_H_ @}*/
diff --git a/src/libtls/tls_alert.h b/src/libtls/tls_alert.h
index 95ba4d91b..8ce50f83d 100644
--- a/src/libtls/tls_alert.h
+++ b/src/libtls/tls_alert.h
@@ -98,7 +98,7 @@ struct tls_alert_t {
/**
* Did a fatal alert occur?.
*
- * @return TRUE if a fatal alert has occured
+ * @return TRUE if a fatal alert has occurred
*/
bool (*fatal)(tls_alert_t *this);
diff --git a/src/libtls/tls_application.h b/src/libtls/tls_application.h
index b54a25e22..bd839fbb6 100644
--- a/src/libtls/tls_application.h
+++ b/src/libtls/tls_application.h
@@ -23,8 +23,8 @@
typedef struct tls_application_t tls_application_t;
-#include "tls_reader.h"
-#include "tls_writer.h"
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
/**
* TLS application data interface.
@@ -40,7 +40,7 @@ struct tls_application_t {
* - 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);
+ status_t (*process)(tls_application_t *this, bio_reader_t *reader);
/**
* Build TLS application data to send out.
@@ -52,7 +52,7 @@ struct tls_application_t {
* - 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);
+ status_t (*build)(tls_application_t *this, bio_writer_t *writer);
/**
* Destroy a tls_application_t.
diff --git a/src/libtls/tls_cache.c b/src/libtls/tls_cache.c
new file mode 100644
index 000000000..a89201ad7
--- /dev/null
+++ b/src/libtls/tls_cache.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 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_cache.h"
+
+#include <debug.h>
+#include <utils/linked_list.h>
+#include <utils/hashtable.h>
+#include <threading/rwlock.h>
+
+typedef struct private_tls_cache_t private_tls_cache_t;
+
+/**
+ * Private data of an tls_cache_t object.
+ */
+struct private_tls_cache_t {
+
+ /**
+ * Public tls_cache_t interface.
+ */
+ tls_cache_t public;
+
+ /**
+ * Mapping session => entry_t, fast lookup by session
+ */
+ hashtable_t *table;
+
+ /**
+ * List containing all entries
+ */
+ linked_list_t *list;
+
+ /**
+ * Lock to list and table
+ */
+ rwlock_t *lock;
+
+ /**
+ * Session limit
+ */
+ u_int max_sessions;
+
+ /**
+ * maximum age of a session, in seconds
+ */
+ u_int max_age;
+};
+
+/**
+ * Hashtable entry
+ */
+typedef struct {
+ /** session identifier */
+ chunk_t session;
+ /** master secret */
+ chunk_t master;
+ /** TLS cipher suite */
+ tls_cipher_suite_t suite;
+ /** optional identity this entry is bound to */
+ identification_t *id;
+ /** time of add */
+ time_t t;
+} entry_t;
+
+/**
+ * Destroy an entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ chunk_clear(&entry->session);
+ chunk_clear(&entry->master);
+ DESTROY_IF(entry->id);
+ free(entry);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(chunk_t *key)
+{
+ return chunk_hash(*key);
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(chunk_t *a, chunk_t *b)
+{
+ return chunk_equals(*a, *b);
+}
+
+METHOD(tls_cache_t, create_, void,
+ private_tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t master, tls_cipher_suite_t suite)
+{
+ entry_t *entry;
+
+ INIT(entry,
+ .session = chunk_clone(session),
+ .master = chunk_clone(master),
+ .suite = suite,
+ .id = id ? id->clone(id) : NULL,
+ .t = time_monotonic(NULL),
+ );
+
+ this->lock->write_lock(this->lock);
+ this->list->insert_first(this->list, entry);
+ this->table->put(this->table, &entry->session, entry);
+ if (this->list->get_count(this->list) > this->max_sessions &&
+ this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
+ {
+ DBG2(DBG_TLS, "session limit of %u reached, deleting %#B",
+ this->max_sessions, &entry->session);
+ this->table->remove(this->table, &entry->session);
+ entry_destroy(entry);
+ }
+ this->lock->unlock(this->lock);
+
+ DBG2(DBG_TLS, "created TLS session %#B, %d sessions",
+ &session, this->list->get_count(this->list));
+}
+
+METHOD(tls_cache_t, lookup, tls_cipher_suite_t,
+ private_tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t* master)
+{
+ tls_cipher_suite_t suite = 0;
+ entry_t *entry;
+ time_t now;
+ u_int age;
+
+ now = time_monotonic(NULL);
+
+ this->lock->write_lock(this->lock);
+ entry = this->table->get(this->table, &session);
+ if (entry)
+ {
+ age = now - entry->t;
+ if (age <= this->max_age)
+ {
+ if (!id || !entry->id || id->equals(id, entry->id))
+ {
+ *master = chunk_clone(entry->master);
+ suite = entry->suite;
+ }
+ }
+ else
+ {
+ DBG2(DBG_TLS, "TLS session %#B expired: %u seconds", &session, age);
+ }
+ }
+ this->lock->unlock(this->lock);
+
+ if (suite)
+ {
+ DBG2(DBG_TLS, "resuming TLS session %#B, age %u seconds", &session, age);
+ }
+ return suite;
+}
+
+METHOD(tls_cache_t, check, chunk_t,
+ private_tls_cache_t *this, identification_t *id)
+{
+ chunk_t session = chunk_empty;
+ enumerator_t *enumerator;
+ entry_t *entry;
+ time_t now;
+
+ now = time_monotonic(NULL);
+ this->lock->read_lock(this->lock);
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->t + this->max_age >= now &&
+ entry->id && id->equals(id, entry->id))
+ {
+ session = chunk_clone(entry->session);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return session;
+}
+
+METHOD(tls_cache_t, destroy, void,
+ private_tls_cache_t *this)
+{
+ entry_t *entry;
+
+ while (this->list->remove_last(this->list, (void**)&entry) == SUCCESS)
+ {
+ entry_destroy(entry);
+ }
+ this->list->destroy(this->list);
+ this->table->destroy(this->table);
+ this->lock->destroy(this->lock);
+ free(this);
+}
+
+/**
+ * See header
+ */
+tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age)
+{
+ private_tls_cache_t *this;
+
+ INIT(this,
+ .public = {
+ .create = _create_,
+ .lookup = _lookup,
+ .check = _check,
+ .destroy = _destroy,
+ },
+ .table = hashtable_create((hashtable_hash_t)hash,
+ (hashtable_equals_t)equals, 8),
+ .list = linked_list_create(),
+ .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+ .max_sessions = max_sessions,
+ .max_age = max_age,
+ );
+
+ return &this->public;
+}
diff --git a/src/libtls/tls_cache.h b/src/libtls/tls_cache.h
new file mode 100644
index 000000000..ea4e2013e
--- /dev/null
+++ b/src/libtls/tls_cache.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 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_cache tls_cache
+ * @{ @ingroup libtls
+ */
+
+#ifndef TLS_CACHE_H_
+#define TLS_CACHE_H_
+
+typedef struct tls_cache_t tls_cache_t;
+
+#include "tls_crypto.h"
+
+/**
+ * TLS session cache facility.
+ */
+struct tls_cache_t {
+
+ /**
+ * Create a new TLS session entry.
+ *
+ * @param session session identifier
+ * @param id identity the session is bound to
+ * @param master TLS master secret
+ * @param suite TLS cipher suite of the session
+ */
+ void (*create)(tls_cache_t *this, chunk_t session, identification_t *id,
+ chunk_t master, tls_cipher_suite_t suite);
+
+ /**
+ * Look up a TLS session entry.
+ *
+ * @param session session ID to find
+ * @param id identity the session is bound to
+ * @param master gets allocated master secret, if session found
+ * @return TLS suite of session, 0 if none found
+ */
+ tls_cipher_suite_t (*lookup)(tls_cache_t *this, chunk_t session,
+ identification_t *id, chunk_t* master);
+
+ /**
+ * Check if we have a session for a given identity.
+ *
+ * @param id identity to check
+ * @return allocated session ID, or chunk_empty
+ */
+ chunk_t (*check)(tls_cache_t *this, identification_t *id);
+
+ /**
+ * Destroy a tls_cache_t.
+ */
+ void (*destroy)(tls_cache_t *this);
+};
+
+/**
+ * Create a tls_cache instance.
+ *
+ * @param max_sessions maximum number of sessions to store
+ * @param max_age maximum age of a session, in seconds
+ * @return tls cache
+ */
+tls_cache_t *tls_cache_create(u_int max_sessions, u_int max_age);
+
+#endif /** TLS_CACHE_H_ @}*/
diff --git a/src/libtls/tls_compression.h b/src/libtls/tls_compression.h
index b4832ab06..b2c60d5d6 100644
--- a/src/libtls/tls_compression.h
+++ b/src/libtls/tls_compression.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_compression_t tls_compression_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_fragmentation.h"
-typedef struct tls_compression_t tls_compression_t;
-
/**
* TLS record protocol compression layer.
*/
diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c
index b000f9d47..4d84876d0 100644
--- a/src/libtls/tls_crypto.c
+++ b/src/libtls/tls_crypto.c
@@ -370,6 +370,11 @@ struct private_tls_crypto_t {
tls_t *tls;
/**
+ * TLS session cache
+ */
+ tls_cache_t *cache;
+
+ /**
* All handshake data concatentated
*/
chunk_t handshake;
@@ -437,7 +442,7 @@ typedef struct {
static suite_algs_t suite_algs[] = {
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
@@ -447,7 +452,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
KEY_ECDSA, ECP_384_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
@@ -457,7 +462,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
@@ -467,7 +472,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, ECP_384_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
@@ -477,7 +482,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256,PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
@@ -487,7 +492,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, MODP_3072_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -497,7 +502,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
@@ -507,7 +512,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
KEY_RSA, MODP_3072_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
},
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
@@ -517,12 +522,12 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, MODP_2048_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 16
},
{ TLS_RSA_WITH_AES_128_CBC_SHA256,
@@ -532,7 +537,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_AES_256_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_AES_CBC, 32
},
{ TLS_RSA_WITH_AES_256_CBC_SHA256,
@@ -542,7 +547,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 16
},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
@@ -552,7 +557,7 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_CAMELLIA_CBC, 32
},
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
@@ -562,32 +567,32 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_3DES, 0
},
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_ECDHE_RSA_WITH_NULL_SHA,
KEY_ECDSA, ECP_256_BIT,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_RSA_WITH_NULL_SHA,
KEY_RSA, MODP_NONE,
- HASH_SHA1, PRF_HMAC_SHA1,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA1_160, ENCR_NULL, 0
},
{ TLS_RSA_WITH_NULL_SHA256,
@@ -597,13 +602,13 @@ static suite_algs_t suite_algs[] = {
},
{ TLS_RSA_WITH_NULL_MD5,
KEY_RSA, MODP_NONE,
- HASH_MD5, PRF_HMAC_MD5,
+ HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_MD5_128, ENCR_NULL, 0
},
};
/**
- * Look up algoritms by a suite
+ * Look up algorithms by a suite
*/
static suite_algs_t *find_suite(tls_cipher_suite_t suite)
{
@@ -834,25 +839,25 @@ static void filter_mac_config_suites(private_tls_crypto_t *this,
while (enumerator->enumerate(enumerator, &token))
{
if (strcaseeq(token, "md5") &&
- suites[i].hash == HASH_MD5)
+ suites[i].mac == AUTH_HMAC_MD5_128)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha1") &&
- suites[i].hash == HASH_SHA1)
+ suites[i].mac == AUTH_HMAC_SHA1_160)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha256") &&
- suites[i].hash == HASH_SHA256)
+ suites[i].mac == AUTH_HMAC_SHA2_256_256)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "sha384") &&
- suites[i].hash == HASH_SHA384)
+ suites[i].mac == AUTH_HMAC_SHA2_384_384)
{
suites[remaining++] = suites[i];
break;
@@ -1057,15 +1062,15 @@ METHOD(tls_crypto_t, get_dh_group, diffie_hellman_group_t,
}
METHOD(tls_crypto_t, get_signature_algorithms, void,
- private_tls_crypto_t *this, tls_writer_t *writer)
+ private_tls_crypto_t *this, bio_writer_t *writer)
{
- tls_writer_t *supported;
+ bio_writer_t *supported;
enumerator_t *enumerator;
hash_algorithm_t alg;
tls_hash_algorithm_t hash;
const char *plugin_name;
- supported = tls_writer_create(32);
+ supported = bio_writer_create(32);
enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &alg, &plugin_name))
{
@@ -1280,13 +1285,13 @@ static signature_scheme_t hashsig_to_scheme(key_type_t type,
}
METHOD(tls_crypto_t, sign, bool,
- private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer,
+ private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
chunk_t data, chunk_t hashsig)
{
if (this->tls->get_version(this->tls) >= TLS_1_2)
{
signature_scheme_t scheme;
- tls_reader_t *reader;
+ bio_reader_t *reader;
u_int8_t hash, alg;
chunk_t sig;
bool done = FALSE;
@@ -1296,7 +1301,7 @@ METHOD(tls_crypto_t, sign, bool,
hashsig = chunk_from_chars(
TLS_HASH_SHA1, TLS_SIG_RSA, TLS_HASH_SHA1, TLS_SIG_ECDSA);
}
- reader = tls_reader_create(hashsig);
+ reader = bio_reader_create(hashsig);
while (reader->remaining(reader) >= 2)
{
if (reader->read_uint8(reader, &hash) &&
@@ -1361,7 +1366,7 @@ METHOD(tls_crypto_t, sign, bool,
}
METHOD(tls_crypto_t, verify, bool,
- private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader,
+ private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader,
chunk_t data)
{
if (this->tls->get_version(this->tls) >= TLS_1_2)
@@ -1432,14 +1437,14 @@ METHOD(tls_crypto_t, verify, bool,
}
METHOD(tls_crypto_t, sign_handshake, bool,
- private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer,
+ private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
chunk_t hashsig)
{
return sign(this, key, writer, this->handshake, hashsig);
}
METHOD(tls_crypto_t, verify_handshake, bool,
- private_tls_crypto_t *this, public_key_t *key, tls_reader_t *reader)
+ private_tls_crypto_t *this, public_key_t *key, bio_reader_t *reader)
{
return verify(this, key, reader, this->handshake);
}
@@ -1462,13 +1467,15 @@ METHOD(tls_crypto_t, calculate_finished, bool,
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)
+/**
+ * Derive master secret from premaster, optionally save session
+ */
+static void derive_master(private_tls_crypto_t *this, chunk_t premaster,
+ chunk_t session, identification_t *id,
+ 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;
+ chunk_t seed;
/* derive master secret */
seed = chunk_cata("cc", client_random, server_random);
@@ -1477,7 +1484,22 @@ METHOD(tls_crypto_t, derive_secrets, void,
sizeof(master), master);
this->prf->set_key(this->prf, chunk_from_thing(master));
- memset(master, 0, sizeof(master));
+ if (this->cache && session.len)
+ {
+ this->cache->create(this->cache, session, id, chunk_from_thing(master),
+ this->suite);
+ }
+ memwipe(master, sizeof(master));
+}
+
+/**
+ * Expand key material from master secret
+ */
+static void expand_keys(private_tls_crypto_t *this,
+ chunk_t client_random, chunk_t server_random)
+{
+ chunk_t seed, block, client_write, server_write;
+ int mks, eks = 0, ivs = 0;
/* derive key block for key expansion */
mks = this->signer_out->get_key_size(this->signer_out);
@@ -1546,6 +1568,57 @@ METHOD(tls_crypto_t, derive_secrets, void,
}
}
}
+
+ /* EAP-MSK */
+ if (this->msk_label)
+ {
+ seed = chunk_cata("cc", client_random, server_random);
+ this->msk = chunk_alloc(64);
+ this->prf->get_bytes(this->prf, this->msk_label, seed,
+ this->msk.len, this->msk.ptr);
+ }
+}
+
+METHOD(tls_crypto_t, derive_secrets, void,
+ private_tls_crypto_t *this, chunk_t premaster, chunk_t session,
+ identification_t *id, chunk_t client_random, chunk_t server_random)
+{
+ derive_master(this, premaster, session, id, client_random, server_random);
+ expand_keys(this, client_random, server_random);
+}
+
+METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t,
+ private_tls_crypto_t *this, chunk_t session, identification_t *id,
+ chunk_t client_random, chunk_t server_random)
+{
+ chunk_t master;
+
+ if (this->cache && session.len)
+ {
+ this->suite = this->cache->lookup(this->cache, session, id, &master);
+ if (this->suite)
+ {
+ this->suite = select_cipher_suite(this, &this->suite, 1, KEY_ANY);
+ if (this->suite)
+ {
+ this->prf->set_key(this->prf, master);
+ expand_keys(this, client_random, server_random);
+ }
+ chunk_clear(&master);
+ }
+ return this->suite;
+ }
+ return 0;
+}
+
+METHOD(tls_crypto_t, get_session, chunk_t,
+ private_tls_crypto_t *this, identification_t *server)
+{
+ if (this->cache)
+ {
+ return this->cache->check(this->cache, server);
+ }
+ return chunk_empty;
}
METHOD(tls_crypto_t, change_cipher, void,
@@ -1566,21 +1639,6 @@ METHOD(tls_crypto_t, change_cipher, void,
}
}
-METHOD(tls_crypto_t, derive_eap_msk, void,
- private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random)
-{
- if (this->msk_label)
- {
- 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, this->msk_label, seed,
- this->msk.len, this->msk.ptr);
- }
-}
-
METHOD(tls_crypto_t, get_eap_msk, chunk_t,
private_tls_crypto_t *this)
{
@@ -1606,7 +1664,7 @@ METHOD(tls_crypto_t, destroy, void,
/**
* See header
*/
-tls_crypto_t *tls_crypto_create(tls_t *tls)
+tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache)
{
private_tls_crypto_t *this;
enumerator_t *enumerator;
@@ -1628,12 +1686,14 @@ tls_crypto_t *tls_crypto_create(tls_t *tls)
.verify_handshake = _verify_handshake,
.calculate_finished = _calculate_finished,
.derive_secrets = _derive_secrets,
+ .resume_session = _resume_session,
+ .get_session = _get_session,
.change_cipher = _change_cipher,
- .derive_eap_msk = _derive_eap_msk,
.get_eap_msk = _get_eap_msk,
.destroy = _destroy,
},
.tls = tls,
+ .cache = cache,
);
enumerator = lib->creds->create_builder_enumerator(lib->creds);
diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h
index f57b8f3e1..7430aea66 100644
--- a/src/libtls/tls_crypto.h
+++ b/src/libtls/tls_crypto.h
@@ -54,13 +54,13 @@ enum tls_cipher_suite_t {
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008,
TLS_RSA_WITH_DES_CBC_SHA = 0x0009,
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
- TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
+ TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C,
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D,
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E,
- TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
+ TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010,
- TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
+ TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012,
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014,
@@ -110,7 +110,7 @@ enum tls_cipher_suite_t {
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043,
- TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046,
@@ -126,8 +126,8 @@ enum tls_cipher_suite_t {
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087,
- TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
- TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089,
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088,
+ TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089,
TLS_PSK_WITH_RC4_128_SHA = 0x008A,
TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B,
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
@@ -427,7 +427,7 @@ struct tls_crypto_t {
*
* @param writer writer to write supported hash/sig algorithms
*/
- void (*get_signature_algorithms)(tls_crypto_t *this, tls_writer_t *writer);
+ void (*get_signature_algorithms)(tls_crypto_t *this, bio_writer_t *writer);
/**
* Create an enumerator over supported ECDH groups.
@@ -464,7 +464,7 @@ struct tls_crypto_t {
* @return TRUE if signature create successfully
*/
bool (*sign)(tls_crypto_t *this, private_key_t *key,
- tls_writer_t *writer, chunk_t data, chunk_t hashsig);
+ bio_writer_t *writer, chunk_t data, chunk_t hashsig);
/**
* Verify a blob of data, read signature from a reader.
@@ -475,7 +475,7 @@ struct tls_crypto_t {
* @return TRUE if signature valid
*/
bool (*verify)(tls_crypto_t *this, public_key_t *key,
- tls_reader_t *reader, chunk_t data);
+ bio_reader_t *reader, chunk_t data);
/**
* Create a signature of the handshake data using a given private key.
@@ -486,7 +486,7 @@ struct tls_crypto_t {
* @return TRUE if signature create successfully
*/
bool (*sign_handshake)(tls_crypto_t *this, private_key_t *key,
- tls_writer_t *writer, chunk_t hashsig);
+ bio_writer_t *writer, chunk_t hashsig);
/**
* Verify the signature over handshake data using a given public key.
@@ -496,7 +496,7 @@ struct tls_crypto_t {
* @return TRUE if signature valid
*/
bool (*verify_handshake)(tls_crypto_t *this, public_key_t *key,
- tls_reader_t *reader);
+ bio_reader_t *reader);
/**
* Calculate the data of a TLS finished message.
@@ -511,27 +511,43 @@ struct tls_crypto_t {
* Derive the master secret, MAC and encryption keys.
*
* @param premaster premaster secret
+ * @param session session identifier to cache master secret
+ * @param id identity the session is bound to
* @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 session, identification_t *id,
chunk_t client_random, chunk_t server_random);
/**
- * Change the cipher used at protection layer.
+ * Try to resume a TLS session, derive key material.
*
- * @param inbound TRUE to change inbound cipher, FALSE for outbound
+ * @param session session identifier
+ * @param id identity the session is bound to
+ * @param client_random random data from client hello
+ * @param server_random random data from server hello
+ * @return selected suite
*/
- void (*change_cipher)(tls_crypto_t *this, bool inbound);
+ tls_cipher_suite_t (*resume_session)(tls_crypto_t *this, chunk_t session,
+ identification_t *id,
+ chunk_t client_random,
+ chunk_t server_random);
/**
- * Derive the EAP-TLS MSK.
+ * Check if we have a session to resume as a client.
*
- * @param client_random random data from client hello
- * @param server_random random data from server hello
+ * @param id server identity to get a session for
+ * @return allocated session identifier, or chunk_empty
*/
- void (*derive_eap_msk)(tls_crypto_t *this,
- chunk_t client_random, chunk_t server_random);
+ chunk_t (*get_session)(tls_crypto_t *this, identification_t *id);
+
+ /**
+ * 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);
/**
* Get the MSK to use in EAP-TLS.
@@ -548,7 +564,11 @@ struct tls_crypto_t {
/**
* Create a tls_crypto instance.
+ *
+ * @param tls TLS stack
+ * @param cache TLS session cache
+ * @return TLS crypto helper
*/
-tls_crypto_t *tls_crypto_create(tls_t *tls);
+tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache);
#endif /** TLS_CRYPTO_H_ @}*/
diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c
index 5a598cfc4..62e36aaec 100644
--- a/src/libtls/tls_fragmentation.c
+++ b/src/libtls/tls_fragmentation.c
@@ -15,8 +15,7 @@
#include "tls_fragmentation.h"
-#include "tls_reader.h"
-
+#include <bio/bio_reader.h>
#include <debug.h>
typedef struct private_tls_fragmentation_t private_tls_fragmentation_t;
@@ -108,7 +107,7 @@ struct private_tls_fragmentation_t {
* Process a TLS alert
*/
static status_t process_alert(private_tls_fragmentation_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
u_int8_t level, description;
@@ -125,11 +124,11 @@ static status_t process_alert(private_tls_fragmentation_t *this,
* Process TLS handshake protocol data
*/
static status_t process_handshake(private_tls_fragmentation_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
while (reader->remaining(reader))
{
- tls_reader_t *msg;
+ bio_reader_t *msg;
u_int8_t type;
u_int32_t len;
status_t status;
@@ -178,7 +177,7 @@ static status_t process_handshake(private_tls_fragmentation_t *this,
if (this->input.len == this->inpos)
{ /* message completely defragmented, process */
- msg = tls_reader_create(this->input);
+ msg = bio_reader_create(this->input);
DBG2(DBG_TLS, "received TLS %N handshake (%u bytes)",
tls_handshake_type_names, this->type, this->input.len);
status = this->handshake->process(this->handshake, this->type, msg);
@@ -201,11 +200,12 @@ static status_t process_handshake(private_tls_fragmentation_t *this,
* Process TLS application data
*/
static status_t process_application(private_tls_fragmentation_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
while (reader->remaining(reader))
{
status_t status;
+ chunk_t data;
if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN)
{
@@ -213,6 +213,8 @@ static status_t process_application(private_tls_fragmentation_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
+ data = reader->peek(reader);
+ DBG3(DBG_TLS, "%B", &data);
status = this->application->process(this->application, reader);
switch (status)
{
@@ -233,24 +235,25 @@ static status_t process_application(private_tls_fragmentation_t *this,
METHOD(tls_fragmentation_t, process, status_t,
private_tls_fragmentation_t *this, tls_content_type_t type, chunk_t data)
{
- tls_reader_t *reader;
+ bio_reader_t *reader;
status_t status;
switch (this->state)
{
case ALERT_SENDING:
case ALERT_SENT:
- /* don't accept more input, fatal error ocurred */
+ /* don't accept more input, fatal error occurred */
return NEED_MORE;
case ALERT_NONE:
break;
}
- reader = tls_reader_create(data);
+ reader = bio_reader_create(data);
switch (type)
{
case TLS_CHANGE_CIPHER_SPEC:
- if (this->handshake->change_cipherspec(this->handshake))
+ if (this->handshake->cipherspec_changed(this->handshake, TRUE))
{
+ this->handshake->change_cipherspec(this->handshake, TRUE);
status = NEED_MORE;
break;
}
@@ -281,11 +284,11 @@ static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
{
tls_alert_level_t level;
tls_alert_desc_t desc;
- tls_writer_t *writer;
+ bio_writer_t *writer;
if (this->alert->get(this->alert, &level, &desc))
{
- writer = tls_writer_create(2);
+ writer = bio_writer_create(2);
writer->write_uint8(writer, level);
writer->write_uint8(writer, desc);
@@ -302,14 +305,14 @@ static bool check_alerts(private_tls_fragmentation_t *this, chunk_t *data)
*/
static status_t build_handshake(private_tls_fragmentation_t *this)
{
- tls_writer_t *hs, *msg;
+ bio_writer_t *hs, *msg;
tls_handshake_type_t type;
status_t status;
- msg = tls_writer_create(64);
+ msg = bio_writer_create(64);
while (TRUE)
{
- hs = tls_writer_create(64);
+ hs = bio_writer_create(64);
status = this->handshake->build(this->handshake, &type, hs);
switch (status)
{
@@ -322,8 +325,12 @@ static status_t build_handshake(private_tls_fragmentation_t *this)
msg->write_data24(msg, hs->get_buf(hs));
DBG2(DBG_TLS, "sending TLS %N handshake (%u bytes)",
tls_handshake_type_names, type, hs->get_buf(hs).len);
- hs->destroy(hs);
- continue;
+ if (!this->handshake->cipherspec_changed(this->handshake, FALSE))
+ {
+ hs->destroy(hs);
+ continue;
+ }
+ /* FALL */
case INVALID_STATE:
this->output_type = TLS_HANDSHAKE;
this->output = chunk_clone(msg->get_buf(msg));
@@ -343,10 +350,10 @@ static status_t build_handshake(private_tls_fragmentation_t *this)
*/
static status_t build_application(private_tls_fragmentation_t *this)
{
- tls_writer_t *msg;
+ bio_writer_t *msg;
status_t status;
- msg = tls_writer_create(64);
+ msg = bio_writer_create(64);
while (TRUE)
{
status = this->application->build(this->application, msg);
@@ -395,8 +402,9 @@ METHOD(tls_fragmentation_t, build, status_t,
}
if (!this->output.len)
{
- if (this->handshake->cipherspec_changed(this->handshake))
+ if (this->handshake->cipherspec_changed(this->handshake, FALSE))
{
+ this->handshake->change_cipherspec(this->handshake, FALSE);
*type = TLS_CHANGE_CIPHER_SPEC;
*data = chunk_clone(chunk_from_chars(0x01));
return NEED_MORE;
diff --git a/src/libtls/tls_fragmentation.h b/src/libtls/tls_fragmentation.h
index d80278916..f650e7be8 100644
--- a/src/libtls/tls_fragmentation.h
+++ b/src/libtls/tls_fragmentation.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_fragmentation_t tls_fragmentation_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_handshake.h"
-typedef struct tls_fragmentation_t tls_fragmentation_t;
-
/**
* TLS record protocol fragmentation layer.
*/
diff --git a/src/libtls/tls_handshake.h b/src/libtls/tls_handshake.h
index 6703b341b..bea0024eb 100644
--- a/src/libtls/tls_handshake.h
+++ b/src/libtls/tls_handshake.h
@@ -24,8 +24,9 @@
typedef struct tls_handshake_t tls_handshake_t;
#include "tls.h"
-#include "tls_reader.h"
-#include "tls_writer.h"
+
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
/**
* TLS handshake state machine interface.
@@ -44,7 +45,7 @@ struct tls_handshake_t {
* - DESTROY_ME if a fatal TLS alert received
*/
status_t (*process)(tls_handshake_t *this,
- tls_handshake_type_t type, tls_reader_t *reader);
+ tls_handshake_type_t type, bio_reader_t *reader);
/**
* Build TLS handshake messages to send out.
@@ -58,21 +59,22 @@ struct tls_handshake_t {
* - INVALID_STATE if more input to process() required
*/
status_t (*build)(tls_handshake_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer);
+ tls_handshake_type_t *type, bio_writer_t *writer);
/**
- * Check if the cipher spec for outgoing messages has changed.
+ * Check if the cipher spec should be changed for outgoing messages.
*
- * @return TRUE if cipher spec changed
+ * @param inbound TRUE to check for inbound cipherspec change
+ * @return TRUE if cipher spec should be changed
*/
- bool (*cipherspec_changed)(tls_handshake_t *this);
+ bool (*cipherspec_changed)(tls_handshake_t *this, bool inbound);
/**
- * Change the cipher spec for incoming messages.
+ * Change the cipher for a direction.
*
- * @return TRUE if cipher spec changed
+ * @param inbound TRUE to change inbound cipherspec, FALSE for outbound
*/
- bool (*change_cipherspec)(tls_handshake_t *this);
+ void (*change_cipherspec)(tls_handshake_t *this, bool inbound);
/**
* Check if the finished message was decoded successfully.
diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index 621f1729d..6091702cf 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -36,7 +36,7 @@ typedef enum {
STATE_CIPHERSPEC_CHANGED_OUT,
STATE_FINISHED_SENT,
STATE_CIPHERSPEC_CHANGED_IN,
- STATE_COMPLETE,
+ STATE_FINISHED_RECEIVED,
} peer_state_t;
/**
@@ -110,6 +110,16 @@ struct private_tls_peer_t {
diffie_hellman_t *dh;
/**
+ * Resuming a session?
+ */
+ bool resume;
+
+ /**
+ * TLS session identifier
+ */
+ chunk_t session;
+
+ /**
* List of server-supported hashsig algorithms
*/
chunk_t hashsig;
@@ -124,12 +134,12 @@ struct private_tls_peer_t {
* Process a server hello message
*/
static status_t process_server_hello(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
u_int8_t compression;
u_int16_t version, cipher;
chunk_t random, session, ext = chunk_empty;
- tls_cipher_suite_t suite;
+ tls_cipher_suite_t suite = 0;
this->crypto->append_handshake(this->crypto,
TLS_SERVER_HELLO, reader->peek(reader));
@@ -155,16 +165,34 @@ static status_t process_server_hello(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
return NEED_MORE;
}
- suite = cipher;
- if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+
+ if (chunk_equals(this->session, session))
{
- DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
- tls_cipher_suite_names, suite);
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
+ suite = this->crypto->resume_session(this->crypto, session, this->server,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
+ if (suite)
+ {
+ DBG1(DBG_TLS, "resumed %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ this->resume = TRUE;
+ }
+ }
+ if (!suite)
+ {
+ suite = cipher;
+ if (!this->crypto->select_cipher_suite(this->crypto, &suite, 1, KEY_ANY))
+ {
+ DBG1(DBG_TLS, "received TLS cipher suite %N inacceptable",
+ tls_cipher_suite_names, suite);
+ this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
+ return NEED_MORE;
+ }
+ DBG1(DBG_TLS, "negotiated %N using suite %N",
+ tls_version_names, version, tls_cipher_suite_names, suite);
+ free(this->session.ptr);
+ this->session = chunk_clone(session);
}
- DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
- tls_version_names, version, tls_cipher_suite_names, suite);
this->state = STATE_HELLO_RECEIVED;
return NEED_MORE;
}
@@ -209,10 +237,10 @@ static bool check_certificate(private_tls_peer_t *this, certificate_t *cert)
* Process a Certificate message
*/
static status_t process_certificate(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
certificate_t *cert;
- tls_reader_t *certs;
+ bio_reader_t *certs;
chunk_t data;
bool first = TRUE;
@@ -225,7 +253,7 @@ static status_t process_certificate(private_tls_peer_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- certs = tls_reader_create(data);
+ certs = bio_reader_create(data);
while (certs->remaining(certs))
{
if (!certs->read_data24(certs, &data))
@@ -302,7 +330,7 @@ static public_key_t *find_public_key(private_tls_peer_t *this)
* Process a Key Exchange message using MODP Diffie Hellman
*/
static status_t process_modp_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
chunk_t prime, generator, pub, chunk;
public_key_t *public;
@@ -379,7 +407,7 @@ static diffie_hellman_group_t curve_to_ec_group(private_tls_peer_t *this,
* Process a Key Exchange message using EC Diffie Hellman
*/
static status_t process_ec_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
diffie_hellman_group_t group;
public_key_t *public;
@@ -466,7 +494,7 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
* Process a Server Key Exchange
*/
static status_t process_key_exchange(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
diffie_hellman_group_t group;
@@ -491,10 +519,10 @@ static status_t process_key_exchange(private_tls_peer_t *this,
/**
* Process a Certificate Request message
*/
-static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
+static status_t process_certreq(private_tls_peer_t *this, bio_reader_t *reader)
{
chunk_t types, hashsig, data;
- tls_reader_t *authorities;
+ bio_reader_t *authorities;
identification_t *id;
certificate_t *cert;
@@ -529,7 +557,7 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- authorities = tls_reader_create(data);
+ authorities = bio_reader_create(data);
while (authorities->remaining(authorities))
{
if (!authorities->read_data16(authorities, &data))
@@ -565,7 +593,7 @@ static status_t process_certreq(private_tls_peer_t *this, tls_reader_t *reader)
* Process Hello Done message
*/
static status_t process_hello_done(private_tls_peer_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
this->crypto->append_handshake(this->crypto,
TLS_SERVER_HELLO_DONE, reader->peek(reader));
@@ -576,7 +604,7 @@ static status_t process_hello_done(private_tls_peer_t *this,
/**
* Process finished message
*/
-static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
+static status_t process_finished(private_tls_peer_t *this, bio_reader_t *reader)
{
chunk_t received;
char buf[12];
@@ -599,15 +627,14 @@ static status_t process_finished(private_tls_peer_t *this, tls_reader_t *reader)
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
return NEED_MORE;
}
- this->state = STATE_COMPLETE;
- this->crypto->derive_eap_msk(this->crypto,
- chunk_from_thing(this->client_random),
- chunk_from_thing(this->server_random));
+ this->state = STATE_FINISHED_RECEIVED;
+ this->crypto->append_handshake(this->crypto, TLS_FINISHED, received);
+
return NEED_MORE;
}
METHOD(tls_handshake_t, process, status_t,
- private_tls_peer_t *this, tls_handshake_type_t type, tls_reader_t *reader)
+ private_tls_peer_t *this, tls_handshake_type_t type, bio_reader_t *reader)
{
tls_handshake_type_t expected;
@@ -670,10 +697,10 @@ METHOD(tls_handshake_t, process, status_t,
* 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_handshake_type_t *type, bio_writer_t *writer)
{
tls_cipher_suite_t *suites;
- tls_writer_t *extensions, *curves = NULL;
+ bio_writer_t *extensions, *curves = NULL;
tls_version_t version;
tls_named_curve_t curve;
enumerator_t *enumerator;
@@ -696,8 +723,9 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint16(writer, version);
writer->write_data(writer, chunk_from_thing(this->client_random));
- /* session identifier => none */
- writer->write_data8(writer, chunk_empty);
+ /* session identifier */
+ this->session = this->crypto->get_session(this->crypto, this->server);
+ writer->write_data8(writer, this->session);
/* add TLS cipher suites */
count = this->crypto->get_cipher_suites(this->crypto, &suites);
@@ -711,7 +739,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
writer->write_uint8(writer, 1);
writer->write_uint8(writer, 0);
- extensions = tls_writer_create(32);
+ extensions = bio_writer_create(32);
extensions->write_uint16(extensions, TLS_EXT_SIGNATURE_ALGORITHMS);
this->crypto->get_signature_algorithms(this->crypto, extensions);
@@ -723,7 +751,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
if (!curves)
{
extensions->write_uint16(extensions, TLS_EXT_ELLIPTIC_CURVES);
- curves = tls_writer_create(16);
+ curves = bio_writer_create(16);
}
curves->write_uint16(curves, curve);
}
@@ -741,11 +769,11 @@ static status_t send_client_hello(private_tls_peer_t *this,
}
if (this->server->get_type(this->server) == ID_FQDN)
{
- tls_writer_t *names;
+ bio_writer_t *names;
DBG2(DBG_TLS, "sending Server Name Indication for '%Y'", this->server);
- names = tls_writer_create(8);
+ names = bio_writer_create(8);
names->write_uint8(names, TLS_NAME_TYPE_HOST_NAME);
names->write_data16(names, this->server->get_encoding(this->server));
names->wrap16(names);
@@ -769,7 +797,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
static private_key_t *find_private_key(private_tls_peer_t *this)
{
private_key_t *key = NULL;
- tls_reader_t *reader;
+ bio_reader_t *reader;
key_type_t type;
u_int8_t cert;
@@ -777,7 +805,7 @@ static private_key_t *find_private_key(private_tls_peer_t *this)
{
return NULL;
}
- reader = tls_reader_create(this->cert_types);
+ reader = bio_reader_create(this->cert_types);
while (reader->remaining(reader) && reader->read_uint8(reader, &cert))
{
switch (cert)
@@ -806,12 +834,12 @@ static private_key_t *find_private_key(private_tls_peer_t *this)
* Send Certificate
*/
static status_t send_certificate(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
enumerator_t *enumerator;
certificate_t *cert;
auth_rule_t rule;
- tls_writer_t *certs;
+ bio_writer_t *certs;
chunk_t data;
this->private = find_private_key(this);
@@ -823,7 +851,7 @@ static status_t send_certificate(private_tls_peer_t *this,
}
/* generate certificate payload */
- certs = tls_writer_create(256);
+ certs = bio_writer_create(256);
if (this->peer)
{
cert = this->peer_auth->get(this->peer_auth, AUTH_RULE_SUBJECT_CERT);
@@ -867,7 +895,7 @@ static status_t send_certificate(private_tls_peer_t *this,
* Send client key exchange, using premaster encryption
*/
static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
public_key_t *public;
rng_t *rng;
@@ -886,6 +914,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
htoun16(premaster, TLS_1_2);
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
@@ -919,7 +948,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
* Send client key exchange, using DHE exchange
*/
static status_t send_key_exchange_dhe(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
chunk_t premaster, pub;
@@ -930,6 +959,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
return NEED_MORE;
}
this->crypto->derive_secrets(this->crypto, premaster,
+ this->session, this->server,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
chunk_clear(&premaster);
@@ -957,7 +987,7 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this,
* Send client key exchange, depending on suite
*/
static status_t send_key_exchange(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
if (this->dh)
{
@@ -970,7 +1000,7 @@ static status_t send_key_exchange(private_tls_peer_t *this,
* Send certificate verify
*/
static status_t send_certificate_verify(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
if (!this->private ||
!this->crypto->sign_handshake(this->crypto, this->private,
@@ -991,7 +1021,7 @@ static status_t send_certificate_verify(private_tls_peer_t *this,
* Send Finished
*/
static status_t send_finished(private_tls_peer_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
char buf[12];
@@ -1011,7 +1041,7 @@ static status_t send_finished(private_tls_peer_t *this,
}
METHOD(tls_handshake_t, build, status_t,
- private_tls_peer_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
+ private_tls_peer_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
{
switch (this->state)
{
@@ -1042,34 +1072,52 @@ METHOD(tls_handshake_t, build, status_t,
}
METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_peer_t *this)
+ private_tls_peer_t *this, bool inbound)
{
- if ((this->peer && this->state == STATE_VERIFY_SENT) ||
- (!this->peer && this->state == STATE_KEY_EXCHANGE_SENT))
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
+ if (this->resume)
+ {
+ return this->state == STATE_HELLO_RECEIVED;
+ }
+ return this->state == STATE_FINISHED_SENT;
+ }
+ else
+ {
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_RECEIVED;
+ }
+ if (this->peer)
+ {
+ return this->state == STATE_VERIFY_SENT;
+ }
+ return this->state == STATE_KEY_EXCHANGE_SENT;
}
- return FALSE;
}
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_peer_t *this)
+METHOD(tls_handshake_t, change_cipherspec, void,
+ private_tls_peer_t *this, bool inbound)
{
- if (this->state == STATE_FINISHED_SENT)
+ this->crypto->change_cipher(this->crypto, inbound);
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, TRUE);
this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
}
- return FALSE;
+ else
+ {
+ this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+ }
}
METHOD(tls_handshake_t, finished, bool,
private_tls_peer_t *this)
{
- return this->state == STATE_COMPLETE;
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_SENT;
+ }
+ return this->state == STATE_FINISHED_RECEIVED;
}
METHOD(tls_handshake_t, destroy, void,
@@ -1081,6 +1129,7 @@ METHOD(tls_handshake_t, destroy, void,
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->cert_types.ptr);
+ free(this->session.ptr);
free(this);
}
diff --git a/src/libtls/tls_protection.c b/src/libtls/tls_protection.c
index d823bae04..dc734545c 100644
--- a/src/libtls/tls_protection.c
+++ b/src/libtls/tls_protection.c
@@ -91,28 +91,33 @@ struct private_tls_protection_t {
};
/**
- * Create the header to append to the record data to create the MAC
+ * Create the header and feed it into a signer for MAC verification
*/
-static chunk_t sigheader(u_int32_t seq, u_int8_t type,
- u_int16_t version, u_int16_t length)
+static void sigheader(signer_t *signer, 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));
+ struct __attribute__((__packed__)) {
+ u_int32_t seq_high;
+ u_int32_t seq_low;
+ u_int8_t type;
+ u_int16_t version;
+ u_int16_t length;
+ } header = {
+ .type = type,
+ };
+ htoun32(&header.seq_low, seq);
+ htoun16(&header.version, version);
+ htoun16(&header.length, length);
+
+ signer->get_signature(signer, chunk_from_thing(header), NULL);
}
METHOD(tls_protection_t, process, status_t,
private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
{
if (this->alert->fatal(this->alert))
- { /* don't accept more input, fatal error ocurred */
+ { /* don't accept more input, fatal error occurred */
return NEED_MORE;
}
@@ -154,17 +159,15 @@ METHOD(tls_protection_t, process, status_t,
}
padding_length = data.ptr[data.len - 1];
- if (padding_length >= data.len)
- {
- DBG1(DBG_TLS, "invalid TLS record padding");
- this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
- return NEED_MORE;
+ if (padding_length < data.len)
+ { /* remove padding if it looks valid. Continue with no padding, try
+ * to prevent timing attacks. */
+ data.len -= padding_length + 1;
}
- data.len -= padding_length + 1;
}
if (this->signer_in)
{
- chunk_t mac, macdata, header;
+ chunk_t mac;
u_int8_t bs;
bs = this->signer_in->get_block_size(this->signer_in);
@@ -177,16 +180,13 @@ METHOD(tls_protection_t, process, status_t,
mac = chunk_skip(data, data.len - bs);
data.len -= bs;
- header = sigheader(this->seq_in, type, this->version, data.len);
- macdata = chunk_cat("mc", header, data);
- if (!this->signer_in->verify_signature(this->signer_in, macdata, mac))
+ sigheader(this->signer_in, this->seq_in, type, this->version, data.len);
+ if (!this->signer_in->verify_signature(this->signer_in, data, mac))
{
DBG1(DBG_TLS, "TLS record MAC verification failed");
- free(macdata.ptr);
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE;
}
- free(macdata.ptr);
}
if (type == TLS_CHANGE_CIPHER_SPEC)
@@ -216,11 +216,10 @@ METHOD(tls_protection_t, build, status_t,
{
if (this->signer_out)
{
- chunk_t mac, header;
+ chunk_t mac;
- header = sigheader(this->seq_out, *type, this->version, data->len);
- this->signer_out->get_signature(this->signer_out, header, NULL);
- free(header.ptr);
+ sigheader(this->signer_out, this->seq_out, *type,
+ this->version, data->len);
this->signer_out->allocate_signature(this->signer_out, *data, &mac);
if (this->crypter_out)
{
diff --git a/src/libtls/tls_protection.h b/src/libtls/tls_protection.h
index 99c94e935..05cf3df45 100644
--- a/src/libtls/tls_protection.h
+++ b/src/libtls/tls_protection.h
@@ -23,12 +23,12 @@
#include <library.h>
+typedef struct tls_protection_t tls_protection_t;
+
#include "tls.h"
#include "tls_alert.h"
#include "tls_compression.h"
-typedef struct tls_protection_t tls_protection_t;
-
/**
* TLS record protocol protection layer.
*/
diff --git a/src/libtls/tls_reader.c b/src/libtls/tls_reader.c
deleted file mode 100644
index 2b3cd8cac..000000000
--- a/src/libtls/tls_reader.c
+++ /dev/null
@@ -1,200 +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_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_TLS, "%d bytes insufficient to parse u_int8 data",
- this->buf.len);
- 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_TLS, "%d bytes insufficient to parse u_int16 data",
- this->buf.len);
- 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_TLS, "%d bytes insufficient to parse u_int24 data",
- this->buf.len);
- 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_TLS, "%d bytes insufficient to parse u_int32 data",
- this->buf.len);
- 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_TLS, "%d bytes insufficient to parse %d bytes of 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
deleted file mode 100644
index a8978b486..000000000
--- a/src/libtls/tls_reader.h
+++ /dev/null
@@ -1,131 +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_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
index b0417f6cb..e3617dc9a 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -22,6 +22,10 @@
typedef struct private_tls_server_t private_tls_server_t;
+/**
+ * Size of a session ID
+ */
+#define SESSION_ID_SIZE 16
typedef enum {
STATE_INIT,
@@ -121,6 +125,16 @@ struct private_tls_server_t {
tls_version_t client_version;
/**
+ * TLS session identifier
+ */
+ chunk_t session;
+
+ /**
+ * Do we resume a session?
+ */
+ bool resume;
+
+ /**
* Hash and signature algorithms supported by peer
*/
chunk_t hashsig;
@@ -192,13 +206,14 @@ static bool select_suite_and_key(private_tls_server_t *this,
* Process client hello message
*/
static status_t process_client_hello(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
u_int16_t version, extension;
chunk_t random, session, ciphers, compression, ext = chunk_empty;
- tls_reader_t *extensions;
+ bio_reader_t *extensions;
tls_cipher_suite_t *suites;
int count, i;
+ rng_t *rng;
this->crypto->append_handshake(this->crypto,
TLS_CLIENT_HELLO, reader->peek(reader));
@@ -217,7 +232,7 @@ static status_t process_client_hello(private_tls_server_t *this,
if (ext.len)
{
- extensions = tls_reader_create(ext);
+ extensions = bio_reader_create(ext);
while (extensions->remaining(extensions))
{
if (!extensions->read_uint16(extensions, &extension) ||
@@ -228,7 +243,7 @@ static status_t process_client_hello(private_tls_server_t *this,
extensions->destroy(extensions);
return NEED_MORE;
}
- DBG1(DBG_TLS, "received TLS '%N' extension",
+ DBG2(DBG_TLS, "received TLS '%N' extension",
tls_extension_names, extension);
DBG3(DBG_TLS, "%B", &ext);
switch (extension)
@@ -249,6 +264,17 @@ static status_t process_client_hello(private_tls_server_t *this,
memcpy(this->client_random, random.ptr, sizeof(this->client_random));
+ htoun32(&this->server_random, time(NULL));
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
+ {
+ DBG1(DBG_TLS, "no suitable RNG found to generate server random");
+ this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
+ return NEED_MORE;
+ }
+ rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
+ rng->destroy(rng);
+
if (!this->tls->set_version(this->tls, version))
{
DBG1(DBG_TLS, "negotiated version %N not supported",
@@ -256,24 +282,44 @@ static status_t process_client_hello(private_tls_server_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_PROTOCOL_VERSION);
return NEED_MORE;
}
- count = ciphers.len / sizeof(u_int16_t);
- suites = alloca(count * sizeof(tls_cipher_suite_t));
- DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
- for (i = 0; i < count; i++)
+
+ this->client_version = version;
+ this->suite = this->crypto->resume_session(this->crypto, session, this->peer,
+ chunk_from_thing(this->client_random),
+ chunk_from_thing(this->server_random));
+ if (this->suite)
{
- suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
- DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
+ this->session = chunk_clone(session);
+ this->resume = TRUE;
+ DBG1(DBG_TLS, "resumed %N using suite %N",
+ tls_version_names, this->tls->get_version(this->tls),
+ tls_cipher_suite_names, this->suite);
}
-
- if (!select_suite_and_key(this, suites, count))
+ else
{
- this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
- return NEED_MORE;
+ count = ciphers.len / sizeof(u_int16_t);
+ suites = alloca(count * sizeof(tls_cipher_suite_t));
+ DBG2(DBG_TLS, "received %d TLS cipher suites:", count);
+ for (i = 0; i < count; i++)
+ {
+ suites[i] = untoh16(&ciphers.ptr[i * sizeof(u_int16_t)]);
+ DBG2(DBG_TLS, " %N", tls_cipher_suite_names, suites[i]);
+ }
+ if (!select_suite_and_key(this, suites, count))
+ {
+ this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
+ return NEED_MORE;
+ }
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ if (rng)
+ {
+ rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session);
+ rng->destroy(rng);
+ }
+ DBG1(DBG_TLS, "negotiated %N using suite %N",
+ tls_version_names, this->tls->get_version(this->tls),
+ tls_cipher_suite_names, this->suite);
}
- DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
- tls_version_names, this->tls->get_version(this->tls),
- tls_cipher_suite_names, this->suite);
- this->client_version = version;
this->state = STATE_HELLO_RECEIVED;
return NEED_MORE;
}
@@ -282,10 +328,10 @@ static status_t process_client_hello(private_tls_server_t *this,
* Process certificate
*/
static status_t process_certificate(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
certificate_t *cert;
- tls_reader_t *certs;
+ bio_reader_t *certs;
chunk_t data;
bool first = TRUE;
@@ -298,7 +344,7 @@ static status_t process_certificate(private_tls_server_t *this,
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- certs = tls_reader_create(data);
+ certs = bio_reader_create(data);
while (certs->remaining(certs))
{
if (!certs->read_data24(certs, &data))
@@ -342,7 +388,7 @@ static status_t process_certificate(private_tls_server_t *this,
* Process Client Key Exchange, using premaster encryption
*/
static status_t process_key_exchange_encrypted(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
chunk_t encrypted, decrypted;
char premaster[48];
@@ -391,6 +437,7 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this,
}
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
+ this->session, this->peer,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
@@ -402,7 +449,7 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this,
* Process client key exchange, using DHE exchange
*/
static status_t process_key_exchange_dhe(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
chunk_t premaster, pub;
bool ec;
@@ -439,6 +486,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
}
this->crypto->derive_secrets(this->crypto, premaster,
+ this->session, this->peer,
chunk_from_thing(this->client_random),
chunk_from_thing(this->server_random));
chunk_clear(&premaster);
@@ -451,7 +499,7 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this,
* Process Client Key Exchange
*/
static status_t process_key_exchange(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
if (this->dh)
{
@@ -464,19 +512,19 @@ static status_t process_key_exchange(private_tls_server_t *this,
* Process Certificate verify
*/
static status_t process_cert_verify(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
bool verified = FALSE;
enumerator_t *enumerator;
public_key_t *public;
auth_cfg_t *auth;
- tls_reader_t *sig;
+ bio_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));
+ sig = bio_reader_create(reader->peek(reader));
verified = this->crypto->verify_handshake(this->crypto, public, sig);
sig->destroy(sig);
if (verified)
@@ -505,7 +553,7 @@ static status_t process_cert_verify(private_tls_server_t *this,
* Process finished message
*/
static status_t process_finished(private_tls_server_t *this,
- tls_reader_t *reader)
+ bio_reader_t *reader)
{
chunk_t received;
char buf[12];
@@ -535,7 +583,7 @@ static status_t process_finished(private_tls_server_t *this,
}
METHOD(tls_handshake_t, process, status_t,
- private_tls_server_t *this, tls_handshake_type_t type, tls_reader_t *reader)
+ private_tls_server_t *this, tls_handshake_type_t type, bio_reader_t *reader)
{
tls_handshake_type_t expected;
@@ -576,10 +624,7 @@ METHOD(tls_handshake_t, process, status_t,
expected = TLS_CERTIFICATE_VERIFY;
break;
}
- else
- {
- return INVALID_STATE;
- }
+ return INVALID_STATE;
case STATE_CIPHERSPEC_CHANGED_IN:
if (type == TLS_FINISHED)
{
@@ -603,29 +648,14 @@ METHOD(tls_handshake_t, process, status_t,
* Send ServerHello message
*/
static status_t send_server_hello(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
- tls_version_t version;
- rng_t *rng;
-
- htoun32(&this->server_random, time(NULL));
- rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
- if (!rng)
- {
- DBG1(DBG_TLS, "no suitable RNG found to generate server random");
- this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
- return FAILED;
- }
- rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4);
- rng->destroy(rng);
-
/* TLS version */
- version = this->tls->get_version(this->tls);
- writer->write_uint16(writer, version);
+ 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);
+ /* session identifier if we have one */
+ writer->write_data8(writer, this->session);
/* add selected TLS cipher suite */
writer->write_uint16(writer, this->suite);
@@ -643,16 +673,16 @@ static status_t send_server_hello(private_tls_server_t *this,
* Send Certificate
*/
static status_t send_certificate(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
enumerator_t *enumerator;
certificate_t *cert;
auth_rule_t rule;
- tls_writer_t *certs;
+ bio_writer_t *certs;
chunk_t data;
/* generate certificate payload */
- certs = tls_writer_create(256);
+ certs = bio_writer_create(256);
cert = this->server_auth->get(this->server_auth, AUTH_RULE_SUBJECT_CERT);
if (cert)
{
@@ -693,15 +723,15 @@ static status_t send_certificate(private_tls_server_t *this,
* Send Certificate Request
*/
static status_t send_certificate_request(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
- tls_writer_t *authorities, *supported;
+ bio_writer_t *authorities, *supported;
enumerator_t *enumerator;
certificate_t *cert;
x509_t *x509;
identification_t *id;
- supported = tls_writer_create(4);
+ supported = bio_writer_create(4);
/* we propose both RSA and ECDSA */
supported->write_uint8(supported, TLS_RSA_SIGN);
supported->write_uint8(supported, TLS_ECDSA_SIGN);
@@ -712,7 +742,7 @@ static status_t send_certificate_request(private_tls_server_t *this,
this->crypto->get_signature_algorithms(this->crypto, writer);
}
- authorities = tls_writer_create(64);
+ authorities = bio_writer_create(64);
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
CERT_X509, KEY_RSA, NULL, TRUE);
while (enumerator->enumerate(enumerator, &cert))
@@ -763,14 +793,14 @@ static tls_named_curve_t ec_group_to_curve(private_tls_server_t *this,
*/
bool peer_supports_curve(private_tls_server_t *this, tls_named_curve_t curve)
{
- tls_reader_t *reader;
+ bio_reader_t *reader;
u_int16_t current;
if (!this->curves_received)
{ /* none received, assume yes */
return TRUE;
}
- reader = tls_reader_create(this->curves);
+ reader = bio_reader_create(this->curves);
while (reader->remaining(reader) && reader->read_uint16(reader, &current))
{
if (current == curve)
@@ -810,7 +840,7 @@ static bool find_supported_curve(private_tls_server_t *this,
* Send Server key Exchange
*/
static status_t send_server_key_exchange(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer,
+ tls_handshake_type_t *type, bio_writer_t *writer,
diffie_hellman_group_t group)
{
diffie_hellman_params_t *params = NULL;
@@ -887,7 +917,7 @@ static status_t send_server_key_exchange(private_tls_server_t *this,
* Send Hello Done
*/
static status_t send_hello_done(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
*type = TLS_SERVER_HELLO_DONE;
this->state = STATE_HELLO_DONE;
@@ -899,7 +929,7 @@ static status_t send_hello_done(private_tls_server_t *this,
* Send Finished
*/
static status_t send_finished(private_tls_server_t *this,
- tls_handshake_type_t *type, tls_writer_t *writer)
+ tls_handshake_type_t *type, bio_writer_t *writer)
{
char buf[12];
@@ -914,14 +944,13 @@ static status_t send_finished(private_tls_server_t *this,
*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));
+ this->crypto->append_handshake(this->crypto, *type, writer->get_buf(writer));
+
return NEED_MORE;
}
METHOD(tls_handshake_t, build, status_t,
- private_tls_server_t *this, tls_handshake_type_t *type, tls_writer_t *writer)
+ private_tls_server_t *this, tls_handshake_type_t *type, bio_writer_t *writer)
{
diffie_hellman_group_t group;
@@ -956,33 +985,52 @@ METHOD(tls_handshake_t, build, status_t,
}
METHOD(tls_handshake_t, cipherspec_changed, bool,
- private_tls_server_t *this)
+ private_tls_server_t *this, bool inbound)
{
- if (this->state == STATE_FINISHED_RECEIVED)
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, FALSE);
- this->state = STATE_CIPHERSPEC_CHANGED_OUT;
- return TRUE;
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_SENT;
+ }
+ if (this->peer)
+ {
+ return this->state == STATE_CERT_VERIFY_RECEIVED;
+ }
+ return this->state == STATE_KEY_EXCHANGE_RECEIVED;
+ }
+ else
+ {
+ if (this->resume)
+ {
+ return this->state == STATE_HELLO_SENT;
+ }
+ return this->state == STATE_FINISHED_RECEIVED;
}
return FALSE;
}
-METHOD(tls_handshake_t, change_cipherspec, bool,
- private_tls_server_t *this)
+METHOD(tls_handshake_t, change_cipherspec, void,
+ private_tls_server_t *this, bool inbound)
{
- if ((this->peer && this->state == STATE_CERT_VERIFY_RECEIVED) ||
- (!this->peer && this->state == STATE_KEY_EXCHANGE_RECEIVED))
+ this->crypto->change_cipher(this->crypto, inbound);
+ if (inbound)
{
- this->crypto->change_cipher(this->crypto, TRUE);
this->state = STATE_CIPHERSPEC_CHANGED_IN;
- return TRUE;
}
- return FALSE;
+ else
+ {
+ this->state = STATE_CIPHERSPEC_CHANGED_OUT;
+ }
}
METHOD(tls_handshake_t, finished, bool,
private_tls_server_t *this)
{
+ if (this->resume)
+ {
+ return this->state == STATE_FINISHED_RECEIVED;
+ }
return this->state == STATE_FINISHED_SENT;
}
@@ -995,6 +1043,7 @@ METHOD(tls_handshake_t, destroy, void,
this->server_auth->destroy(this->server_auth);
free(this->hashsig.ptr);
free(this->curves.ptr);
+ free(this->session.ptr);
free(this);
}
diff --git a/src/libtls/tls_socket.c b/src/libtls/tls_socket.c
index e0c440a4c..3abff596d 100644
--- a/src/libtls/tls_socket.c
+++ b/src/libtls/tls_socket.c
@@ -16,8 +16,20 @@
#include "tls_socket.h"
#include <unistd.h>
+#include <errno.h>
#include <debug.h>
+#include <threading/thread.h>
+
+/**
+ * Buffer size for plain side I/O
+ */
+#define PLAIN_BUF_SIZE 4096
+
+/**
+ * Buffer size for encrypted side I/O
+ */
+#define CRYPTO_BUF_SIZE 4096
typedef struct private_tls_socket_t private_tls_socket_t;
typedef struct private_tls_application_t private_tls_application_t;
@@ -67,7 +79,7 @@ struct private_tls_socket_t {
};
METHOD(tls_application_t, process, status_t,
- private_tls_application_t *this, tls_reader_t *reader)
+ private_tls_application_t *this, bio_reader_t *reader)
{
chunk_t data;
@@ -80,7 +92,7 @@ METHOD(tls_application_t, process, status_t,
}
METHOD(tls_application_t, build, status_t,
- private_tls_application_t *this, tls_writer_t *writer)
+ private_tls_application_t *this, bio_writer_t *writer)
{
if (this->out.len)
{
@@ -96,8 +108,8 @@ METHOD(tls_application_t, build, status_t,
*/
static bool exchange(private_tls_socket_t *this, bool wr)
{
- char buf[1024];
- ssize_t len;
+ char buf[CRYPTO_BUF_SIZE], *pos;
+ ssize_t len, out;
int round = 0;
for (round = 0; TRUE; round++)
@@ -109,10 +121,18 @@ static bool exchange(private_tls_socket_t *this, bool wr)
{
case NEED_MORE:
case ALREADY_DONE:
- len = write(this->fd, buf, len);
- if (len == -1)
+ pos = buf;
+ while (len)
{
- return FALSE;
+ out = write(this->fd, pos, len);
+ if (out == -1)
+ {
+ DBG1(DBG_TLS, "TLS crypto write error: %s",
+ strerror(errno));
+ return FALSE;
+ }
+ len -= out;
+ pos += out;
}
continue;
case INVALID_STATE:
@@ -175,6 +195,81 @@ METHOD(tls_socket_t, write_, bool,
return FALSE;
}
+METHOD(tls_socket_t, splice, bool,
+ private_tls_socket_t *this, int rfd, int wfd)
+{
+ char buf[PLAIN_BUF_SIZE], *pos;
+ fd_set set;
+ chunk_t data;
+ ssize_t len;
+ bool old;
+
+ while (TRUE)
+ {
+ FD_ZERO(&set);
+ FD_SET(rfd, &set);
+ FD_SET(this->fd, &set);
+
+ old = thread_cancelability(TRUE);
+ len = select(max(rfd, this->fd) + 1, &set, NULL, NULL, NULL);
+ thread_cancelability(old);
+ if (len == -1)
+ {
+ DBG1(DBG_TLS, "TLS select error: %s", strerror(errno));
+ return FALSE;
+ }
+ if (FD_ISSET(this->fd, &set))
+ {
+ if (!read_(this, &data))
+ {
+ DBG2(DBG_TLS, "TLS read error/disconnect");
+ return TRUE;
+ }
+ pos = data.ptr;
+ while (data.len)
+ {
+ len = write(wfd, pos, data.len);
+ if (len == -1)
+ {
+ free(data.ptr);
+ DBG1(DBG_TLS, "TLS plain write error: %s", strerror(errno));
+ return FALSE;
+ }
+ data.len -= len;
+ pos += len;
+ }
+ free(data.ptr);
+ }
+ if (FD_ISSET(rfd, &set))
+ {
+ len = read(rfd, buf, sizeof(buf));
+ if (len > 0)
+ {
+ if (!write_(this, chunk_create(buf, len)))
+ {
+ DBG1(DBG_TLS, "TLS write error");
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (len < 0)
+ {
+ DBG1(DBG_TLS, "TLS plain read error: %s", strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ }
+}
+
+METHOD(tls_socket_t, get_fd, int,
+ private_tls_socket_t *this)
+{
+ return this->fd;
+}
+
METHOD(tls_socket_t, destroy, void,
private_tls_socket_t *this)
{
@@ -187,7 +282,7 @@ METHOD(tls_socket_t, destroy, void,
* See header
*/
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
- identification_t *peer, int fd)
+ identification_t *peer, int fd, tls_cache_t *cache)
{
private_tls_socket_t *this;
@@ -195,6 +290,8 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
.public = {
.read = _read_,
.write = _write_,
+ .splice = _splice,
+ .get_fd = _get_fd,
.destroy = _destroy,
},
.app = {
@@ -208,7 +305,7 @@ tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
);
this->tls = tls_create(is_server, server, peer, TLS_PURPOSE_GENERIC,
- &this->app.application);
+ &this->app.application, cache);
if (!this->tls)
{
free(this);
diff --git a/src/libtls/tls_socket.h b/src/libtls/tls_socket.h
index ac714a385..edd05fd29 100644
--- a/src/libtls/tls_socket.h
+++ b/src/libtls/tls_socket.h
@@ -55,6 +55,25 @@ struct tls_socket_t {
bool (*write)(tls_socket_t *this, chunk_t data);
/**
+ * Read/write plain data from file descriptor.
+ *
+ * This call is blocking, but a thread cancellation point. Data is
+ * exchanged until one of the sockets gets closed or an error occurs.
+ *
+ * @param rfd file descriptor to read plain data from
+ * @param wfd file descriptor to write plain data to
+ * @return TRUE if data exchanged successfully
+ */
+ bool (*splice)(tls_socket_t *this, int rfd, int wfd);
+
+ /**
+ * Get the underlying file descriptor passed to the constructor.
+ *
+ * @return file descriptor
+ */
+ int (*get_fd)(tls_socket_t *this);
+
+ /**
* Destroy a tls_socket_t.
*/
void (*destroy)(tls_socket_t *this);
@@ -67,9 +86,10 @@ struct tls_socket_t {
* @param server server identity
* @param peer client identity, NULL for no client authentication
* @param fd socket to read/write from
+ * @param cache session cache to use, or NULL
* @return TLS socket wrapper
*/
tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
- identification_t *peer, int fd);
+ identification_t *peer, int fd, tls_cache_t *cache);
#endif /** TLS_SOCKET_H_ @}*/
diff --git a/src/libtls/tls_writer.c b/src/libtls/tls_writer.c
deleted file mode 100644
index 57c60fdaf..000000000
--- a/src/libtls/tls_writer.c
+++ /dev/null
@@ -1,237 +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_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, this->used);
- 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, this->used);
- 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, this->used);
-
- 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, this->used);
- 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 ? max(bufsize, 4) : 32,
- );
- if (bufsize)
- {
- this->buf = chunk_alloc(bufsize);
- }
-
- return &this->public;
-}
diff --git a/src/libtls/tls_writer.h b/src/libtls/tls_writer.h
deleted file mode 100644
index d3f09d5da..000000000
--- a/src/libtls/tls_writer.h
+++ /dev/null
@@ -1,136 +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_writer tls_writer
- * @{ @ingroup libtls
- */
-
-#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 8-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 16-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_ @}*/