]> git.sesse.net Git - cubemap/commitdiff
Add server-side TLS support, through kTLS.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Apr 2018 19:03:13 +0000 (21:03 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Apr 2018 19:03:13 +0000 (21:03 +0200)
This, unfortunately, includes a (lightly patched) embedded copy of
the TLS library TLSe in tlse/, since it doesn't really work in any
other way.

23 files changed:
Makefile.in
README
acceptor.cpp
acceptor.h
client.cpp
client.h
config.cpp
config.h
configure.ac
cubemap.config.sample
log.cpp
log.h
main.cpp
server.cpp
server.h
serverpool.cpp
serverpool.h
state.proto
tlse/LICENSE [new file with mode: 0644]
tlse/README [new file with mode: 0644]
tlse/ktls.h [new file with mode: 0644]
tlse/tlse.c [new file with mode: 0644]
tlse/tlse.h [new file with mode: 0644]

index f5da6c6e7303152b0f2e0ae6bae017b6be39197b..c702ef69b91c4546ac57eff5eaec0b3492475230 100644 (file)
@@ -3,11 +3,12 @@ CXX=@CXX@
 INSTALL=install
 PROTOC=protoc
 CPPFLAGS=@CPPFLAGS@
 INSTALL=install
 PROTOC=protoc
 CPPFLAGS=@CPPFLAGS@
-CXXFLAGS=-Wall @CXXFLAGS@ @protobuf_CFLAGS@ @libsystemd_CFLAGS@
+CPPFLAGS += -Itlse -DWITH_KTLS -DNO_TLS_LEGACY_SUPPORT -DNO_SSL_COMPATIBLE_INTERFACE -DLTM_DESC -DTLS_REEXPORTABLE -DNO_TLS_WITH_CHACHA20_POLY1305
+CXXFLAGS=-Wall @CXXFLAGS@ @protobuf_CFLAGS@ @libsystemd_CFLAGS@ @libtomcrypt_CFLAGS@
 LDFLAGS=@LDFLAGS@
 LDFLAGS=@LDFLAGS@
-LIBS=@LIBS@ @protobuf_LIBS@ @libsystemd_LIBS@
+LIBS=@LIBS@ @protobuf_LIBS@ @libsystemd_LIBS@ @libtomcrypt_LIBS@
 
 
-OBJS=main.o client.o server.o stream.o udpstream.o serverpool.o mutexlock.o input.o input_stats.o httpinput.o udpinput.o parse.o config.o acceptor.o stats.o accesslog.o thread.o util.o log.o metacube2.o sa_compare.o timespec.o state.pb.o
+OBJS=main.o client.o server.o stream.o udpstream.o serverpool.o mutexlock.o input.o input_stats.o httpinput.o udpinput.o parse.o config.o acceptor.o stats.o accesslog.o thread.o util.o log.o metacube2.o sa_compare.o timespec.o state.pb.o tlse/tlse.o
 
 all: cubemap
 
 
 all: cubemap
 
@@ -16,6 +17,8 @@ all: cubemap
 
 %.o: %.cpp state.pb.h
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
 
 %.o: %.cpp state.pb.h
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
+%.o: %.c
+       $(CC) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
 %.pb.o: %.pb.cc
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
 cubemap: $(OBJS)
 %.pb.o: %.pb.cc
        $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
 cubemap: $(OBJS)
diff --git a/README b/README
index 056f705b80cc4d9f481c18e273c4284af3dc46ec..5c9119e0297bdd1a703dc0061282a7753ad7be5f 100644 (file)
--- a/README
+++ b/README
@@ -18,12 +18,15 @@ A short list of features:
    has problems reflecting itself (in particular, FLV).
  - Multicast support, both for sending and receiving (supports only protocols
    that can go over UDP, e.g. MPEG-TS). Supports both ASM and SSM.
    has problems reflecting itself (in particular, FLV).
  - Multicast support, both for sending and receiving (supports only protocols
    that can go over UDP, e.g. MPEG-TS). Supports both ASM and SSM.
+ - TLS output support, through the TLSe library (requires libtomcrypt)
+   and the Linux kernel's kTLS (Linux 4.13 or newer). There are a few
+   limitations; see below.
  - IPv4 support. Yes, Cubemap even supports (some) legacy protocols.
 
 
 HOWTO:
 
  - IPv4 support. Yes, Cubemap even supports (some) legacy protocols.
 
 
 HOWTO:
 
-  sudo aptitude install libprotobuf-dev protobuf-compiler libsystemd-dev
+  sudo apt install libprotobuf-dev protobuf-compiler libsystemd-dev libtomcrypt-dev
   ./configure
   make -j4
 
   ./configure
   make -j4
 
@@ -46,6 +49,21 @@ are OK, and then exec() the new version, which deserializes everything and
 keeps going.
 
 
 keeps going.
 
 
+Notes on TLS support:
+
+Cubemap supports TLS on output, so that you can play video on TLS
+web sites without issues with mixed content. TLS on input streams is
+not (yet) supported.
+
+TLS requires kTLS, ie., Linux >= 4.13 with CONFIG_TLS enabled. Only cipher
+suites supported by kTLS is supposed, ie., AES-128-GCM (if no such cipher
+suite is available, the connection will be aborted). If the server is restarted
+before the key exchange for a connection is completed, that connection will
+not survive the restart, unlike all other connections. (This is a TLSe
+limitation.) You can have different certificates on different ports (and
+have separate ports for TLS and non-TLS), but SNI is not yet supported.
+
+
 Munin plugins:
 
 To activate these, symlink them into /etc/munin/plugins. If you don't put
 Munin plugins:
 
 To activate these, symlink them into /etc/munin/plugins. If you don't put
@@ -64,3 +82,5 @@ Legalese:
 
 Copyright 2013 Steinar H. Gunderson <steinar+cubemap@gunderson.no>.
 Licensed under the GNU GPL, version 2. See the included COPYING file.
 
 Copyright 2013 Steinar H. Gunderson <steinar+cubemap@gunderson.no>.
 Licensed under the GNU GPL, version 2. See the included COPYING file.
+
+See tlse/LICENSE for TLSe licensing.
index 7c28ca58038c27b107cad1b8dd82d6dd3b78bd3c..bb3ebcb06cc3f6479a7e620c5ac37dcfb7cb7a0b 100644 (file)
@@ -91,15 +91,20 @@ sockaddr_in6 extract_address_from_acceptor_proto(const AcceptorProto &proto)
        return sin6;
 }
        
        return sin6;
 }
        
-Acceptor::Acceptor(int server_sock, const sockaddr_in6 &addr)
+Acceptor::Acceptor(int server_sock, const sockaddr_in6 &addr,
+                   const string &certificate_chain, const string &private_key)
        : server_sock(server_sock),
        : server_sock(server_sock),
-         addr(addr)
+         addr(addr),
+         certificate_chain(certificate_chain),
+         private_key(private_key)
 {
 }
 
 Acceptor::Acceptor(const AcceptorProto &serialized)
        : server_sock(serialized.server_sock()),
 {
 }
 
 Acceptor::Acceptor(const AcceptorProto &serialized)
        : server_sock(serialized.server_sock()),
-         addr(extract_address_from_acceptor_proto(serialized))
+         addr(extract_address_from_acceptor_proto(serialized)),
+         certificate_chain(serialized.certificate_chain()),
+         private_key(serialized.private_key())
 {
 }
 
 {
 }
 
@@ -112,6 +117,8 @@ AcceptorProto Acceptor::serialize() const
        serialized.set_server_sock(server_sock);
        serialized.set_addr(buf);
        serialized.set_port(ntohs(addr.sin6_port));
        serialized.set_server_sock(server_sock);
        serialized.set_addr(buf);
        serialized.set_port(ntohs(addr.sin6_port));
+       serialized.set_certificate_chain(certificate_chain);
+       serialized.set_private_key(private_key);
        return serialized;
 }
 
        return serialized;
 }
 
@@ -151,6 +158,6 @@ void Acceptor::do_work()
                }
 
                // Pick a server, round-robin, and hand over the socket to it.
                }
 
                // Pick a server, round-robin, and hand over the socket to it.
-               servers->add_client(sock);
+               servers->add_client(sock, this);
        }
 }
        }
 }
index fe62c31396d119ea97addc6bdafae262fef8d452..969ea65889419a38efd6683072be36bf60e9dc35 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <netinet/in.h>
 
 
 #include <netinet/in.h>
 
+#include <string>
+
 #include "thread.h"
 
 enum SocketType {
 #include "thread.h"
 
 enum SocketType {
@@ -20,12 +22,25 @@ sockaddr_in6 extract_address_from_acceptor_proto(const AcceptorProto &proto);
 // and hands them off to the server pool.
 class Acceptor : public Thread {
 public:
 // and hands them off to the server pool.
 class Acceptor : public Thread {
 public:
-       Acceptor(int server_sock, const sockaddr_in6 &addr);
+       Acceptor(int server_sock, const sockaddr_in6 &addr,
+                const std::string &certificate_chain, const std::string &private_key);
 
        // Serialization/deserialization.
        Acceptor(const AcceptorProto &serialized);
        AcceptorProto serialize() const;
 
 
        // Serialization/deserialization.
        Acceptor(const AcceptorProto &serialized);
        AcceptorProto serialize() const;
 
+       bool is_tls() const { return !certificate_chain.empty(); }
+
+       std::string get_certificate_chain() const {
+               assert(is_tls());
+               return certificate_chain;
+       }
+
+       std::string get_private_key() const {
+               assert(is_tls());
+               return private_key;
+       }
+
        void close_socket();
 
 private:
        void close_socket();
 
 private:
@@ -33,6 +48,7 @@ private:
 
        int server_sock;
        sockaddr_in6 addr;
 
        int server_sock;
        sockaddr_in6 addr;
+       std::string certificate_chain, private_key;  // Both empty for no TLS.
 };
 
 #endif  // !defined(_ACCEPTOR_H)
 };
 
 #endif  // !defined(_ACCEPTOR_H)
index 77fad722a6ba9881ad44cc1e3c949beba1a580e9..7c58d515485b03d27e9e26650dacb4c36116781f 100644 (file)
@@ -23,7 +23,11 @@ Client::Client(int sock)
          stream_pos(0),
          bytes_sent(0),
          bytes_lost(0),
          stream_pos(0),
          bytes_sent(0),
          bytes_lost(0),
-         num_loss_events(0)
+         num_loss_events(0),
+         tls_context(NULL),
+         tls_data_to_send(NULL),
+         tls_data_left_to_send(0),
+         in_ktls_mode(false)
 {
        request.reserve(1024);
 
 {
        request.reserve(1024);
 
@@ -86,6 +90,30 @@ Client::Client(const ClientProto &serialized, Stream *stream)
        }
        connect_time.tv_sec = serialized.connect_time_sec();
        connect_time.tv_nsec = serialized.connect_time_nsec();
        }
        connect_time.tv_sec = serialized.connect_time_sec();
        connect_time.tv_nsec = serialized.connect_time_nsec();
+
+       in_ktls_mode = false;
+       if (serialized.has_tls_context()) {
+               tls_context = tls_import_context(
+                       reinterpret_cast<const unsigned char *>(serialized.tls_context().data()),
+                       serialized.tls_context().size());
+               if (tls_context == NULL) {
+                       log(WARNING, "tls_import_context() failed, TLS client might not survive across restart");
+               } else {
+                       tls_data_to_send = tls_get_write_buffer(tls_context, &tls_data_left_to_send);
+
+                       assert(serialized.tls_output_bytes_already_consumed() <= tls_data_left_to_send);
+                       if (serialized.tls_output_bytes_already_consumed() >= tls_data_left_to_send) {
+                               tls_buffer_clear(tls_context);
+                               tls_data_to_send = NULL;
+                       } else {
+                               tls_data_to_send += serialized.tls_output_bytes_already_consumed();
+                               tls_data_left_to_send -= serialized.tls_output_bytes_already_consumed();
+                       }
+                       in_ktls_mode = serialized.in_ktls_mode();
+               }
+       } else {
+               tls_context = NULL;
+       }
 }
 
 ClientProto Client::serialize() const
 }
 
 ClientProto Client::serialize() const
@@ -106,6 +134,46 @@ ClientProto Client::serialize() const
        serialized.set_bytes_sent(bytes_sent);
        serialized.set_bytes_lost(bytes_lost);
        serialized.set_num_loss_events(num_loss_events);
        serialized.set_bytes_sent(bytes_sent);
        serialized.set_bytes_lost(bytes_lost);
        serialized.set_num_loss_events(num_loss_events);
+
+       if (tls_context != NULL) {
+               bool small_version = false;
+               int required_size = tls_export_context(tls_context, NULL, 0, small_version);
+               if (required_size <= 0) {
+                       // Can happen if we're in the middle of the key exchange, unfortunately.
+                       // We'll get an error fairly fast, and this client hasn't started playing
+                       // anything yet, so just log the error and continue.
+                       //
+                       // In theory, we could still rescue it if we had sent _zero_ bytes,
+                       // by doing an entirely new TLS context, but it's an edge case
+                       // that's not really worth it.
+                       log(WARNING, "tls_export_context() failed (returned %d), TLS client might not survive across restart",
+                               required_size);
+               } else {
+                       string *serialized_context = serialized.mutable_tls_context();
+                       serialized_context->resize(required_size);
+
+                       int ret = tls_export_context(tls_context,
+                               reinterpret_cast<unsigned char *>(&(*serialized_context)[0]),
+                               serialized_context->size(),
+                               small_version);
+                       assert(ret == required_size);
+
+                       // tls_export_context() has exported the contents of the write buffer, but it doesn't
+                       // know how much of that we've consumed, so we need to figure that out by ourselves.
+                       // In a sense, it's unlikely that this will ever be relevant, though, since TLSe can't
+                       // currently serialize in-progress key exchanges.
+                       unsigned base_tls_data_left_to_send;
+                       const unsigned char *base_tls_data_to_send = tls_get_write_buffer(tls_context, &base_tls_data_left_to_send);
+                       if (base_tls_data_to_send == NULL) {
+                               assert(tls_data_to_send == NULL);
+                       } else {
+                               assert(tls_data_to_send + tls_data_left_to_send == base_tls_data_to_send + base_tls_data_left_to_send);
+                       }
+                       serialized.set_tls_output_bytes_already_consumed(tls_data_to_send - base_tls_data_to_send);
+                       serialized.set_in_ktls_mode(in_ktls_mode);
+               }
+       }
+
        return serialized;
 }
 
        return serialized;
 }
 
index 2ee478375fd9edcda5da464c90907b0e41f7e0e6..666e3b417c1e6db142bc2c34d759be902dc27d56 100644 (file)
--- a/client.h
+++ b/client.h
@@ -7,6 +7,8 @@
 #include <time.h>
 #include <string>
 
 #include <time.h>
 #include <string>
 
+#include "tlse.h"
+
 class ClientProto;
 struct Stream;
 
 class ClientProto;
 struct Stream;
 
@@ -81,6 +83,11 @@ struct Client {
        // Number of times we've skipped forward due to the backlog being too big,
        // and how many bytes we've skipped over in all. Only relevant for SENDING_DATA.
        size_t bytes_lost, num_loss_events;
        // Number of times we've skipped forward due to the backlog being too big,
        // and how many bytes we've skipped over in all. Only relevant for SENDING_DATA.
        size_t bytes_lost, num_loss_events;
+
+       TLSContext *tls_context;
+       const unsigned char *tls_data_to_send;
+       unsigned tls_data_left_to_send;
+       bool in_ktls_mode;
 };
 
 #endif  // !defined(_CLIENT_H)
 };
 
 #endif  // !defined(_CLIENT_H)
index 2e680b818c111ca02490688cc3ac1bcb34365204..47118b48612e18bce0966c7bb696326532cf277e 100644 (file)
@@ -12,6 +12,8 @@
 #include <utility>
 #include <vector>
 
 #include <utility>
 #include <vector>
 
+#include "tlse.h"
+
 #include "acceptor.h"
 #include "config.h"
 #include "log.h"
 #include "acceptor.h"
 #include "config.h"
 #include "log.h"
@@ -174,6 +176,104 @@ bool fetch_config_int(const vector<ConfigLine> &config, const string &keyword, i
        return false;
 }
 
        return false;
 }
 
+bool load_file_to_string(const string &filename, size_t max_size, string *contents)
+{
+       contents->clear();
+
+       FILE *fp = fopen(filename.c_str(), "r");
+       if (fp == NULL) {
+               log_perror(filename.c_str());
+               return false;
+       }
+
+       char buf[4096];
+       while (!feof(fp)) {
+               size_t ret = fread(buf, 1, sizeof(buf), fp);
+               if (ret > 0) {
+                       contents->append(buf, buf + ret);
+               } else {
+                       if (ferror(fp)) {
+                               log_perror(filename.c_str());
+                               fclose(fp);
+                               return false;
+                       }
+                       assert(feof(fp));
+                       break;
+               }
+
+               if (contents->size() > max_size) {
+                       log(ERROR, "%s was longer than the maximum allowed %zu bytes", filename.c_str(), max_size);
+                       fclose(fp);
+                       return false;
+               }
+       }
+       fclose(fp);
+       return true;
+}
+
+bool parse_tls_parameters(const map<string, string> &parameters, AcceptorConfig *acceptor)
+{
+       bool has_cert = false, has_key = false;
+
+       map<string, string>::const_iterator tls_cert_it = parameters.find("tls_cert");
+       if (tls_cert_it != parameters.end()) {
+               if (!load_file_to_string(tls_cert_it->second, 1048576, &acceptor->certificate_chain)) {
+                       return false;
+               }
+
+               // Verify that the certificate is valid.
+               bool is_server = true;
+               TLSContext *server_context = tls_create_context(is_server, TLS_V12);
+               int num_cert = tls_load_certificates(
+                       server_context,
+                       reinterpret_cast<const unsigned char *>(acceptor->certificate_chain.data()),
+                       acceptor->certificate_chain.size());
+               if (num_cert < 0) {
+                       log_tls_error(tls_cert_it->second.c_str(), num_cert);
+                       tls_destroy_context(server_context);
+                       return false;
+               } else if (num_cert == 0) {
+                       log(ERROR, "%s did not contain any certificates", tls_cert_it->second.c_str());
+                       return false;
+               }
+               tls_destroy_context(server_context);
+               has_cert = true;
+       }
+
+       map<string, string>::const_iterator tls_key_it = parameters.find("tls_key");
+       if (tls_key_it != parameters.end()) {
+               if (!load_file_to_string(tls_key_it->second, 1048576, &acceptor->private_key)) {
+                       return false;
+               }
+
+               // Verify that the key is valid.
+               bool is_server = true;
+               TLSContext *server_context = tls_create_context(is_server, TLS_V12);
+               int num_keys = tls_load_private_key(
+                       server_context,
+                       reinterpret_cast<const unsigned char *>(acceptor->private_key.data()),
+                       acceptor->private_key.size());
+               if (num_keys < 0) {
+                       log_tls_error(tls_key_it->second.c_str(), num_keys);
+                       tls_destroy_context(server_context);
+                       return false;
+               } else if (num_keys == 0) {
+                       log(ERROR, "%s did not contain any private keys", tls_key_it->second.c_str());
+                       return false;
+               }
+               tls_destroy_context(server_context);
+               has_key = true;
+       }
+
+       if (has_cert != has_key) {
+               log(ERROR, "Only one of tls_cert= and tls_key= was given, needs zero or both");
+               return false;
+       }
+
+       return true;
+}
+
+
 bool parse_port(const ConfigLine &line, Config *config)
 {
        if (line.arguments.size() != 1) {
 bool parse_port(const ConfigLine &line, Config *config)
 {
        if (line.arguments.size() != 1) {
@@ -190,6 +290,9 @@ bool parse_port(const ConfigLine &line, Config *config)
        AcceptorConfig acceptor;
        acceptor.addr = create_any_address(port);
 
        AcceptorConfig acceptor;
        acceptor.addr = create_any_address(port);
 
+       if (!parse_tls_parameters(line.parameters, &acceptor)) {
+               return false;
+       }
        config->acceptors.push_back(acceptor);
        return true;
 }
        config->acceptors.push_back(acceptor);
        return true;
 }
@@ -205,6 +308,9 @@ bool parse_listen(const ConfigLine &line, Config *config)
        if (!parse_hostport(line.arguments[0], &acceptor.addr)) {
                return false;
        }
        if (!parse_hostport(line.arguments[0], &acceptor.addr)) {
                return false;
        }
+       if (!parse_tls_parameters(line.parameters, &acceptor)) {
+               return false;
+       }
        config->acceptors.push_back(acceptor);
        return true;
 }
        config->acceptors.push_back(acceptor);
        return true;
 }
index 2e052876cd0a43e3bfa381c4db385dcc0a77abc2..4d78a37caa76ae2313925c4da92e1bdf1155bc21 100644 (file)
--- a/config.h
+++ b/config.h
@@ -35,6 +35,8 @@ struct Gen204Config {
 
 struct AcceptorConfig {
        sockaddr_in6 addr;
 
 struct AcceptorConfig {
        sockaddr_in6 addr;
+
+       std::string certificate_chain, private_key;  // In PEM format.
 };
 
 struct LogConfig {
 };
 
 struct LogConfig {
index 02c735475f79d193f3de00d831b5d24d7d8f2b45..e3ac3765a196cc9a685009a679861c6b872954d4 100644 (file)
@@ -1,5 +1,5 @@
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_MACRO_DIR([m4])
-AC_INIT(cubemap, 1.2.2-pre)
+AC_INIT(cubemap, 1.4.0-pre)
 
 AC_CONFIG_SRCDIR(main.cpp)
 
 
 AC_CONFIG_SRCDIR(main.cpp)
 
@@ -8,6 +8,7 @@ AC_SYS_LARGEFILE
 PKG_PROG_PKG_CONFIG
 PKG_CHECK_MODULES([libsystemd], [libsystemd])
 PKG_CHECK_MODULES([protobuf], [protobuf])
 PKG_PROG_PKG_CONFIG
 PKG_CHECK_MODULES([libsystemd], [libsystemd])
 PKG_CHECK_MODULES([protobuf], [protobuf])
+PKG_CHECK_MODULES([libtomcrypt], [libtomcrypt])
 
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
 
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
index 0d283ddbb748a49dca2ceb03b14046a9bf691567..c1780ece46315230e0d40cd41f0fd34e1f381aa4 100644 (file)
@@ -9,7 +9,10 @@
 num_servers 1
 
 #
 num_servers 1
 
 #
-# All input ports are treated exactly the same, but you may use multiple ones nevertheless.
+# You may specify multiple input ports; save for TLS settings (TLS is automatically
+# enabled for a port if you give a key pair), they are treated exactly the same.
+# “port N” is equivalent to “listen [::]:N”. TLS requires kTLS support (Linux >= 4.13,
+# CONFIG_TLS enabled).
 #
 port 9094
 # listen 127.0.0.1:9095
 #
 port 9094
 # listen 127.0.0.1:9095
diff --git a/log.cpp b/log.cpp
index 409639fed7fa02e913b7024db82c6a92a8ca9f3a..417b544974d30754103bcb2640d0dce6c600f116 100644 (file)
--- a/log.cpp
+++ b/log.cpp
@@ -9,6 +9,8 @@
 #include <string>
 #include <vector>
 
 #include <string>
 #include <vector>
 
+#include "tlse.h"
+
 #include "log.h"
 
 using namespace std;
 #include "log.h"
 
 using namespace std;
@@ -126,3 +128,66 @@ void log_perror(const char *msg)
        char errbuf[4096];
        log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
 }
        char errbuf[4096];
        log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
 }
+
+void log_tls_error(const char *msg, int tls_err)
+{
+       switch (tls_err) {
+       case TLS_NEED_MORE_DATA:
+               log(ERROR, "%s: Need more data (TLS)", msg);
+               break;
+       case TLS_GENERIC_ERROR:
+               log(ERROR, "%s: Generic TLS error", msg);
+               break;
+       case TLS_BROKEN_PACKET:
+               log(ERROR, "%s: Broken TLS packet", msg);
+               break;
+       case TLS_NOT_UNDERSTOOD:
+               log(ERROR, "%s: Not understood (TLS)", msg);
+               break;
+       case TLS_NOT_SAFE:
+               log(ERROR, "%s: Not safe (TLS)", msg);
+               break;
+       case TLS_NO_COMMON_CIPHER:
+               log(ERROR, "%s: No common TLS cipher", msg);
+               break;
+       case TLS_UNEXPECTED_MESSAGE:
+               log(ERROR, "%s: Unexpected TLS message", msg);
+               break;
+       case TLS_CLOSE_CONNECTION:
+               log(ERROR, "%s: Close TLS connection", msg);
+               break;
+       case TLS_COMPRESSION_NOT_SUPPORTED:
+               log(ERROR, "%s: TLS compression not supported", msg);
+               break;
+       case TLS_NO_MEMORY:
+               log(ERROR, "%s: No TLS memory", msg);
+               break;
+       case TLS_NOT_VERIFIED:
+               log(ERROR, "%s: Not verified (TLS)", msg);
+               break;
+       case TLS_INTEGRITY_FAILED:
+               log(ERROR, "%s: TLS integrity failed", msg);
+               break;
+       case TLS_ERROR_ALERT:
+               log(ERROR, "%s: TLS alert", msg);
+               break;
+       case TLS_BROKEN_CONNECTION:
+               log(ERROR, "%s: Broken TLS connection", msg);
+               break;
+       case TLS_BAD_CERTIFICATE:
+               log(ERROR, "%s: Bad TLS certificate", msg);
+               break;
+       case TLS_UNSUPPORTED_CERTIFICATE:
+               log(ERROR, "%s: Unsupported TLS certificate", msg);
+               break;
+       case TLS_NO_RENEGOTIATION:
+               log(ERROR, "%s: No TLS renegotiation", msg);
+               break;
+       case TLS_FEATURE_NOT_SUPPORTED:
+               log(ERROR, "%s: TLS feature not supported", msg);
+               break;
+       default:
+               log(ERROR, "%s: Unknown TLS error %d", msg, tls_err);
+               break;
+       }
+}
diff --git a/log.h b/log.h
index 9ba0b5ab728b427811e781a92ad5d5e7193b53d8..ff1d8e63f224eadf688a968696e3bfa5c6d60110 100644 (file)
--- a/log.h
+++ b/log.h
@@ -20,5 +20,6 @@ void shut_down_logging();
 
 void log(LogLevel log_level, const char *fmt, ...);
 void log_perror(const char *msg);
 
 void log(LogLevel log_level, const char *fmt, ...);
 void log_perror(const char *msg);
+void log_tls_error(const char *msg, int tls_err);
 
 #endif  // !defined(_LOG_H)
 
 #endif  // !defined(_LOG_H)
index 0b8825a9da595b6f36bf7247cd75cfd25bdb619a..33ed9dfba726bc8b5332d42a3fcae2e4ceca54f5 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -18,6 +18,8 @@
 #include <utility>
 #include <vector>
 
 #include <utility>
 #include <vector>
 
+#include "tlse.h"
+
 #include "acceptor.h"
 #include "accesslog.h"
 #include "config.h"
 #include "acceptor.h"
 #include "accesslog.h"
 #include "config.h"
@@ -51,6 +53,23 @@ struct OrderByConnectionTime {
        }
 };
 
        }
 };
 
+// An arbitrary ordering.
+struct AcceptorConfigCompare {
+       bool operator() (const AcceptorConfig &a, const AcceptorConfig &b) const {
+               int cmp = a.certificate_chain.compare(b.certificate_chain);
+               if (cmp != 0) {
+                       return cmp < 0;
+               }
+
+               cmp = a.private_key.compare(b.private_key);
+               if (cmp != 0) {
+                       return cmp < 0;
+               }
+
+               return Sockaddr6Compare()(a.addr, b.addr);
+       }
+};
+
 }  // namespace
 
 struct InputWithRefcount {
 }  // namespace
 
 struct InputWithRefcount {
@@ -92,30 +111,32 @@ CubemapStateProto collect_state(const timespec &serialize_start,
        return state;
 }
 
        return state;
 }
 
-// Find all port statements in the configuration file, and create acceptors for htem.
+// Find all port statements in the configuration file, and create acceptors for them.
 vector<Acceptor *> create_acceptors(
        const Config &config,
 vector<Acceptor *> create_acceptors(
        const Config &config,
-       map<sockaddr_in6, Acceptor *, Sockaddr6Compare> *deserialized_acceptors)
+       map<AcceptorConfig, Acceptor *, AcceptorConfigCompare> *deserialized_acceptors)
 {
        vector<Acceptor *> acceptors;
        for (unsigned i = 0; i < config.acceptors.size(); ++i) {
                const AcceptorConfig &acceptor_config = config.acceptors[i];
                Acceptor *acceptor = NULL;
 {
        vector<Acceptor *> acceptors;
        for (unsigned i = 0; i < config.acceptors.size(); ++i) {
                const AcceptorConfig &acceptor_config = config.acceptors[i];
                Acceptor *acceptor = NULL;
-               map<sockaddr_in6, Acceptor *, Sockaddr6Compare>::iterator deserialized_acceptor_it =
-                       deserialized_acceptors->find(acceptor_config.addr);
+               map<AcceptorConfig, Acceptor *, AcceptorConfigCompare>::iterator deserialized_acceptor_it =
+                       deserialized_acceptors->find(acceptor_config);
                if (deserialized_acceptor_it != deserialized_acceptors->end()) {
                        acceptor = deserialized_acceptor_it->second;
                        deserialized_acceptors->erase(deserialized_acceptor_it);
                } else {
                        int server_sock = create_server_socket(acceptor_config.addr, TCP_SOCKET);
                if (deserialized_acceptor_it != deserialized_acceptors->end()) {
                        acceptor = deserialized_acceptor_it->second;
                        deserialized_acceptors->erase(deserialized_acceptor_it);
                } else {
                        int server_sock = create_server_socket(acceptor_config.addr, TCP_SOCKET);
-                       acceptor = new Acceptor(server_sock, acceptor_config.addr);
+                       acceptor = new Acceptor(server_sock, acceptor_config.addr,
+                                               acceptor_config.certificate_chain,
+                                               acceptor_config.private_key);
                }
                acceptor->run();
                acceptors.push_back(acceptor);
        }
 
        // Close all acceptors that are no longer in the configuration file.
                }
                acceptor->run();
                acceptors.push_back(acceptor);
        }
 
        // Close all acceptors that are no longer in the configuration file.
-       for (map<sockaddr_in6, Acceptor *, Sockaddr6Compare>::iterator
+       for (map<AcceptorConfig, Acceptor *, AcceptorConfigCompare>::iterator
                 acceptor_it = deserialized_acceptors->begin();
             acceptor_it != deserialized_acceptors->end();
             ++acceptor_it) {
                 acceptor_it = deserialized_acceptors->begin();
             acceptor_it != deserialized_acceptors->end();
             ++acceptor_it) {
@@ -318,6 +339,8 @@ int main(int argc, char **argv)
        signal(SIGINT, hup);
        signal(SIGUSR1, do_nothing);  // Used in internal signalling.
        signal(SIGPIPE, SIG_IGN);
        signal(SIGINT, hup);
        signal(SIGUSR1, do_nothing);  // Used in internal signalling.
        signal(SIGPIPE, SIG_IGN);
+
+       tls_init();
        
        // Parse options.
        int state_fd = -1;
        
        // Parse options.
        int state_fd = -1;
@@ -406,7 +429,7 @@ start:
        CubemapStateProto loaded_state;
        timespec serialize_start;
        set<string> deserialized_urls;
        CubemapStateProto loaded_state;
        timespec serialize_start;
        set<string> deserialized_urls;
-       map<sockaddr_in6, Acceptor *, Sockaddr6Compare> deserialized_acceptors;
+       map<AcceptorConfig, Acceptor *, AcceptorConfigCompare> deserialized_acceptors;
        multimap<InputKey, InputWithRefcount> inputs;  // multimap due to older versions without deduplication.
        if (state_fd != -1) {
                log(INFO, "Deserializing state from previous process...");
        multimap<InputKey, InputWithRefcount> inputs;  // multimap due to older versions without deduplication.
        if (state_fd != -1) {
                log(INFO, "Deserializing state from previous process...");
@@ -462,9 +485,12 @@ start:
 
                // Deserialize the acceptors.
                for (int i = 0; i < loaded_state.acceptors_size(); ++i) {
 
                // Deserialize the acceptors.
                for (int i = 0; i < loaded_state.acceptors_size(); ++i) {
-                       sockaddr_in6 sin6 = extract_address_from_acceptor_proto(loaded_state.acceptors(i));
+                       AcceptorConfig config;
+                       config.addr = extract_address_from_acceptor_proto(loaded_state.acceptors(i));
+                       config.certificate_chain = loaded_state.acceptors(i).certificate_chain();
+                       config.private_key = loaded_state.acceptors(i).private_key();
                        deserialized_acceptors.insert(make_pair(
                        deserialized_acceptors.insert(make_pair(
-                               sin6,
+                               config,
                                new Acceptor(loaded_state.acceptors(i))));
                }
 
                                new Acceptor(loaded_state.acceptors(i))));
                }
 
@@ -477,6 +503,13 @@ start:
        // Find all streams in the configuration file, create them, and connect to the inputs.
        create_streams(config, deserialized_urls, &inputs);
        vector<Acceptor *> acceptors = create_acceptors(config, &deserialized_acceptors);
        // Find all streams in the configuration file, create them, and connect to the inputs.
        create_streams(config, deserialized_urls, &inputs);
        vector<Acceptor *> acceptors = create_acceptors(config, &deserialized_acceptors);
+
+       // Make all the servers create TLS contexts for every TLS keypair we have.
+       for (Acceptor *acceptor : acceptors) {
+               if (acceptor->is_tls()) {
+                       servers->create_tls_context_for_acceptor(acceptor);
+               }
+       }
        
        // Put back the existing clients. It doesn't matter which server we
        // allocate them to, so just do round-robin. However, we need to sort them
        
        // Put back the existing clients. It doesn't matter which server we
        // allocate them to, so just do round-robin. However, we need to sort them
index 608ed6b70b504e0d0ff4152f77568b6a5fac1236..dbfe19b51d91981b348e738ebeee332e952db9fa 100644 (file)
@@ -17,6 +17,9 @@
 #include <utility>
 #include <vector>
 
 #include <utility>
 #include <vector>
 
+#include "tlse.h"
+
+#include "acceptor.h"
 #include "accesslog.h"
 #include "log.h"
 #include "metacube2.h"
 #include "accesslog.h"
 #include "log.h"
 #include "metacube2.h"
@@ -204,14 +207,15 @@ CubemapStateProto Server::serialize()
        return serialized;
 }
 
        return serialized;
 }
 
-void Server::add_client_deferred(int sock)
+void Server::add_client_deferred(int sock, Acceptor *acceptor)
 {
        MutexLock lock(&queued_clients_mutex);
 {
        MutexLock lock(&queued_clients_mutex);
-       queued_add_clients.push_back(sock);
+       queued_add_clients.push_back(std::make_pair(sock, acceptor));
 }
 
 }
 
-void Server::add_client(int sock)
+void Server::add_client(int sock, Acceptor *acceptor)
 {
 {
+       const bool is_tls = acceptor->is_tls();
        pair<map<int, Client>::iterator, bool> ret =
                clients.insert(make_pair(sock, Client(sock)));
        assert(ret.second == true);  // Should not already exist.
        pair<map<int, Client>::iterator, bool> ret =
                clients.insert(make_pair(sock, Client(sock)));
        assert(ret.second == true);  // Should not already exist.
@@ -230,13 +234,32 @@ void Server::add_client(int sock)
 
        // Start listening on data from this socket.
        epoll_event ev;
 
        // Start listening on data from this socket.
        epoll_event ev;
-       ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
+       if (is_tls) {
+               // Even in the initial state (READING_REQUEST), TLS needs to
+               // send data for the handshake, and thus might end up needing
+               // to know about EPOLLOUT.
+               ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP;
+       } else {
+               // EPOLLOUT will be added once we go out of READING_REQUEST.
+               ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
+       }
        ev.data.u64 = reinterpret_cast<uint64_t>(client_ptr);
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) == -1) {
                log_perror("epoll_ctl(EPOLL_CTL_ADD)");
                exit(1);
        }
 
        ev.data.u64 = reinterpret_cast<uint64_t>(client_ptr);
        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) == -1) {
                log_perror("epoll_ctl(EPOLL_CTL_ADD)");
                exit(1);
        }
 
+       if (is_tls) {
+               assert(tls_server_contexts.count(acceptor));
+               client_ptr->tls_context = tls_accept(tls_server_contexts[acceptor]);
+               if (client_ptr->tls_context == NULL) {
+                       log(ERROR, "tls_accept() failed");
+                       close_client(client_ptr);
+                       return;
+               }
+               tls_make_exportable(client_ptr->tls_context, 1);
+       }
+
        process_client(client_ptr);
 }
 
        process_client(client_ptr);
 }
 
@@ -264,7 +287,12 @@ void Server::add_client_from_serialized(const ClientProto &client)
        // Start listening on data from this socket.
        epoll_event ev;
        if (client.state() == Client::READING_REQUEST) {
        // Start listening on data from this socket.
        epoll_event ev;
        if (client.state() == Client::READING_REQUEST) {
-               ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
+               // See the corresponding comment in Server::add_client().
+               if (client.has_tls_context()) {
+                       ev.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP;
+               } else {
+                       ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
+               }
        } else {
                // If we don't have more data for this client, we'll be putting it into
                // the sleeping array again soon.
        } else {
                // If we don't have more data for this client, we'll be putting it into
                // the sleeping array again soon.
@@ -373,6 +401,24 @@ void Server::add_gen204(const std::string &url, const std::string &allow_origin)
        ping_url_map[url] = allow_origin;
 }
 
        ping_url_map[url] = allow_origin;
 }
 
+void Server::create_tls_context_for_acceptor(const Acceptor *acceptor)
+{
+       assert(acceptor->is_tls());
+
+       bool is_server = true;
+       TLSContext *server_context = tls_create_context(is_server, TLS_V12);
+
+       const string &cert = acceptor->get_certificate_chain();
+       int num_cert = tls_load_certificates(server_context, reinterpret_cast<const unsigned char *>(cert.data()), cert.size());
+       assert(num_cert > 0);  // Should have been checked by config earlier.
+
+       const string &key = acceptor->get_private_key();
+       int num_key = tls_load_private_key(server_context, reinterpret_cast<const unsigned char *>(key.data()), key.size());
+       assert(num_key > 0);  // Should have been checked by config earlier.
+
+       tls_server_contexts.insert(make_pair(acceptor, server_context));
+}
+
 void Server::add_data_deferred(int stream_index, const char *data, size_t bytes, uint16_t metacube_flags)
 {
        assert(stream_index >= 0 && stream_index < ssize_t(streams.size()));
 void Server::add_data_deferred(int stream_index, const char *data, size_t bytes, uint16_t metacube_flags)
 {
        assert(stream_index >= 0 && stream_index < ssize_t(streams.size()));
@@ -384,28 +430,29 @@ void Server::process_client(Client *client)
 {
        switch (client->state) {
        case Client::READING_REQUEST: {
 {
        switch (client->state) {
        case Client::READING_REQUEST: {
+               if (client->tls_context != NULL) {
+                       if (send_pending_tls_data(client)) {
+                               // send_pending_tls_data() hit postconditions #1 or #4.
+                               return;
+                       }
+               }
+
 read_request_again:
                // Try to read more of the request.
                char buf[1024];
                int ret;
 read_request_again:
                // Try to read more of the request.
                char buf[1024];
                int ret;
-               do {
-                       ret = read(client->sock, buf, sizeof(buf));
-               } while (ret == -1 && errno == EINTR);
-
-               if (ret == -1 && errno == EAGAIN) {
-                       // No more data right now. Nothing to do.
-                       // This is postcondition #2.
-                       return;
-               }
-               if (ret == -1) {
-                       log_perror("read");
-                       close_client(client);
-                       return;
-               }
-               if (ret == 0) {
-                       // OK, the socket is closed.
-                       close_client(client);
-                       return;
+               if (client->tls_context == NULL) {
+                       ret = read_nontls_data(client, buf, sizeof(buf));
+                       if (ret == -1) {
+                               // read_nontls_data() hit postconditions #1 or #2.
+                               return;
+                       }
+               } else {
+                       ret = read_tls_data(client, buf, sizeof(buf));
+                       if (ret == -1) {
+                               // read_tls_data() hit postconditions #1, #2 or #4.
+                               return;
+                       }
                }
 
                RequestParseStatus status = wait_for_double_newline(&client->request, buf, ret);
                }
 
                RequestParseStatus status = wait_for_double_newline(&client->request, buf, ret);
@@ -429,6 +476,22 @@ read_request_again:
 
                assert(status == RP_FINISHED);
 
 
                assert(status == RP_FINISHED);
 
+               if (client->tls_context && !client->in_ktls_mode && tls_established(client->tls_context)) {
+                       // We're ready to enter kTLS mode, unless we still have some
+                       // handshake data to send (which then must be sent as non-kTLS).
+                       if (send_pending_tls_data(client)) {
+                               // send_pending_tls_data() hit postconditions #1 or #4.
+                               return;
+                       }
+                       ret = tls_make_ktls(client->tls_context, client->sock);
+                       if (ret < 0) {
+                               log_tls_error("tls_make_ktls", ret);
+                               close_client(client);
+                               return;
+                       }
+                       client->in_ktls_mode = true;
+               }
+
                int error_code = parse_request(client);
                if (error_code == 200) {
                        construct_header(client);
                int error_code = parse_request(client);
                if (error_code == 200) {
                        construct_header(client);
@@ -607,6 +670,133 @@ sending_data_again:
        }
 }
 
        }
 }
 
+bool Server::send_pending_tls_data(Client *client)
+{
+       // See if there's data from the TLS library to write.
+       if (client->tls_data_to_send == NULL) {
+               client->tls_data_to_send = tls_get_write_buffer(client->tls_context, &client->tls_data_left_to_send);
+               if (client->tls_data_to_send == NULL) {
+                       // Really no data to send.
+                       return false;
+               }
+       }
+
+send_data_again:
+       int ret;
+       do {
+               ret = write(client->sock, client->tls_data_to_send, client->tls_data_left_to_send);
+       } while (ret == -1 && errno == EINTR);
+       assert(ret < 0 || size_t(ret) <= client->tls_data_left_to_send);
+
+       if (ret == -1 && errno == EAGAIN) {
+               // We're out of socket space, so now we're at the “low edge” of epoll's
+               // edge triggering. epoll will tell us when there is more room, so for now,
+               // just return.
+               // This is postcondition #4.
+               return true;
+       }
+       if (ret == -1) {
+               // Error! Postcondition #1.
+               log_perror("write");
+               close_client(client);
+               return true;
+       }
+       if (ret > 0 && size_t(ret) == client->tls_data_left_to_send) {
+               // All data has been sent, so we don't need to go to sleep.
+               tls_buffer_clear(client->tls_context);
+               client->tls_data_to_send = NULL;
+               return false;
+       }
+
+       // More data to send, so try again.
+       client->tls_data_to_send += ret;
+       client->tls_data_left_to_send -= ret;
+       goto send_data_again;
+}
+
+int Server::read_nontls_data(Client *client, char *buf, size_t max_size)
+{
+       int ret;
+       do {
+               ret = read(client->sock, buf, max_size);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret == -1 && errno == EAGAIN) {
+               // No more data right now. Nothing to do.
+               // This is postcondition #2.
+               return -1;
+       }
+       if (ret == -1) {
+               log_perror("read");
+               close_client(client);
+               return -1;
+       }
+       if (ret == 0) {
+               // OK, the socket is closed.
+               close_client(client);
+               return -1;
+       }
+
+       return ret;
+}
+
+int Server::read_tls_data(Client *client, char *buf, size_t max_size)
+{
+read_again:
+       int ret;
+       do {
+               ret = read(client->sock, buf, max_size);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret == -1 && errno == EAGAIN) {
+               // No more data right now. Nothing to do.
+               // This is postcondition #2.
+               return -1;
+       }
+       if (ret == -1) {
+               log_perror("read");
+               close_client(client);
+               return -1;
+       }
+       if (ret == 0) {
+               // OK, the socket is closed.
+               close_client(client);
+               return -1;
+       }
+
+       // Give it to the TLS library.
+       int err = tls_consume_stream(client->tls_context, reinterpret_cast<const unsigned char *>(buf), ret, nullptr);
+       if (err < 0) {
+               log_tls_error("tls_consume_stream", err);
+               close_client(client);
+               return -1;
+       }
+       if (err == 0) {
+               // Not consumed any data. See if we can read more.
+               goto read_again;
+       }
+
+       // Read any decrypted data available for us. (We can reuse buf, since it's free now.)
+       ret = tls_read(client->tls_context, reinterpret_cast<unsigned char *>(buf), max_size);
+       if (ret == 0) {
+               // No decrypted data for us yet, but there might be some more handshaking
+               // to send. Do that if needed, then look for more data.
+               if (send_pending_tls_data(client)) {
+                       // send_pending_tls_data() hit postconditions #1 or #4.
+                       return -1;
+               }
+               goto read_again;
+       }
+       if (ret < 0) {
+               log_tls_error("tls_read", ret);
+               close_client(client);
+               return -1;
+       }
+
+       assert(ret > 0);
+       return ret;
+}
+
 // See if there's some data we've lost. Ideally, we should drop to a block boundary,
 // but resync will be the mux's problem.
 void Server::skip_lost_data(Client *client)
 // See if there's some data we've lost. Ideally, we should drop to a block boundary,
 // but resync will be the mux's problem.
 void Server::skip_lost_data(Client *client)
@@ -811,7 +1001,7 @@ void Server::process_queued_data()
                MutexLock lock(&queued_clients_mutex);
 
                for (size_t i = 0; i < queued_add_clients.size(); ++i) {
                MutexLock lock(&queued_clients_mutex);
 
                for (size_t i = 0; i < queued_add_clients.size(); ++i) {
-                       add_client(queued_add_clients[i]);
+                       add_client(queued_add_clients[i].first, queued_add_clients[i].second);
                }
                queued_add_clients.clear();
        }
                }
                queued_add_clients.clear();
        }
index b05f661aa6641d5aed95953b98b1d103fee8702f..cb726c6fb818b7f73ce39ec09b2803215e635df6 100644 (file)
--- a/server.h
+++ b/server.h
 #include <string>
 #include <vector>
 
 #include <string>
 #include <vector>
 
+#include "tlse.h"
+
 #include "client.h"
 #include "stream.h"
 #include "thread.h"
 
 #include "client.h"
 #include "stream.h"
 #include "thread.h"
 
+class Acceptor;
 class ClientProto;
 struct Stream;
 
 class ClientProto;
 struct Stream;
 
@@ -47,7 +50,7 @@ public:
        // These will be deferred until the next time an iteration in do_work() happens,
        // and the order between them are undefined.
        // XXX: header should ideally be ordered with respect to data.
        // These will be deferred until the next time an iteration in do_work() happens,
        // and the order between them are undefined.
        // XXX: header should ideally be ordered with respect to data.
-       void add_client_deferred(int sock);
+       void add_client_deferred(int sock, Acceptor *acceptor);
        void add_data_deferred(int stream_index, const char *data, size_t bytes, uint16_t metacube_flags);
 
        // These should not be called while running, since that would violate
        void add_data_deferred(int stream_index, const char *data, size_t bytes, uint16_t metacube_flags);
 
        // These should not be called while running, since that would violate
@@ -63,6 +66,7 @@ public:
        void set_encoding(int stream_index, Stream::Encoding encoding);
        void set_src_encoding(int stream_index, Stream::Encoding encoding);
        void add_gen204(const std::string &url, const std::string &allow_origin);
        void set_encoding(int stream_index, Stream::Encoding encoding);
        void set_src_encoding(int stream_index, Stream::Encoding encoding);
        void add_gen204(const std::string &url, const std::string &allow_origin);
+       void create_tls_context_for_acceptor(const Acceptor *acceptor);
 
 private:
        // Mutex protecting queued_add_clients.
 
 private:
        // Mutex protecting queued_add_clients.
@@ -80,7 +84,7 @@ private:
        //    can be taken a lot of the time.
        //      
        // Protected by <queued_clients_mutex>.
        //    can be taken a lot of the time.
        //      
        // Protected by <queued_clients_mutex>.
-       std::vector<int> queued_add_clients;
+       std::vector<std::pair<int, Acceptor *> > queued_add_clients;
 
        // All variables below this line are protected by the mutex.
        mutable pthread_mutex_t mutex;
 
        // All variables below this line are protected by the mutex.
        mutable pthread_mutex_t mutex;
@@ -114,6 +118,9 @@ private:
        int epoll_fd;
        epoll_event events[EPOLL_MAX_EVENTS];
 
        int epoll_fd;
        epoll_event events[EPOLL_MAX_EVENTS];
 
+       // For each TLS-enabled acceptor, our private server context for its key pair.
+       std::map<const Acceptor *, TLSContext *> tls_server_contexts;
+
        // The actual worker thread.
        virtual void do_work();
 
        // The actual worker thread.
        virtual void do_work();
 
@@ -132,6 +139,22 @@ private:
        // but it's cheaper than taking it in and out all the time.
        void process_client(Client *client);
 
        // but it's cheaper than taking it in and out all the time.
        void process_client(Client *client);
 
+       // If the TLS library wants to write anything to this client,
+       // output it. Returns true if the processing should go to sleep
+       // (an error, or lack of outgoing buffer space).
+       bool send_pending_tls_data(Client *client);
+
+       // Reads regular data fro ma socket. Returns -1 if the processing
+       // should go to sleep (an error, or no data available yet), otherwise
+       // the number of bytes read.
+       int read_nontls_data(Client *client, char *buf, size_t max_size);
+
+       // Reads (decrypted) data from a TLS socket. Returns -1 if the processing
+       // should go to sleep (an error, or no data available yet), otherwise
+       // the number of bytes read. The buffer will be used as scratch space
+       // for TLS data, so it can be overwritten by more bytes than what is returned.
+       int read_tls_data(Client *client, char *buf, size_t max_size);
+
        // Close a given client socket, and clean up after it.
        void close_client(Client *client);
 
        // Close a given client socket, and clean up after it.
        void close_client(Client *client);
 
@@ -152,7 +175,7 @@ private:
        void process_queued_data();
        void skip_lost_data(Client *client);
 
        void process_queued_data();
        void skip_lost_data(Client *client);
 
-       void add_client(int sock);
+       void add_client(int sock, Acceptor *acceptor);
 };
 
 #endif  // !defined(_SERVER_H)
 };
 
 #endif  // !defined(_SERVER_H)
index 3e79b45ba41d065aa19021efe549eb1b65c08be6..ce1bcef1caf299b82d3e9237b30fda2eead88633 100644 (file)
@@ -57,9 +57,9 @@ CubemapStateProto ServerPool::serialize()
        return state;
 }
 
        return state;
 }
 
-void ServerPool::add_client(int sock)
+void ServerPool::add_client(int sock, Acceptor *acceptor)
 {
 {
-       servers[clients_added++ % num_servers].add_client_deferred(sock);
+       servers[clients_added++ % num_servers].add_client_deferred(sock, acceptor);
 }
 
 void ServerPool::add_client_from_serialized(const ClientProto &client)
 }
 
 void ServerPool::add_client_from_serialized(const ClientProto &client)
@@ -170,6 +170,13 @@ void ServerPool::add_gen204(const std::string &url, const std::string &allow_ori
        }
 }
 
        }
 }
 
+void ServerPool::create_tls_context_for_acceptor(const Acceptor *acceptor)
+{
+       for (int i = 0; i < num_servers; ++i) {
+               servers[i].create_tls_context_for_acceptor(acceptor);
+       }
+}
+
 void ServerPool::run()
 {
        for (int i = 0; i < num_servers; ++i) {
 void ServerPool::run()
 {
        for (int i = 0; i < num_servers; ++i) {
index c72623da13664fca6d54809f42bfb0393ac22835..d257a86c48f7dc1186c12f3e285cce3371f5af28 100644 (file)
@@ -10,6 +10,7 @@
 #include "stream.h"
 #include "udpstream.h"
 
 #include "stream.h"
 #include "udpstream.h"
 
+class Acceptor;
 class Server;
 class UDPStream;
 struct ClientStats;
 class Server;
 class UDPStream;
 struct ClientStats;
@@ -25,7 +26,7 @@ public:
        CubemapStateProto serialize();
 
        // Picks a server (round-robin) and allocates the given client to it.
        CubemapStateProto serialize();
 
        // Picks a server (round-robin) and allocates the given client to it.
-       void add_client(int sock);
+       void add_client(int sock, Acceptor *acceptor);
        void add_client_from_serialized(const ClientProto &client);
 
        // Adds the given stream to all the servers. Returns the stream index.
        void add_client_from_serialized(const ClientProto &client);
 
        // Adds the given stream to all the servers. Returns the stream index.
@@ -61,6 +62,10 @@ public:
        // Adds the given gen204 endpoint to all the servers.
        void add_gen204(const std::string &url, const std::string &allow_origin);
 
        // Adds the given gen204 endpoint to all the servers.
        void add_gen204(const std::string &url, const std::string &allow_origin);
 
+       // Prepares all the servers for accepting TLS connections from the given acceptor.
+       // (They need a private context, since the contexts are not definde to be thread-safe.)
+       void create_tls_context_for_acceptor(const Acceptor *acceptor);
+
        // Starts all the servers.
        void run();
 
        // Starts all the servers.
        void run();
 
index 9799c0d29e9bb4d7c65aa0b0be5e3ee16eb0deea..35d5c505c7a157c072cc3e312f2aff66da5f9206 100644 (file)
@@ -17,6 +17,9 @@ message ClientProto {
        optional int64 num_loss_events = 12;
        optional bytes referer = 15;
        optional bytes user_agent = 16;
        optional int64 num_loss_events = 12;
        optional bytes referer = 15;
        optional bytes user_agent = 16;
+       optional bytes tls_context = 17;  // If not present, then not using TLS for this client.
+       optional int64 tls_output_bytes_already_consumed = 18;
+       optional bool in_ktls_mode = 19;
 };
 
 // Corresponds to struct Stream.
 };
 
 // Corresponds to struct Stream.
@@ -56,6 +59,8 @@ message AcceptorProto {
        optional int32 server_sock = 1;
        optional int32 port = 2;
        optional string addr = 3;  // As a string. Empty is equivalent to "::".
        optional int32 server_sock = 1;
        optional int32 port = 2;
        optional string addr = 3;  // As a string. Empty is equivalent to "::".
+       optional bytes certificate_chain = 4;
+       optional bytes private_key = 5;
 };
 
 message CubemapStateProto {
 };
 
 message CubemapStateProto {
diff --git a/tlse/LICENSE b/tlse/LICENSE
new file mode 100644 (file)
index 0000000..abd686b
--- /dev/null
@@ -0,0 +1,23 @@
+Copyright (c) 2016, Eduard Suica
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tlse/README b/tlse/README
new file mode 100644 (file)
index 0000000..3fa5ca5
--- /dev/null
@@ -0,0 +1,8 @@
+This is a copy of the core files of TLSe, checked out from
+
+  https://github.com/eduardsui/tlse
+
+It is patched to add and include ktls.h, since glibc does not include
+kTLS definitions yet, and then irrelevant files removed. It is embedded
+(as opposed to a regular link) since TLSe does not provide a static or
+shared library.
diff --git a/tlse/ktls.h b/tlse/ktls.h
new file mode 100644 (file)
index 0000000..bbcc4f3
--- /dev/null
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _UAPI_LINUX_TLS_H
+#define _UAPI_LINUX_TLS_H
+
+#include <linux/types.h>
+
+/* TLS socket options */
+#define TLS_TX                 1       /* Set transmit parameters */
+
+/* Supported versions */
+#define TLS_VERSION_MINOR(ver) ((ver) & 0xFF)
+#define TLS_VERSION_MAJOR(ver) (((ver) >> 8) & 0xFF)
+
+#define TLS_VERSION_NUMBER(id) ((((id##_VERSION_MAJOR) & 0xFF) << 8) | \
+                                ((id##_VERSION_MINOR) & 0xFF))
+
+#define TLS_1_2_VERSION_MAJOR  0x3
+#define TLS_1_2_VERSION_MINOR  0x3
+#define TLS_1_2_VERSION                TLS_VERSION_NUMBER(TLS_1_2)
+
+/* Supported ciphers */
+#define TLS_CIPHER_AES_GCM_128                         51
+#define TLS_CIPHER_AES_GCM_128_IV_SIZE                 8
+#define TLS_CIPHER_AES_GCM_128_KEY_SIZE                16
+#define TLS_CIPHER_AES_GCM_128_SALT_SIZE               4
+#define TLS_CIPHER_AES_GCM_128_TAG_SIZE                16
+#define TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE            8
+
+#define TLS_SET_RECORD_TYPE    1
+
+struct tls_crypto_info {
+       __u16 version;
+       __u16 cipher_type;
+};
+
+struct tls12_crypto_info_aes_gcm_128 {
+       struct tls_crypto_info info;
+       unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE];
+       unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE];
+       unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE];
+       unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE];
+};
+
+#define SOL_TLS                282
+#define TCP_ULP        31
+
+#endif /* _UAPI_LINUX_TLS_H */
diff --git a/tlse/tlse.c b/tlse/tlse.c
new file mode 100644 (file)
index 0000000..dac0263
--- /dev/null
@@ -0,0 +1,8885 @@
+/********************************************************************************\r
+ Copyright (c) 2016-2018, Eduard Suica\r
+ All rights reserved.\r
\r
+ Redistribution and use in source and binary forms, with or without modification,\r
+ are permitted provided that the following conditions are met:\r
\r
+ 1. Redistributions of source code must retain the above copyright notice, this\r
+ list of conditions and the following disclaimer.\r
\r
+ 2. Redistributions in binary form must reproduce the above copyright notice, this\r
+ list of conditions and the following disclaimer in the documentation and/or other\r
+ materials provided with the distribution.\r
\r
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ POSSIBILITY OF SUCH DAMAGE.\r
+ ********************************************************************************/\r
+#ifndef TLSE_C\r
+#define TLSE_C\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdint.h>\r
+#include <time.h>\r
+#ifdef _WIN32\r
+#include <windows.h>\r
+#include <wincrypt.h>\r
+#define strcasecmp stricmp\r
+#else\r
+// hton* and ntoh* functions\r
+#include <arpa/inet.h>\r
+#include <unistd.h>\r
+#endif\r
+\r
+#ifdef TLS_AMALGAMATION\r
+#include "libtomcrypt.c"\r
+#else\r
+#include <tomcrypt.h>\r
+#endif\r
+\r
+#if (CRYPT <= 0x0117)\r
+    #define LTC_PKCS_1_EMSA LTC_LTC_PKCS_1_EMSA\r
+    #define LTC_PKCS_1_V1_5 LTC_LTC_PKCS_1_V1_5\r
+#endif\r
+\r
+#ifdef WITH_KTLS\r
+    #include <sys/types.h>\r
+    #include <sys/socket.h>\r
+    #include <netinet/tcp.h>\r
+    #include "ktls.h"\r
+#endif\r
+// using ChaCha20 implementation by D. J. Bernstein\r
+\r
+#include "tlse.h"\r
+\r
+#ifndef TLS_FORWARD_SECRECY\r
+#undef TLS_ECDSA_SUPPORTED\r
+#endif\r
+\r
+#ifndef TLS_ECDSA_SUPPORTED\r
+// disable client ECDSA if not supported\r
+#undef TLS_CLIENT_ECDSA\r
+#endif\r
+\r
+#define TLS_DH_DEFAULT_P            "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597"\r
+#define TLS_DH_DEFAULT_G            "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659"\r
+#define __TLS_DHE_KEY_SIZE          2048\r
+\r
+// you should never use weak DH groups (1024 bits)\r
+// but if you have old devices (like grandstream ip phones)\r
+// that can't handle 2048bit DHE, uncomment next lines\r
+// and define TLS_WEAK_DH_LEGACY_DEVICES\r
+// #ifdef TLS_WEAK_DH_LEGACY_DEVICES\r
+//     #define TLS_DH_DEFAULT_P            "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"\r
+//     #define TLS_DH_DEFAULT_G            "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"\r
+//     #define __TLS_DHE_KEY_SIZE          1024\r
+// #endif\r
+\r
+#ifndef TLS_MALLOC\r
+    #define TLS_MALLOC(size)        malloc(size)\r
+#endif\r
+#ifndef TLS_REALLOC\r
+    #define TLS_REALLOC(ptr, size)  realloc(ptr, size)\r
+#endif\r
+#ifndef TLS_FREE\r
+    #define TLS_FREE(ptr)           if (ptr) free(ptr)\r
+#endif\r
+\r
+#ifdef DEBUG\r
+#define DEBUG_PRINT(...)            fprintf(stderr, __VA_ARGS__)\r
+#define DEBUG_DUMP_HEX(buf, len)    {int i; for (i = 0; i < len; i++) { DEBUG_PRINT("%02X ", (unsigned int)(buf)[i]); } }\r
+#define DEBUG_INDEX(fields)         print_index(fields)\r
+#define DEBUG_DUMP(buf, length)     fwrite(buf, 1, length, stderr);\r
+#define DEBUG_DUMP_HEX_LABEL(title, buf, len)    {fprintf(stderr, "%s (%i): ", title, (int)len); DEBUG_DUMP_HEX(buf, len); fprintf(stderr, "\n");}\r
+#else\r
+#define DEBUG_PRINT(...)            { }\r
+#define DEBUG_DUMP_HEX(buf, len)    { }\r
+#define DEBUG_INDEX(fields)         { }\r
+#define DEBUG_DUMP(buf, length)     { }\r
+#define DEBUG_DUMP_HEX_LABEL(title, buf, len) { }\r
+#endif\r
+\r
+#ifndef htonll\r
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))\r
+#endif\r
+\r
+#ifndef ntohll\r
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))\r
+#endif\r
+\r
+#define TLS_CHANGE_CIPHER       0x14\r
+#define TLS_ALERT               0x15\r
+#define TLS_HANDSHAKE           0x16\r
+#define TLS_APPLICATION_DATA    0x17\r
+\r
+#define TLS_SERIALIZED_OBJECT   0xFE\r
+\r
+#define __TLS_CLIENT_HELLO_MINSIZE  41\r
+#define __TLS_CLIENT_RANDOM_SIZE    32\r
+#define __TLS_SERVER_RANDOM_SIZE    32\r
+#define __TLS_MAX_SESSION_ID        32\r
+#define __TLS_SHA256_MAC_SIZE       32\r
+#define __TLS_SHA1_MAC_SIZE         20\r
+#define __TLS_SHA384_MAC_SIZE       48\r
+#define __TLS_MAX_MAC_SIZE          __TLS_SHA384_MAC_SIZE\r
+#define __TLS_MAX_KEY_EXPANSION_SIZE 192 // 160\r
+// 512bits (sha256) = 64 bytes\r
+#define __TLS_MAX_HASH_LEN          64\r
+#define __TLS_AES_IV_LENGTH         16\r
+#define __TLS_AES_BLOCK_SIZE        16\r
+#define __TLS_AES_GCM_IV_LENGTH     4\r
+#define __TLS_GCM_TAG_LEN           16\r
+#define __TLS_MAX_TAG_LEN           16\r
+#define __TLS_MIN_FINISHED_OPAQUE_LEN 12\r
+\r
+#define __TLS_BLOB_INCREMENT        0xFFF\r
+#define __TLS_ASN1_MAXLEVEL         0xFF\r
+\r
+#define __DTLS_COOKIE_SIZE          32\r
+\r
+#define __TLS_MAX_SHA_SIZE 48\r
+#define __TLS_V11_HASH_SIZE 36      // 16(md5) + 20(sha1)\r
+#define __TLS_MAX_HASH_SIZE __TLS_MAX_SHA_SIZE\r
+#define __TLS_MAX_RSA_KEY   2048    // 16kbits\r
+\r
+#define __TLS_MAX_TLS_APP_SIZE      0x4000\r
+// max 1 second sleep\r
+#define __TLS_MAX_ERROR_SLEEP_uS    1000000\r
+// max 5 seconds context sleep\r
+#define __TLS_MAX_ERROR_IDLE_S      5\r
+\r
+#define VERSION_SUPPORTED(version, err)  if ((version != TLS_V12) && (version != TLS_V11) && (version != TLS_V10) && (version != DTLS_V12) && (version != DTLS_V10)) { if ((version == SSL_V30) && (context->connection_status == 0)) { version = TLS_V12; } else { DEBUG_PRINT("UNSUPPORTED TLS VERSION %x\n", (int)version); return err;} }\r
+#define CHECK_SIZE(size, buf_size, err)  if (((int)size > (int)buf_size) || ((int)buf_size < 0)) return err;\r
+#define TLS_IMPORT_CHECK_SIZE(buf_pos, size, buf_size) if (((int)size > (int)buf_size - buf_pos) || ((int)buf_pos > (int)buf_size)) { DEBUG_PRINT("IMPORT ELEMENT SIZE ERROR\n"); tls_destroy_context(context); return NULL; }\r
+#define CHECK_HANDSHAKE_STATE(context, n, limit)  { if (context->hs_messages[n] >= limit) { DEBUG_PRINT("* UNEXPECTED MESSAGE (%i)\n", (int)n); payload_res = TLS_UNEXPECTED_MESSAGE; break; } context->hs_messages[n]++; }\r
+\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+#define __TLS_CHACHA20_IV_LENGTH    12\r
+\r
+// ChaCha20 implementation by D. J. Bernstein\r
+// Public domain.\r
+\r
+#define CHACHA_MINKEYLEN    16\r
+#define CHACHA_NONCELEN     8\r
+#define CHACHA_NONCELEN_96  12\r
+#define CHACHA_CTRLEN       8\r
+#define CHACHA_CTRLEN_96    4\r
+#define CHACHA_STATELEN     (CHACHA_NONCELEN+CHACHA_CTRLEN)\r
+#define CHACHA_BLOCKLEN     64\r
+\r
+#define POLY1305_MAX_AAD    32\r
+#define POLY1305_KEYLEN     32\r
+#define POLY1305_TAGLEN     16\r
+\r
+#define u_int   unsigned int\r
+#define uint8_t unsigned char\r
+#define u_char  unsigned char\r
+#ifndef NULL\r
+#define NULL (void *)0\r
+#endif\r
+\r
+#if (CRYPT >= 0x0117) && (0)\r
+    // to do: use ltc chacha/poly1305 implementation (working on big-endian machines)\r
+    #define chacha_ctx                                  chacha20poly1305_state\r
+    #define poly1305_context                            poly1305_state\r
+\r
+    #define __private_tls_poly1305_init(ctx, key, len)  poly1305_init(ctx, key, len)\r
+    #define __private_tls_poly1305_update(ctx, in, len) poly1305_process(ctx, in, len)\r
+    #define __private_tls_poly1305_finish(ctx, mac)     poly1305_done(ctx, mac, 16)\r
+#else\r
+struct chacha_ctx {\r
+    u_int input[16];\r
+    uint8_t ks[CHACHA_BLOCKLEN];\r
+    uint8_t unused;\r
+};\r
+\r
+static inline void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits);\r
+static inline void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr);\r
+static inline void chacha_ivsetup_96bitnonce(struct chacha_ctx *x, const u_char *iv, const u_char *ctr);\r
+static inline void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, u_char *c, u_int bytes);\r
+static inline int poly1305_generate_key(unsigned char *key256, unsigned char *nonce, unsigned int noncelen, unsigned char *poly_key, unsigned int counter);\r
+\r
+#define poly1305_block_size 16\r
+#define poly1305_context poly1305_state_internal_t\r
+\r
+//========== ChaCha20 from D. J. Bernstein ========= //\r
+// Source available at https://cr.yp.to/chacha.html  //\r
+\r
+typedef unsigned char u8;\r
+typedef unsigned int u32;\r
+\r
+typedef struct chacha_ctx chacha_ctx;\r
+\r
+#define U8C(v) (v##U)\r
+#define U32C(v) (v##U)\r
+\r
+#define U8V(v) ((u8)(v) & U8C(0xFF))\r
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))\r
+\r
+#define ROTL32(v, n) \\r
+  (U32V((v) << (n)) | ((v) >> (32 - (n))))\r
+\r
+#define __private_tls_U8TO32_LITTLE(p) \\r
+  (((u32)((p)[0])) | \\r
+   ((u32)((p)[1]) <<  8) | \\r
+   ((u32)((p)[2]) << 16) | \\r
+   ((u32)((p)[3]) << 24))\r
+\r
+#define __private_tls_U32TO8_LITTLE(p, v) \\r
+  do { \\r
+    (p)[0] = U8V((v)); \\r
+    (p)[1] = U8V((v) >>  8); \\r
+    (p)[2] = U8V((v) >> 16); \\r
+    (p)[3] = U8V((v) >> 24); \\r
+  } while (0)\r
+\r
+#define ROTATE(v,c) (ROTL32(v,c))\r
+#define XOR(v,w) ((v) ^ (w))\r
+#define PLUS(v,w) (U32V((v) + (w)))\r
+#define PLUSONE(v) (PLUS((v),1))\r
+\r
+#define QUARTERROUND(a,b,c,d) \\r
+  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \\r
+  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \\r
+  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \\r
+  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);\r
+\r
+static const char sigma[] = "expand 32-byte k";\r
+static const char tau[] = "expand 16-byte k";\r
+\r
+static inline void chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits) {\r
+    const char *constants;\r
+\r
+    x->input[4] = __private_tls_U8TO32_LITTLE(k + 0);\r
+    x->input[5] = __private_tls_U8TO32_LITTLE(k + 4);\r
+    x->input[6] = __private_tls_U8TO32_LITTLE(k + 8);\r
+    x->input[7] = __private_tls_U8TO32_LITTLE(k + 12);\r
+    if (kbits == 256) { /* recommended */\r
+        k += 16;\r
+        constants = sigma;\r
+    } else { /* kbits == 128 */\r
+        constants = tau;\r
+    }\r
+    x->input[8] = __private_tls_U8TO32_LITTLE(k + 0);\r
+    x->input[9] = __private_tls_U8TO32_LITTLE(k + 4);\r
+    x->input[10] = __private_tls_U8TO32_LITTLE(k + 8);\r
+    x->input[11] = __private_tls_U8TO32_LITTLE(k + 12);\r
+    x->input[0] = __private_tls_U8TO32_LITTLE(constants + 0);\r
+    x->input[1] = __private_tls_U8TO32_LITTLE(constants + 4);\r
+    x->input[2] = __private_tls_U8TO32_LITTLE(constants + 8);\r
+    x->input[3] = __private_tls_U8TO32_LITTLE(constants + 12);\r
+}\r
+\r
+static inline void chacha_key(chacha_ctx *x, u8 *k) {\r
+    __private_tls_U32TO8_LITTLE(k, x->input[4]);\r
+    __private_tls_U32TO8_LITTLE(k + 4, x->input[5]);\r
+    __private_tls_U32TO8_LITTLE(k + 8, x->input[6]);\r
+    __private_tls_U32TO8_LITTLE(k + 12, x->input[7]);\r
+\r
+    __private_tls_U32TO8_LITTLE(k + 16, x->input[8]);\r
+    __private_tls_U32TO8_LITTLE(k + 20, x->input[9]);\r
+    __private_tls_U32TO8_LITTLE(k + 24, x->input[10]);\r
+    __private_tls_U32TO8_LITTLE(k + 28, x->input[11]);\r
+}\r
+\r
+static inline void chacha_nonce(chacha_ctx *x, u8 *nonce) {\r
+    __private_tls_U32TO8_LITTLE(nonce + 0, x->input[13]);\r
+    __private_tls_U32TO8_LITTLE(nonce + 4, x->input[14]);\r
+    __private_tls_U32TO8_LITTLE(nonce + 8, x->input[15]);\r
+}\r
+\r
+static inline void chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) {\r
+    x->input[12] = counter == NULL ? 0 : __private_tls_U8TO32_LITTLE(counter + 0);\r
+    x->input[13] = counter == NULL ? 0 : __private_tls_U8TO32_LITTLE(counter + 4);\r
+    if (iv) {\r
+        x->input[14] = __private_tls_U8TO32_LITTLE(iv + 0);\r
+        x->input[15] = __private_tls_U8TO32_LITTLE(iv + 4);\r
+    }\r
+}\r
+\r
+static inline void chacha_ivsetup_96bitnonce(chacha_ctx *x, const u8 *iv, const u8 *counter) {\r
+    x->input[12] = counter == NULL ? 0 : __private_tls_U8TO32_LITTLE(counter + 0);\r
+    if (iv) {\r
+        x->input[13] = __private_tls_U8TO32_LITTLE(iv + 0);\r
+        x->input[14] = __private_tls_U8TO32_LITTLE(iv + 4);\r
+        x->input[15] = __private_tls_U8TO32_LITTLE(iv + 8);\r
+    }\r
+}\r
+\r
+static inline void chacha_ivupdate(chacha_ctx *x, const u8 *iv, const u8 *aad, const u8 *counter) {\r
+    x->input[12] = counter == NULL ? 0 : __private_tls_U8TO32_LITTLE(counter + 0);\r
+    x->input[13] = __private_tls_U8TO32_LITTLE(iv + 0);\r
+    x->input[14] = __private_tls_U8TO32_LITTLE(iv + 4) ^ __private_tls_U8TO32_LITTLE(aad);\r
+    x->input[15] = __private_tls_U8TO32_LITTLE(iv + 8) ^ __private_tls_U8TO32_LITTLE(aad + 4);\r
+}\r
+\r
+static inline void chacha_encrypt_bytes(chacha_ctx *x, const u8 *m, u8 *c, u32 bytes) {\r
+    u32 x0, x1, x2, x3, x4, x5, x6, x7;\r
+    u32 x8, x9, x10, x11, x12, x13, x14, x15;\r
+    u32 j0, j1, j2, j3, j4, j5, j6, j7;\r
+    u32 j8, j9, j10, j11, j12, j13, j14, j15;\r
+    u8 *ctarget = NULL;\r
+    u8 tmp[64];\r
+    u_int i;\r
+\r
+    if (!bytes)\r
+        return;\r
+\r
+    j0 = x->input[0];\r
+    j1 = x->input[1];\r
+    j2 = x->input[2];\r
+    j3 = x->input[3];\r
+    j4 = x->input[4];\r
+    j5 = x->input[5];\r
+    j6 = x->input[6];\r
+    j7 = x->input[7];\r
+    j8 = x->input[8];\r
+    j9 = x->input[9];\r
+    j10 = x->input[10];\r
+    j11 = x->input[11];\r
+    j12 = x->input[12];\r
+    j13 = x->input[13];\r
+    j14 = x->input[14];\r
+    j15 = x->input[15];\r
+\r
+    for (;;) {\r
+        if (bytes < 64) {\r
+            for (i = 0; i < bytes; ++i)\r
+                tmp[i] = m[i];\r
+            m = tmp;\r
+            ctarget = c;\r
+            c = tmp;\r
+        }\r
+        x0 = j0;\r
+        x1 = j1;\r
+        x2 = j2;\r
+        x3 = j3;\r
+        x4 = j4;\r
+        x5 = j5;\r
+        x6 = j6;\r
+        x7 = j7;\r
+        x8 = j8;\r
+        x9 = j9;\r
+        x10 = j10;\r
+        x11 = j11;\r
+        x12 = j12;\r
+        x13 = j13;\r
+        x14 = j14;\r
+        x15 = j15;\r
+        for (i = 20; i > 0; i -= 2) {\r
+            QUARTERROUND(x0, x4, x8, x12)\r
+            QUARTERROUND(x1, x5, x9, x13)\r
+            QUARTERROUND(x2, x6, x10, x14)\r
+            QUARTERROUND(x3, x7, x11, x15)\r
+            QUARTERROUND(x0, x5, x10, x15)\r
+            QUARTERROUND(x1, x6, x11, x12)\r
+            QUARTERROUND(x2, x7, x8, x13)\r
+            QUARTERROUND(x3, x4, x9, x14)\r
+        }\r
+        x0 = PLUS(x0, j0);\r
+        x1 = PLUS(x1, j1);\r
+        x2 = PLUS(x2, j2);\r
+        x3 = PLUS(x3, j3);\r
+        x4 = PLUS(x4, j4);\r
+        x5 = PLUS(x5, j5);\r
+        x6 = PLUS(x6, j6);\r
+        x7 = PLUS(x7, j7);\r
+        x8 = PLUS(x8, j8);\r
+        x9 = PLUS(x9, j9);\r
+        x10 = PLUS(x10, j10);\r
+        x11 = PLUS(x11, j11);\r
+        x12 = PLUS(x12, j12);\r
+        x13 = PLUS(x13, j13);\r
+        x14 = PLUS(x14, j14);\r
+        x15 = PLUS(x15, j15);\r
+\r
+        if (bytes < 64) {\r
+            __private_tls_U32TO8_LITTLE(x->ks + 0, x0);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 4, x1);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 8, x2);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 12, x3);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 16, x4);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 20, x5);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 24, x6);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 28, x7);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 32, x8);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 36, x9);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 40, x10);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 44, x11);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 48, x12);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 52, x13);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 56, x14);\r
+            __private_tls_U32TO8_LITTLE(x->ks + 60, x15);\r
+        }\r
+\r
+        x0 = XOR(x0, __private_tls_U8TO32_LITTLE(m + 0));\r
+        x1 = XOR(x1, __private_tls_U8TO32_LITTLE(m + 4));\r
+        x2 = XOR(x2, __private_tls_U8TO32_LITTLE(m + 8));\r
+        x3 = XOR(x3, __private_tls_U8TO32_LITTLE(m + 12));\r
+        x4 = XOR(x4, __private_tls_U8TO32_LITTLE(m + 16));\r
+        x5 = XOR(x5, __private_tls_U8TO32_LITTLE(m + 20));\r
+        x6 = XOR(x6, __private_tls_U8TO32_LITTLE(m + 24));\r
+        x7 = XOR(x7, __private_tls_U8TO32_LITTLE(m + 28));\r
+        x8 = XOR(x8, __private_tls_U8TO32_LITTLE(m + 32));\r
+        x9 = XOR(x9, __private_tls_U8TO32_LITTLE(m + 36));\r
+        x10 = XOR(x10, __private_tls_U8TO32_LITTLE(m + 40));\r
+        x11 = XOR(x11, __private_tls_U8TO32_LITTLE(m + 44));\r
+        x12 = XOR(x12, __private_tls_U8TO32_LITTLE(m + 48));\r
+        x13 = XOR(x13, __private_tls_U8TO32_LITTLE(m + 52));\r
+        x14 = XOR(x14, __private_tls_U8TO32_LITTLE(m + 56));\r
+        x15 = XOR(x15, __private_tls_U8TO32_LITTLE(m + 60));\r
+\r
+        j12 = PLUSONE(j12);\r
+        if (!j12) {\r
+            j13 = PLUSONE(j13);\r
+            /*\r
+             * Stopping at 2^70 bytes per nonce is the user's\r
+             * responsibility.\r
+             */\r
+        }\r
+\r
+        __private_tls_U32TO8_LITTLE(c + 0, x0);\r
+        __private_tls_U32TO8_LITTLE(c + 4, x1);\r
+        __private_tls_U32TO8_LITTLE(c + 8, x2);\r
+        __private_tls_U32TO8_LITTLE(c + 12, x3);\r
+        __private_tls_U32TO8_LITTLE(c + 16, x4);\r
+        __private_tls_U32TO8_LITTLE(c + 20, x5);\r
+        __private_tls_U32TO8_LITTLE(c + 24, x6);\r
+        __private_tls_U32TO8_LITTLE(c + 28, x7);\r
+        __private_tls_U32TO8_LITTLE(c + 32, x8);\r
+        __private_tls_U32TO8_LITTLE(c + 36, x9);\r
+        __private_tls_U32TO8_LITTLE(c + 40, x10);\r
+        __private_tls_U32TO8_LITTLE(c + 44, x11);\r
+        __private_tls_U32TO8_LITTLE(c + 48, x12);\r
+        __private_tls_U32TO8_LITTLE(c + 52, x13);\r
+        __private_tls_U32TO8_LITTLE(c + 56, x14);\r
+        __private_tls_U32TO8_LITTLE(c + 60, x15);\r
+\r
+        if (bytes <= 64) {\r
+            if (bytes < 64) {\r
+                for (i = 0; i < bytes; ++i)\r
+                    ctarget[i] = c[i];\r
+            }\r
+            x->input[12] = j12;\r
+            x->input[13] = j13;\r
+            x->unused = 64 - bytes;\r
+            return;\r
+        }\r
+        bytes -= 64;\r
+        c += 64;\r
+        m += 64;\r
+    }\r
+}\r
+\r
+static inline void chacha20_block(chacha_ctx *x, unsigned char *c, int len) {\r
+    u_int i;\r
+\r
+    unsigned int state[16];\r
+    for (i = 0; i < 16; i++)\r
+        state[i] = x->input[i];\r
+    for (i = 20; i > 0; i -= 2) {\r
+        QUARTERROUND(state[0], state[4], state[8], state[12])\r
+        QUARTERROUND(state[1], state[5], state[9], state[13])\r
+        QUARTERROUND(state[2], state[6], state[10], state[14])\r
+        QUARTERROUND(state[3], state[7], state[11], state[15])\r
+        QUARTERROUND(state[0], state[5], state[10], state[15])\r
+        QUARTERROUND(state[1], state[6], state[11], state[12])\r
+        QUARTERROUND(state[2], state[7], state[8], state[13])\r
+        QUARTERROUND(state[3], state[4], state[9], state[14])\r
+    }\r
+\r
+    for (i = 0; i < 16; i++)\r
+        x->input[i] = PLUS(x->input[i], state[i]);\r
+\r
+    for (i = 0; i < len; i += 4) {\r
+        __private_tls_U32TO8_LITTLE(c + i, x->input[i/4]);\r
+    }\r
+}\r
+\r
+static inline int poly1305_generate_key(unsigned char *key256, unsigned char *nonce, unsigned int noncelen, unsigned char *poly_key, unsigned int counter) {\r
+    struct chacha_ctx ctx;\r
+    uint64_t ctr;\r
+    memset(&ctx, 0, sizeof(ctx));\r
+    chacha_keysetup(&ctx, key256, 256);\r
+    switch (noncelen) {\r
+        case 8:\r
+            ctr = counter;\r
+            chacha_ivsetup(&ctx, nonce, (unsigned char *)&ctr);\r
+            break;\r
+        case 12:\r
+            chacha_ivsetup_96bitnonce(&ctx, nonce, (unsigned char *)&counter);\r
+            break;\r
+        default:\r
+            return -1;\r
+    }\r
+    chacha20_block(&ctx, poly_key, POLY1305_KEYLEN);\r
+    return 0;\r
+}\r
+\r
+/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */\r
+typedef struct poly1305_state_internal_t {\r
+    unsigned long r[5];\r
+    unsigned long h[5];\r
+    unsigned long pad[4];\r
+    size_t leftover;\r
+    unsigned char buffer[poly1305_block_size];\r
+    unsigned char final;\r
+} poly1305_state_internal_t;\r
+\r
+/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */\r
+static unsigned long __private_tls_U8TO32(const unsigned char *p) {\r
+    return\r
+        (((unsigned long)(p[0] & 0xff)      ) |\r
+         ((unsigned long)(p[1] & 0xff) <<  8) |\r
+         ((unsigned long)(p[2] & 0xff) << 16) |\r
+         ((unsigned long)(p[3] & 0xff) << 24));\r
+}\r
+\r
+/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */\r
+static void __private_tls_U32TO8(unsigned char *p, unsigned long v) {\r
+    p[0] = (v      ) & 0xff;\r
+    p[1] = (v >>  8) & 0xff;\r
+    p[2] = (v >> 16) & 0xff;\r
+    p[3] = (v >> 24) & 0xff;\r
+}\r
+\r
+void __private_tls_poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {\r
+    poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;\r
+\r
+    /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */\r
+    st->r[0] = (__private_tls_U8TO32(&key[ 0])     ) & 0x3ffffff;\r
+    st->r[1] = (__private_tls_U8TO32(&key[ 3]) >> 2) & 0x3ffff03;\r
+    st->r[2] = (__private_tls_U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff;\r
+    st->r[3] = (__private_tls_U8TO32(&key[ 9]) >> 6) & 0x3f03fff;\r
+    st->r[4] = (__private_tls_U8TO32(&key[12]) >> 8) & 0x00fffff;\r
+\r
+    /* h = 0 */\r
+    st->h[0] = 0;\r
+    st->h[1] = 0;\r
+    st->h[2] = 0;\r
+    st->h[3] = 0;\r
+    st->h[4] = 0;\r
+\r
+    /* save pad for later */\r
+    st->pad[0] = __private_tls_U8TO32(&key[16]);\r
+    st->pad[1] = __private_tls_U8TO32(&key[20]);\r
+    st->pad[2] = __private_tls_U8TO32(&key[24]);\r
+    st->pad[3] = __private_tls_U8TO32(&key[28]);\r
+\r
+    st->leftover = 0;\r
+    st->final = 0;\r
+}\r
+\r
+static void __private_tls_poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {\r
+    const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */\r
+    unsigned long r0,r1,r2,r3,r4;\r
+    unsigned long s1,s2,s3,s4;\r
+    unsigned long h0,h1,h2,h3,h4;\r
+    unsigned long long d0,d1,d2,d3,d4;\r
+    unsigned long c;\r
+\r
+    r0 = st->r[0];\r
+    r1 = st->r[1];\r
+    r2 = st->r[2];\r
+    r3 = st->r[3];\r
+    r4 = st->r[4];\r
+\r
+    s1 = r1 * 5;\r
+    s2 = r2 * 5;\r
+    s3 = r3 * 5;\r
+    s4 = r4 * 5;\r
+\r
+    h0 = st->h[0];\r
+    h1 = st->h[1];\r
+    h2 = st->h[2];\r
+    h3 = st->h[3];\r
+    h4 = st->h[4];\r
+\r
+    while (bytes >= poly1305_block_size) {\r
+        /* h += m[i] */\r
+        h0 += (__private_tls_U8TO32(m+ 0)     ) & 0x3ffffff;\r
+        h1 += (__private_tls_U8TO32(m+ 3) >> 2) & 0x3ffffff;\r
+        h2 += (__private_tls_U8TO32(m+ 6) >> 4) & 0x3ffffff;\r
+        h3 += (__private_tls_U8TO32(m+ 9) >> 6) & 0x3ffffff;\r
+        h4 += (__private_tls_U8TO32(m+12) >> 8) | hibit;\r
+\r
+        /* h *= r */\r
+        d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);\r
+        d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);\r
+        d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);\r
+        d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);\r
+        d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);\r
+\r
+        /* (partial) h %= p */\r
+                      c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff;\r
+        d1 += c;      c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff;\r
+        d2 += c;      c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff;\r
+        d3 += c;      c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff;\r
+        d4 += c;      c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff;\r
+        h0 += c * 5;  c =                (h0 >> 26); h0 =                h0 & 0x3ffffff;\r
+        h1 += c;\r
+\r
+        m += poly1305_block_size;\r
+        bytes -= poly1305_block_size;\r
+    }\r
+\r
+    st->h[0] = h0;\r
+    st->h[1] = h1;\r
+    st->h[2] = h2;\r
+    st->h[3] = h3;\r
+    st->h[4] = h4;\r
+}\r
+\r
+void __private_tls_poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {\r
+    poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;\r
+    unsigned long h0,h1,h2,h3,h4,c;\r
+    unsigned long g0,g1,g2,g3,g4;\r
+    unsigned long long f;\r
+    unsigned long mask;\r
+\r
+    /* process the remaining block */\r
+    if (st->leftover) {\r
+        size_t i = st->leftover;\r
+        st->buffer[i++] = 1;\r
+        for (; i < poly1305_block_size; i++)\r
+            st->buffer[i] = 0;\r
+        st->final = 1;\r
+        __private_tls_poly1305_blocks(st, st->buffer, poly1305_block_size);\r
+    }\r
+\r
+    /* fully carry h */\r
+    h0 = st->h[0];\r
+    h1 = st->h[1];\r
+    h2 = st->h[2];\r
+    h3 = st->h[3];\r
+    h4 = st->h[4];\r
+\r
+                 c = h1 >> 26; h1 = h1 & 0x3ffffff;\r
+    h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;\r
+    h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;\r
+    h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;\r
+    h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;\r
+    h1 +=     c;\r
+\r
+    /* compute h + -p */\r
+    g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;\r
+    g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;\r
+    g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;\r
+    g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;\r
+    g4 = h4 + c - (1UL << 26);\r
+\r
+    /* select h if h < p, or h + -p if h >= p */\r
+    mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;\r
+    g0 &= mask;\r
+    g1 &= mask;\r
+    g2 &= mask;\r
+    g3 &= mask;\r
+    g4 &= mask;\r
+    mask = ~mask;\r
+    h0 = (h0 & mask) | g0;\r
+    h1 = (h1 & mask) | g1;\r
+    h2 = (h2 & mask) | g2;\r
+    h3 = (h3 & mask) | g3;\r
+    h4 = (h4 & mask) | g4;\r
+\r
+    /* h = h % (2^128) */\r
+    h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;\r
+    h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;\r
+    h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;\r
+    h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;\r
+\r
+    /* mac = (h + pad) % (2^128) */\r
+    f = (unsigned long long)h0 + st->pad[0]            ; h0 = (unsigned long)f;\r
+    f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f;\r
+    f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f;\r
+    f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f;\r
+\r
+    __private_tls_U32TO8(mac +  0, h0);\r
+    __private_tls_U32TO8(mac +  4, h1);\r
+    __private_tls_U32TO8(mac +  8, h2);\r
+    __private_tls_U32TO8(mac + 12, h3);\r
+\r
+    /* zero out the state */\r
+    st->h[0] = 0;\r
+    st->h[1] = 0;\r
+    st->h[2] = 0;\r
+    st->h[3] = 0;\r
+    st->h[4] = 0;\r
+    st->r[0] = 0;\r
+    st->r[1] = 0;\r
+    st->r[2] = 0;\r
+    st->r[3] = 0;\r
+    st->r[4] = 0;\r
+    st->pad[0] = 0;\r
+    st->pad[1] = 0;\r
+    st->pad[2] = 0;\r
+    st->pad[3] = 0;\r
+}\r
+\r
+void __private_tls_poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {\r
+    poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;\r
+    size_t i;\r
+    /* handle leftover */\r
+    if (st->leftover) {\r
+        size_t want = (poly1305_block_size - st->leftover);\r
+        if (want > bytes)\r
+            want = bytes;\r
+        for (i = 0; i < want; i++)\r
+            st->buffer[st->leftover + i] = m[i];\r
+        bytes -= want;\r
+        m += want;\r
+        st->leftover += want;\r
+        if (st->leftover < poly1305_block_size)\r
+            return;\r
+        __private_tls_poly1305_blocks(st, st->buffer, poly1305_block_size);\r
+        st->leftover = 0;\r
+    }\r
+\r
+    /* process full blocks */\r
+    if (bytes >= poly1305_block_size) {\r
+        size_t want = (bytes & ~(poly1305_block_size - 1));\r
+        __private_tls_poly1305_blocks(st, m, want);\r
+        m += want;\r
+        bytes -= want;\r
+    }\r
+\r
+    /* store leftover */\r
+    if (bytes) {\r
+        for (i = 0; i < bytes; i++)\r
+            st->buffer[st->leftover + i] = m[i];\r
+        st->leftover += bytes;\r
+    }\r
+}\r
+\r
+int poly1305_verify(const unsigned char mac1[16], const unsigned char mac2[16]) {\r
+    size_t i;\r
+    unsigned int dif = 0;\r
+    for (i = 0; i < 16; i++)\r
+        dif |= (mac1[i] ^ mac2[i]);\r
+    dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1);\r
+    return (dif & 1);\r
+}\r
+\r
+void chacha20_poly1305_key(struct chacha_ctx *ctx, unsigned char *poly1305_key) {\r
+    unsigned char key[32];\r
+    unsigned char nonce[12];\r
+    chacha_key(ctx, key);\r
+    chacha_nonce(ctx, nonce);\r
+    poly1305_generate_key(key, nonce, sizeof(nonce), poly1305_key, 0);\r
+}\r
+\r
+int chacha20_poly1305_aead(struct chacha_ctx *ctx,  unsigned char *pt, unsigned int len, unsigned char *aad, unsigned int aad_len, unsigned char *poly_key, unsigned char *out) {\r
+    static unsigned char zeropad[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\r
+    if (aad_len > POLY1305_MAX_AAD)\r
+        return -1;\r
+\r
+    unsigned int counter = 1;\r
+    chacha_ivsetup_96bitnonce(ctx, NULL, (unsigned char *)&counter);\r
+    chacha_encrypt_bytes(ctx, pt, out, len);\r
+    \r
+    poly1305_context aead_ctx;\r
+    __private_tls_poly1305_init(&aead_ctx, poly_key);\r
+    __private_tls_poly1305_update(&aead_ctx, aad, aad_len);\r
+    int rem = aad_len % 16;\r
+    if (rem)\r
+        __private_tls_poly1305_update(&aead_ctx, zeropad, 16 - rem);\r
+    __private_tls_poly1305_update(&aead_ctx, out, len);\r
+    rem = len % 16;\r
+    if (rem)\r
+        __private_tls_poly1305_update(&aead_ctx, zeropad, 16 - rem);\r
+\r
+    unsigned char trail[16];\r
+    __private_tls_U32TO8(&trail[0], aad_len);\r
+    *(int *)&trail[4] = 0;\r
+    __private_tls_U32TO8(&trail[8], len);\r
+    *(int *)&trail[12] = 0;\r
+\r
+    __private_tls_poly1305_update(&aead_ctx, trail, 16);\r
+    __private_tls_poly1305_finish(&aead_ctx, out + len);\r
+    \r
+    return len + POLY1305_TAGLEN;\r
+}\r
+#endif\r
+#endif\r
+\r
+typedef enum {\r
+    KEA_dhe_dss,\r
+    KEA_dhe_rsa,\r
+    KEA_dh_anon,\r
+    KEA_rsa,\r
+    KEA_dh_dss,\r
+    KEA_dh_rsa,\r
+    KEA_ec_diffie_hellman\r
+} KeyExchangeAlgorithm;\r
+\r
+typedef enum {\r
+    rsa_sign = 1,\r
+    dss_sign = 2,\r
+    rsa_fixed_dh = 3,\r
+    dss_fixed_dh = 4,\r
+    rsa_ephemeral_dh_RESERVED = 5,\r
+    dss_ephemeral_dh_RESERVED = 6,\r
+    fortezza_dms_RESERVED = 20,\r
+    ecdsa_sign = 64,\r
+    rsa_fixed_ecdh = 65,\r
+    ecdsa_fixed_ecdh = 66\r
+} TLSClientCertificateType;\r
+\r
+typedef enum {\r
+    none = 0,\r
+    md5 = 1,\r
+    sha1 = 2,\r
+    sha224 = 3,\r
+    sha256 = 4,\r
+    sha384 = 5,\r
+    sha512 = 6,\r
+    __md5_sha1 = 255\r
+} TLSHashAlgorithm;\r
+\r
+typedef enum {\r
+    anonymous = 0,\r
+    rsa = 1,\r
+    dsa = 2,\r
+    ecdsa = 3\r
+} TLSSignatureAlgorithm;\r
+\r
+struct __private_OID_chain {\r
+    void *top;\r
+    unsigned char *oid;\r
+};\r
+\r
+struct TLSCertificate {\r
+    unsigned short version;\r
+    unsigned int algorithm;\r
+    unsigned int key_algorithm;\r
+    unsigned int ec_algorithm;\r
+    unsigned char *exponent;\r
+    unsigned int exponent_len;\r
+    unsigned char *pk;\r
+    unsigned int pk_len;\r
+    unsigned char *priv;\r
+    unsigned int priv_len;\r
+    unsigned char *issuer_country;\r
+    unsigned char *issuer_state;\r
+    unsigned char *issuer_location;\r
+    unsigned char *issuer_entity;\r
+    unsigned char *issuer_subject;\r
+    unsigned char *not_before;\r
+    unsigned char *not_after;\r
+    unsigned char *country;\r
+    unsigned char *state;\r
+    unsigned char *location;\r
+    unsigned char *entity;\r
+    unsigned char *subject;\r
+    unsigned char **san;\r
+    unsigned short san_length;\r
+    unsigned char *ocsp;\r
+    unsigned char *serial_number;\r
+    unsigned int serial_len;\r
+    unsigned char *sign_key;\r
+    unsigned int sign_len;\r
+    unsigned char *fingerprint;\r
+    unsigned char *der_bytes;\r
+    unsigned int der_len;\r
+    unsigned char *bytes;\r
+    unsigned int len;\r
+};\r
+\r
+typedef struct {\r
+    union {\r
+        symmetric_CBC aes_local;\r
+        gcm_state aes_gcm_local;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        chacha_ctx chacha_local;\r
+#endif\r
+    } ctx_local;\r
+    union {\r
+        symmetric_CBC aes_remote;\r
+        gcm_state aes_gcm_remote;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        chacha_ctx chacha_remote;\r
+#endif\r
+    } ctx_remote;\r
+    union {\r
+        unsigned char local_mac[__TLS_MAX_MAC_SIZE];\r
+        unsigned char local_aead_iv[__TLS_AES_GCM_IV_LENGTH];\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        unsigned char local_nonce[__TLS_CHACHA20_IV_LENGTH];\r
+#endif\r
+    } ctx_local_mac;\r
+    union {\r
+        unsigned char remote_aead_iv[__TLS_AES_GCM_IV_LENGTH];\r
+        unsigned char remote_mac[__TLS_MAX_MAC_SIZE];\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        unsigned char remote_nonce[__TLS_CHACHA20_IV_LENGTH];\r
+#endif\r
+    } ctx_remote_mac;\r
+    unsigned char created;\r
+} TLSCipher;\r
+\r
+typedef struct {\r
+    hash_state hash;\r
+#ifdef TLS_LEGACY_SUPPORT\r
+    hash_state hash2;\r
+#endif\r
+    unsigned char created;\r
+} TLSHash;\r
+\r
+#ifdef TLS_FORWARD_SECRECY\r
+#define mp_init(a)                           ltc_mp.init(a)\r
+#define mp_init_multi                        ltc_init_multi\r
+#define mp_clear(a)                          ltc_mp.deinit(a)\r
+#define mp_clear_multi                       ltc_deinit_multi\r
+#define mp_count_bits(a)                     ltc_mp.count_bits(a)\r
+#define mp_read_radix(a, b, c)               ltc_mp.read_radix(a, b, c)\r
+#define mp_unsigned_bin_size(a)              ltc_mp.unsigned_size(a)\r
+#define mp_to_unsigned_bin(a, b)             ltc_mp.unsigned_write(a, b)\r
+#define mp_read_unsigned_bin(a, b, c)        ltc_mp.unsigned_read(a, b, c)\r
+#define mp_exptmod(a, b, c, d)               ltc_mp.exptmod(a, b, c, d)\r
+#define mp_add(a, b, c)                      ltc_mp.add(a, b, c)\r
+#define mp_mul(a, b, c)                      ltc_mp.mul(a, b, c)\r
+#define mp_cmp(a, b)                         ltc_mp.compare(a, b)\r
+#define mp_cmp_d(a, b)                       ltc_mp.compare_d(a, b)\r
+#define mp_sqr(a, b)                         ltc_mp.sqr(a, b)\r
+#define mp_mod(a, b, c)                      ltc_mp.mpdiv(a, b, NULL, c)\r
+#define mp_sub(a, b, c)                      ltc_mp.sub(a, b, c)\r
+#define mp_set(a, b)                         ltc_mp.set_int(a, b)\r
+\r
+typedef struct {\r
+    void *x;\r
+    void *y;\r
+    void *p;\r
+    void *g;\r
+} DHKey;\r
+\r
+struct ECCCurveParameters {\r
+    int size;\r
+    int iana;\r
+    const char *name;\r
+    const char *P;\r
+    const char *A;\r
+    const char *B;\r
+    const char *Gx;\r
+    const char *Gy;\r
+    const char *order;\r
+    ltc_ecc_set_type dp;\r
+};\r
+\r
+static struct ECCCurveParameters secp192r1 = {\r
+    24,\r
+    19,\r
+    "secp192r1",\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", // P\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", // A\r
+    "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", // B\r
+    "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", // Gx\r
+    "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", // Gy\r
+    "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"  // order (n)\r
+};\r
+\r
+\r
+static struct ECCCurveParameters secp224r1 = {\r
+    28,\r
+    21,\r
+    "secp224r1",\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", // P\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", // A\r
+    "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", // B\r
+    "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", // Gx\r
+    "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", // Gy\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters secp224k1 = {\r
+    28,\r
+    20,\r
+    "secp224k1",\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", // P\r
+    "00000000000000000000000000000000000000000000000000000000", // A\r
+    "00000000000000000000000000000000000000000000000000000005", // B\r
+    "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", // Gx\r
+    "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", // Gy\r
+    "0000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters secp256r1 = {\r
+    32,\r
+    23,\r
+    "secp256r1",\r
+    "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", // P\r
+    "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", // A\r
+    "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", // B\r
+    "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", // Gx\r
+    "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", // Gy\r
+    "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters secp256k1 = {\r
+    32,\r
+    22,\r
+    "secp256k1",\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", // P\r
+    "0000000000000000000000000000000000000000000000000000000000000000", // A\r
+    "0000000000000000000000000000000000000000000000000000000000000007", // B\r
+    "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", // Gx\r
+    "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", // Gy\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters secp384r1 = {\r
+    48,\r
+    24,\r
+    "secp384r1",\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", // P\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", // A\r
+    "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", // B\r
+    "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", // Gx\r
+    "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", // Gy\r
+    "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters secp521r1 = {\r
+    66,\r
+    25,\r
+    "secp521r1",\r
+    "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // P\r
+    "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", // A\r
+    "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", // B\r
+    "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", // Gx\r
+    "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", // Gy\r
+    "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"  // order (n)\r
+};\r
+\r
+static struct ECCCurveParameters * const default_curve = &secp256r1;\r
+\r
+void init_curve(struct ECCCurveParameters *curve) {\r
+    curve->dp.size = curve->size;\r
+    curve->dp.name = (char *)curve->name;\r
+    curve->dp.B = (char *)curve->B;\r
+    curve->dp.prime = (char *)curve->P;\r
+    curve->dp.Gx = (char *)curve->Gx;\r
+    curve->dp.Gy = (char *)curve->Gy;\r
+    curve->dp.order = (char *)curve->order;\r
+}\r
+\r
+void init_curves() {\r
+    init_curve(&secp192r1);\r
+    init_curve(&secp224r1);\r
+    init_curve(&secp224k1);\r
+    init_curve(&secp256r1);\r
+    init_curve(&secp256k1);\r
+    init_curve(&secp384r1);\r
+    init_curve(&secp521r1);\r
+}\r
+#endif\r
+\r
+struct TLSContext {\r
+    unsigned char remote_random[__TLS_CLIENT_RANDOM_SIZE];\r
+    unsigned char local_random[__TLS_SERVER_RANDOM_SIZE];\r
+    unsigned char session[__TLS_MAX_SESSION_ID];\r
+    unsigned char session_size;\r
+    unsigned short cipher;\r
+    unsigned short version;\r
+    unsigned char is_server;\r
+    struct TLSCertificate **certificates;\r
+    struct TLSCertificate *private_key;\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+    struct TLSCertificate *ec_private_key;\r
+#endif\r
+#ifdef TLS_FORWARD_SECRECY\r
+    DHKey *dhe;\r
+    ecc_key *ecc_dhe;\r
+    char *default_dhe_p;\r
+    char *default_dhe_g;\r
+    const struct ECCCurveParameters *curve;\r
+#endif\r
+    struct TLSCertificate **client_certificates;\r
+    unsigned int certificates_count;\r
+    unsigned int client_certificates_count;\r
+    unsigned char *master_key;\r
+    unsigned int master_key_len;\r
+    unsigned char *premaster_key;\r
+    unsigned int premaster_key_len;\r
+    unsigned char cipher_spec_set;\r
+    TLSCipher crypto;\r
+    TLSHash *handshake_hash;\r
+    \r
+    unsigned char *message_buffer;\r
+    unsigned int message_buffer_len;\r
+    uint64_t remote_sequence_number;\r
+    uint64_t local_sequence_number;\r
+    \r
+    unsigned char connection_status;\r
+    unsigned char critical_error;\r
+    unsigned char error_code;\r
+    \r
+    unsigned char *tls_buffer;\r
+    unsigned int tls_buffer_len;\r
+    \r
+    unsigned char *application_buffer;\r
+    unsigned int application_buffer_len;\r
+    unsigned char is_child;\r
+    unsigned char exportable;\r
+    unsigned char *exportable_keys;\r
+    unsigned char exportable_size;\r
+    char *sni;\r
+    unsigned char request_client_certificate;\r
+    unsigned char dtls;\r
+    unsigned short dtls_epoch_local;\r
+    unsigned short dtls_epoch_remote;\r
+    unsigned char *dtls_cookie;\r
+    unsigned char dtls_cookie_len;\r
+    unsigned char dtls_seq;\r
+    unsigned char *cached_handshake;\r
+    unsigned int cached_handshake_len;\r
+    unsigned char client_verified;\r
+    // handshake messages flags\r
+    unsigned char hs_messages[11];\r
+    void *user_data;\r
+    struct TLSCertificate **root_certificates;\r
+    unsigned int root_count;\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+    unsigned char *verify_data;\r
+    unsigned char verify_len;\r
+#endif\r
+    char **alpn;\r
+    unsigned char alpn_count;\r
+    char *negotiated_alpn;\r
+    unsigned int sleep_until;\r
+};\r
+\r
+struct TLSPacket {\r
+    unsigned char *buf;\r
+    unsigned int len;\r
+    unsigned int size;\r
+    unsigned char broken;\r
+    struct TLSContext *context;\r
+};\r
+\r
+#ifdef SSL_COMPATIBLE_INTERFACE\r
+\r
+typedef int (*SOCKET_RECV_CALLBACK)(int socket, void *buffer, size_t length, int flags);\r
+typedef int (*SOCKET_SEND_CALLBACK)(int socket, const void *buffer, size_t length, int flags);\r
+\r
+#ifdef _WIN32\r
+#include <winsock2.h>\r
+#else\r
+#include <sys/socket.h>\r
+#endif\r
+#endif\r
+\r
+static const unsigned int version_id[] = {1, 1, 1, 0};\r
+static const unsigned int pk_id[] = {1, 1, 7, 0};\r
+static const unsigned int serial_id[] = {1, 1, 2, 1, 0};\r
+static const unsigned int issurer_id[] = {1, 1, 4, 0};\r
+static const unsigned int owner_id[] = {1, 1, 6, 0};\r
+static const unsigned int validity_id[] = {1, 1, 5, 0};\r
+static const unsigned int algorithm_id[] = {1, 1, 3, 0};\r
+static const unsigned int sign_id[] = {1, 3, 2, 1, 0};\r
+static const unsigned int priv_id[] = {1, 4, 0};\r
+static const unsigned int priv_der_id[] = {1, 3, 1, 0};\r
+static const unsigned int ecc_priv_id[] = {1, 2, 0};\r
+\r
+static const unsigned char country_oid[] = {0x55, 0x04, 0x06, 0x00};\r
+static const unsigned char state_oid[] = {0x55, 0x04, 0x08, 0x00};\r
+static const unsigned char location_oid[] = {0x55, 0x04, 0x07, 0x00};\r
+static const unsigned char entity_oid[] = {0x55, 0x04, 0x0A, 0x00};\r
+static const unsigned char subject_oid[] = {0x55, 0x04, 0x03, 0x00};\r
+static const unsigned char san_oid[] = {0x55, 0x1D, 0x11, 0x00};\r
+static const unsigned char ocsp_oid[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x00};\r
+\r
+static const unsigned char TLS_RSA_SIGN_RSA_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x00};\r
+static const unsigned char TLS_RSA_SIGN_MD5_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x00};\r
+static const unsigned char TLS_RSA_SIGN_SHA1_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x00};\r
+static const unsigned char TLS_RSA_SIGN_SHA256_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x00};\r
+static const unsigned char TLS_RSA_SIGN_SHA384_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C, 0x00};\r
+static const unsigned char TLS_RSA_SIGN_SHA512_OID[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D, 0x00};\r
+\r
+// static const unsigned char TLS_ECDSA_SIGN_SHA1_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01, 0x05, 0x00, 0x00};\r
+// static const unsigned char TLS_ECDSA_SIGN_SHA224_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x05, 0x00, 0x00};\r
+// static const unsigned char TLS_ECDSA_SIGN_SHA256_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x05, 0x00, 0x00};\r
+// static const unsigned char TLS_ECDSA_SIGN_SHA384_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x05, 0x00, 0x00};\r
+// static const unsigned char TLS_ECDSA_SIGN_SHA512_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04, 0x05, 0x00, 0x00};\r
+\r
+static const unsigned char TLS_EC_PUBLIC_KEY_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x00};\r
+\r
+static const unsigned char TLS_EC_prime192v1_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01, 0x00};\r
+static const unsigned char TLS_EC_prime192v2_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x02, 0x00};\r
+static const unsigned char TLS_EC_prime192v3_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x03, 0x00};\r
+static const unsigned char TLS_EC_prime239v1_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x04, 0x00};\r
+static const unsigned char TLS_EC_prime239v2_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x05, 0x00};\r
+static const unsigned char TLS_EC_prime239v3_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x06, 0x00};\r
+static const unsigned char TLS_EC_prime256v1_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x00};\r
+\r
+#define TLS_EC_secp256r1_OID    TLS_EC_prime256v1_OID\r
+static const unsigned char TLS_EC_secp224r1_OID[] = {0x2B, 0x81, 0x04, 0x00, 0x21, 0x00};\r
+static const unsigned char TLS_EC_secp384r1_OID[] = {0x2B, 0x81, 0x04, 0x00, 0x22, 0x00};\r
+static const unsigned char TLS_EC_secp521r1_OID[] = {0x2B, 0x81, 0x04, 0x00, 0x23, 0x00};\r
+\r
+struct TLSCertificate *asn1_parse(struct TLSContext *context, const unsigned char *buffer, int size, int client_cert);\r
+int __private_tls_update_hash(struct TLSContext *context, const unsigned char *in, unsigned int len);\r
+struct TLSPacket *tls_build_finished(struct TLSContext *context);\r
+unsigned int __private_tls_hmac_message(unsigned char local, struct TLSContext *context, const unsigned char *buf, int buf_len, const unsigned char *buf2, int buf_len2, unsigned char *out, unsigned int outlen, uint64_t remote_sequence_number);\r
+int tls_random(unsigned char *key, int len);\r
+void tls_destroy_packet(struct TLSPacket *packet);\r
+struct TLSPacket *tls_build_hello(struct TLSContext *context);\r
+struct TLSPacket *tls_build_certificate(struct TLSContext *context);\r
+struct TLSPacket *tls_build_done(struct TLSContext *context);\r
+struct TLSPacket *tls_build_alert(struct TLSContext *context, char critical, unsigned char code);\r
+struct TLSPacket *tls_build_change_cipher_spec(struct TLSContext *context);\r
+struct TLSPacket *tls_build_verify_request(struct TLSContext *context);\r
+int __private_tls_crypto_create(struct TLSContext *context, int key_length, int iv_length, unsigned char *localkey, unsigned char *localiv, unsigned char *remotekey, unsigned char *remoteiv);\r
+int __private_tls_get_hash(struct TLSContext *context, unsigned char *hout);\r
+int __private_tls_build_random(struct TLSPacket *packet);\r
+unsigned int __private_tls_mac_length(struct TLSContext *context);\r
+void __private_dtls_handshake_data(struct TLSContext *context, struct TLSPacket *packet, unsigned int dataframe);\r
+#ifdef TLS_FORWARD_SECRECY\r
+void __private_tls_dhe_free(struct TLSContext *context);\r
+void __private_tls_ecc_dhe_free(struct TLSContext *context);\r
+void __private_tls_dh_clear_key(DHKey *key);\r
+#endif\r
+\r
+static unsigned char dependecies_loaded = 0;\r
+// not supported\r
+// static unsigned char TLS_DSA_SIGN_SHA1_OID[] = {0x2A, 0x86, 0x52, 0xCE, 0x38, 0x04, 0x03, 0x00};\r
+\r
+// base64 stuff\r
+static const char cd64[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";\r
+\r
+void __private_b64_decodeblock(unsigned char in[4], unsigned char out[3]) {\r
+    out[0] = (unsigned char )(in[0] << 2 | in[1] >> 4);\r
+    out[1] = (unsigned char )(in[1] << 4 | in[2] >> 2);\r
+    out[2] = (unsigned char )(((in[2] << 6) & 0xc0) | in[3]);\r
+}\r
+\r
+int __private_b64_decode(const char *in_buffer, int in_buffer_size, unsigned char *out_buffer) {\r
+    unsigned char in[4], out[3], v;\r
+    int           i, len;\r
+    \r
+    const char *ptr     = in_buffer;\r
+    char *out_ptr = (char *)out_buffer;\r
+    \r
+    while (ptr <= in_buffer + in_buffer_size) {\r
+        for (len = 0, i = 0; i < 4 && (ptr <= in_buffer + in_buffer_size); i++) {\r
+            v = 0;\r
+            while ((ptr <= in_buffer + in_buffer_size) && v == 0) {\r
+                v = (unsigned char)ptr[0];\r
+                ptr++;\r
+                v = (unsigned char)((v < 43 || v > 122) ? 0 : cd64[v - 43]);\r
+                if (v)\r
+                    v = (unsigned char)((v == '$') ? 0 : v - 61);\r
+            }\r
+            if (ptr <= in_buffer + in_buffer_size) {\r
+                len++;\r
+                if (v)\r
+                    in[i] = (unsigned char)(v - 1);\r
+            } else {\r
+                in[i] = 0;\r
+            }\r
+        }\r
+        if (len) {\r
+            __private_b64_decodeblock(in, out);\r
+            for (i = 0; i < len - 1; i++) {\r
+                out_ptr[0] = out[i];\r
+                out_ptr++;\r
+            }\r
+        }\r
+    }\r
+    return (int)((intptr_t)out_ptr - (intptr_t)out_buffer);\r
+}\r
+\r
+void tls_init() {\r
+    if (dependecies_loaded)\r
+        return;\r
+    DEBUG_PRINT("Initializing dependencies\n");\r
+    dependecies_loaded = 1;\r
+#ifdef LTM_DESC\r
+    ltc_mp = ltm_desc;\r
+#else\r
+#ifdef TFM_DESC\r
+    ltc_mp = tfm_desc;\r
+#else\r
+#ifdef GMP_DESC\r
+    ltc_mp = gmp_desc;\r
+#endif\r
+#endif\r
+#endif\r
+    register_prng(&sprng_desc);\r
+    register_hash(&sha256_desc);\r
+    register_hash(&sha1_desc);\r
+    register_hash(&sha384_desc);\r
+    register_hash(&sha512_desc);\r
+    register_hash(&md5_desc);\r
+    register_cipher(&aes_desc);\r
+#ifdef TLS_FORWARD_SECRECY\r
+    init_curves();\r
+#endif\r
+}\r
+\r
+#ifdef TLS_FORWARD_SECRECY\r
+int __private_tls_dh_shared_secret(DHKey *private_key, DHKey *public_key, unsigned char *out, unsigned long *outlen) {\r
+    void *tmp;\r
+    unsigned long x;\r
+    int err;\r
+    \r
+    if ((!private_key) || (!public_key) || (!out) || (!outlen))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    /* compute y^x mod p */\r
+    if ((err = mp_init(&tmp)) != CRYPT_OK)\r
+        return err;\r
+    \r
+    if ((err = mp_exptmod(public_key->y, private_key->x, private_key->p, tmp)) != CRYPT_OK) {\r
+        mp_clear(tmp);\r
+        return err;\r
+    }\r
+    \r
+    x = (unsigned long)mp_unsigned_bin_size(tmp);\r
+    if (*outlen < x) {\r
+        err = CRYPT_BUFFER_OVERFLOW;\r
+        mp_clear(tmp);\r
+        return err;\r
+    }\r
+    \r
+    if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {\r
+        mp_clear(tmp);\r
+        return err;\r
+    }\r
+    *outlen = x;\r
+    mp_clear(tmp);\r
+    return 0;\r
+}\r
+\r
+unsigned char *__private_tls_decrypt_dhe(struct TLSContext *context, const unsigned char *buffer, unsigned int len, unsigned int *size, int clear_key) {\r
+    *size = 0;\r
+    if ((!len) || (!context) || (!context->dhe)) {\r
+        DEBUG_PRINT("No private DHE key set\n");\r
+        return NULL;\r
+    }\r
+    \r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(len);\r
+    unsigned long out_size = len;\r
+    void *Yc = NULL;\r
+    \r
+    if (mp_init(&Yc)) {\r
+        DEBUG_PRINT("ERROR CREATING Yc\n");\r
+        return NULL;\r
+    }\r
+    if (mp_read_unsigned_bin(Yc, (unsigned char *)buffer, len)) {\r
+        DEBUG_PRINT("ERROR LOADING DHE Yc\n");\r
+        mp_clear(Yc);\r
+        return NULL;\r
+    }\r
+    DHKey client_key;\r
+    memset(&client_key, 0, sizeof(DHKey));\r
+    \r
+    client_key.p = context->dhe->p;\r
+    client_key.g = context->dhe->g;\r
+    client_key.y = Yc;\r
+    int err = __private_tls_dh_shared_secret(context->dhe, &client_key, out, &out_size);\r
+    // don't delete p and g\r
+    client_key.p = NULL;\r
+    client_key.g = NULL;\r
+    __private_tls_dh_clear_key(&client_key);\r
+    // not needing the dhe key anymore\r
+    if (clear_key)\r
+        __private_tls_dhe_free(context);\r
+    if (err) {\r
+        DEBUG_PRINT("DHE DECRYPT ERROR %i\n", err);\r
+        TLS_FREE(out);\r
+        return NULL;\r
+    }\r
+    DEBUG_PRINT("OUT_SIZE: %lu\n", out_size);\r
+    DEBUG_DUMP_HEX_LABEL("DHE", out, out_size);\r
+    *size = (unsigned int)out_size;\r
+    return out;\r
+}\r
+\r
+unsigned char *__private_tls_decrypt_ecc_dhe(struct TLSContext *context, const unsigned char *buffer, unsigned int len, unsigned int *size, int clear_key) {\r
+    *size = 0;\r
+    if ((!len) || (!context) || (!context->ecc_dhe)) {\r
+        DEBUG_PRINT("No private ECC DHE key set\n");\r
+        return NULL;\r
+    }\r
+    \r
+    const struct ECCCurveParameters *curve;\r
+    if (context->curve)\r
+        curve = context->curve;\r
+    else\r
+        curve = default_curve;\r
+    \r
+    ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&curve->dp;\r
+    \r
+    ecc_key client_key;\r
+    memset(&client_key, 0, sizeof(client_key));\r
+    if (ecc_ansi_x963_import_ex(buffer, len, &client_key, dp)) {\r
+        DEBUG_PRINT("Error importing ECC DHE key\n");\r
+        return NULL;\r
+    }\r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(len);\r
+    unsigned long out_size = len;\r
+    \r
+    int err = ecc_shared_secret(context->ecc_dhe, &client_key, out, &out_size);\r
+    ecc_free(&client_key);\r
+    if (clear_key)\r
+        __private_tls_ecc_dhe_free(context);\r
+    if (err) {\r
+        DEBUG_PRINT("ECC DHE DECRYPT ERROR %i\n", err);\r
+        TLS_FREE(out);\r
+        return NULL;\r
+    }\r
+    DEBUG_PRINT("OUT_SIZE: %lu\n", out_size);\r
+    DEBUG_DUMP_HEX_LABEL("ECC DHE", out, out_size);\r
+    *size = (unsigned int)out_size;\r
+    return out;\r
+}\r
+#endif\r
+\r
+unsigned char *__private_tls_decrypt_rsa(struct TLSContext *context, const unsigned char *buffer, unsigned int len, unsigned int *size) {\r
+    *size = 0;\r
+    if ((!len) || (!context) || (!context->private_key) || (!context->private_key->der_bytes) || (!context->private_key->der_len)) {\r
+        DEBUG_PRINT("No private key set\n");\r
+        return NULL;\r
+    }\r
+    tls_init();\r
+    rsa_key key;\r
+    int err;\r
+    err = rsa_import(context->private_key->der_bytes, context->private_key->der_len, &key);\r
+    \r
+    if (err) {\r
+        DEBUG_PRINT("Error importing RSA key (code: %i)\n", err);\r
+        return NULL;\r
+    }\r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(len);\r
+    unsigned long out_size = len;\r
+    int hash_idx = find_hash("sha256");\r
+    int res = 0;\r
+    err = rsa_decrypt_key_ex(buffer, len, out, &out_size, (unsigned char *)"Concept", 7, hash_idx, LTC_PKCS_1_V1_5, &res, &key);\r
+    rsa_free(&key);\r
+    if ((err) || (!out_size)) {\r
+        DEBUG_PRINT("RSA DECRYPT ERROR\n");\r
+        TLS_FREE(out);\r
+        return NULL;\r
+    }\r
+    *size = (unsigned int)out_size;\r
+    return out;\r
+}\r
+\r
+unsigned char *__private_tls_encrypt_rsa(struct TLSContext *context, const unsigned char *buffer, unsigned int len, unsigned int *size) {\r
+    *size = 0;\r
+    if ((!len) || (!context) || (!context->certificates) || (!context->certificates_count) || (!context->certificates[0]) ||\r
+        (!context->certificates[0]->der_bytes) || (!context->certificates[0]->der_len)) {\r
+        DEBUG_PRINT("No certificate set\n");\r
+        return NULL;\r
+    }\r
+    tls_init();\r
+    rsa_key key;\r
+    int err;\r
+    err = rsa_import(context->certificates[0]->der_bytes, context->certificates[0]->der_len, &key);\r
+    \r
+    if (err) {\r
+        DEBUG_PRINT("Error importing RSA certificate (code: %i)\n", err);\r
+        return NULL;\r
+    }\r
+    unsigned long out_size = __TLS_MAX_RSA_KEY;\r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(out_size);\r
+    int hash_idx = find_hash("sha256");\r
+    int prng_idx = find_prng("sprng");\r
+    err = rsa_encrypt_key_ex(buffer, len, out, &out_size, (unsigned char *)"Concept", 7, NULL, prng_idx, hash_idx, LTC_PKCS_1_V1_5, &key);\r
+    rsa_free(&key);\r
+    if ((err) || (!out_size)) {\r
+        TLS_FREE(out);\r
+        return NULL;\r
+    }\r
+    *size = (unsigned int)out_size;\r
+    return out;\r
+}\r
+\r
+#ifdef TLS_LEGACY_SUPPORT\r
+int __private_rsa_verify_hash_md5sha1(const unsigned char *sig, unsigned long siglen, unsigned char *hash, unsigned long hashlen, int *stat, rsa_key *key) {\r
+    unsigned long modulus_bitlen, modulus_bytelen, x;\r
+    int           err;\r
+    unsigned char *tmpbuf = NULL;\r
+    \r
+    if ((hash == NULL) || (sig == NULL) || (stat == NULL) || (key == NULL) || (!siglen) || (!hashlen))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    *stat = 0;\r
+    \r
+    modulus_bitlen = mp_count_bits((key->N));\r
+    \r
+    modulus_bytelen = mp_unsigned_bin_size((key->N));\r
+    if (modulus_bytelen != siglen)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    tmpbuf = (unsigned char *)TLS_MALLOC(siglen);\r
+    if (!tmpbuf)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    x = siglen;\r
+    if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {\r
+        TLS_FREE(tmpbuf);\r
+        return err;\r
+    }\r
+    \r
+    if (x != siglen) {\r
+        TLS_FREE(tmpbuf);\r
+        return CRYPT_INVALID_PACKET;\r
+    }\r
+    unsigned long out_len = siglen;\r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(siglen);\r
+    if (!out) {\r
+        TLS_FREE(tmpbuf);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    int decoded = 0;\r
+    err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &out_len, &decoded);\r
+    if (decoded) {\r
+        if (out_len == hashlen) {\r
+            if (!memcmp(out, hash, hashlen))\r
+                *stat = 1;\r
+        }\r
+    }\r
+    \r
+    TLS_FREE(tmpbuf);\r
+    TLS_FREE(out);\r
+    return err;\r
+}\r
+#endif\r
+\r
+int __private_tls_verify_rsa(struct TLSContext *context, unsigned int hash_type, const unsigned char *buffer, unsigned int len, const unsigned char *message, unsigned int message_len) {\r
+    tls_init();\r
+    rsa_key key;\r
+    int err;\r
+    \r
+    if (context->is_server) {\r
+        if ((!len) || (!context) || (!context->client_certificates) || (!context->client_certificates_count) || (!context->client_certificates[0]) ||\r
+            (!context->client_certificates[0]->der_bytes) || (!context->client_certificates[0]->der_len)) {\r
+            DEBUG_PRINT("No client certificate set\n");\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = rsa_import(context->client_certificates[0]->der_bytes, context->client_certificates[0]->der_len, &key);\r
+    } else {\r
+        if ((!len) || (!context) || (!context->certificates) || (!context->certificates_count) || (!context->certificates[0]) ||\r
+            (!context->certificates[0]->der_bytes) || (!context->certificates[0]->der_len)) {\r
+            DEBUG_PRINT("No server certificate set\n");\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = rsa_import(context->certificates[0]->der_bytes, context->certificates[0]->der_len, &key);\r
+    }\r
+    if (err) {\r
+        DEBUG_PRINT("Error importing RSA certificate (code: %i)\n", err);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int hash_idx = -1;\r
+    unsigned char hash[__TLS_MAX_HASH_LEN];\r
+    unsigned int hash_len = 0;\r
+    hash_state state;\r
+    switch (hash_type) {\r
+        case md5:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_len = 16;\r
+            break;\r
+        case sha1:\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash);\r
+            }\r
+            hash_len = 20;\r
+            break;\r
+        case sha256:\r
+            hash_idx = find_hash("sha256");\r
+            err = sha256_init(&state);\r
+            if (!err) {\r
+                err = sha256_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha256_done(&state, hash);\r
+            }\r
+            hash_len = 32;\r
+            break;\r
+        case sha384:\r
+            hash_idx = find_hash("sha384");\r
+            err = sha384_init(&state);\r
+            if (!err) {\r
+                err = sha384_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha384_done(&state, hash);\r
+            }\r
+            hash_len = 48;\r
+            break;\r
+        case sha512:\r
+            hash_idx = find_hash("sha512");\r
+            err = sha512_init(&state);\r
+            if (!err) {\r
+                err = sha512_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha512_done(&state, hash);\r
+            }\r
+            hash_len = 64;\r
+            break;\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        case __md5_sha1:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            break;\r
+#endif\r
+    }\r
+    if ((hash_idx < 0) || (err)) {\r
+        DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int rsa_stat = 0;\r
+#ifdef TLS_LEGACY_SUPPORT\r
+    if (hash_type == __md5_sha1)\r
+        err = __private_rsa_verify_hash_md5sha1(buffer, len, hash, hash_len, &rsa_stat, &key);\r
+    else\r
+#endif\r
+        err = rsa_verify_hash_ex(buffer, len, hash, hash_len, LTC_PKCS_1_V1_5, hash_idx, 0, &rsa_stat, &key);\r
+    rsa_free(&key);\r
+    if (err)\r
+        return 0;\r
+    return rsa_stat;\r
+}\r
+\r
+#ifdef TLS_LEGACY_SUPPORT\r
+int __private_rsa_sign_hash_md5sha1(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int prng_idx, unsigned long saltlen, rsa_key *key) {\r
+    unsigned long modulus_bitlen, modulus_bytelen, x;\r
+    int err;\r
+    \r
+    if ((in == NULL) || (out == NULL) || (outlen == NULL) || (key == NULL))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    modulus_bitlen = mp_count_bits((key->N));\r
+    \r
+    modulus_bytelen = mp_unsigned_bin_size((key->N));\r
+    if (modulus_bytelen > *outlen) {\r
+        *outlen = modulus_bytelen;\r
+        return CRYPT_BUFFER_OVERFLOW;\r
+    }\r
+    x = modulus_bytelen;\r
+    err = pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, out, &x);\r
+    if (err != CRYPT_OK)\r
+        return err;\r
+    \r
+    return ltc_mp.rsa_me(out, x, out, outlen, PK_PRIVATE, key);\r
+}\r
+#endif\r
+\r
+int __private_tls_sign_rsa(struct TLSContext *context, unsigned int hash_type, const unsigned char *message, unsigned int message_len, unsigned char *out, unsigned long *outlen) {\r
+    if ((!outlen) || (!context) || (!out) || (!outlen) || (!context->private_key) || (!context->private_key->der_bytes) || (!context->private_key->der_len)) {\r
+        DEBUG_PRINT("No private key set\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    tls_init();\r
+    rsa_key key;\r
+    int err;\r
+    err = rsa_import(context->private_key->der_bytes, context->private_key->der_len, &key);\r
+    \r
+    if (err) {\r
+        DEBUG_PRINT("Error importing RSA certificate (code: %i)\n", err);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int hash_idx = -1;\r
+    unsigned char hash[__TLS_MAX_HASH_LEN];\r
+    unsigned int hash_len = 0;\r
+    hash_state state;\r
+    switch (hash_type) {\r
+        case md5:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_len = 16;\r
+            break;\r
+        case sha1:\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash);\r
+            }\r
+            hash_len = 20;\r
+            break;\r
+        case sha256:\r
+            hash_idx = find_hash("sha256");\r
+            err = sha256_init(&state);\r
+            if (!err) {\r
+                err = sha256_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha256_done(&state, hash);\r
+            }\r
+            hash_len = 32;\r
+            break;\r
+        case sha384:\r
+            hash_idx = find_hash("sha384");\r
+            err = sha384_init(&state);\r
+            if (!err) {\r
+                err = sha384_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha384_done(&state, hash);\r
+            }\r
+            hash_len = 48;\r
+            break;\r
+        case sha512:\r
+            hash_idx = find_hash("sha512");\r
+            err = sha512_init(&state);\r
+            if (!err) {\r
+                err = sha512_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha512_done(&state, hash);\r
+            }\r
+            hash_len = 64;\r
+            break;\r
+        case __md5_sha1:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            break;\r
+    }\r
+#ifdef TLS_LEGACY_SUPPORT\r
+    if (hash_type == __md5_sha1) {\r
+        if (err) {\r
+            DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = __private_rsa_sign_hash_md5sha1(hash, hash_len, out, outlen, NULL, find_prng("sprng"), 0, &key);\r
+    } else\r
+#endif\r
+    {\r
+        if ((hash_idx < 0) || (err)) {\r
+            DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = rsa_sign_hash_ex(hash, hash_len, out, outlen, LTC_PKCS_1_V1_5, NULL, find_prng("sprng"), hash_idx, 0, &key);\r
+    }\r
+    rsa_free(&key);\r
+    if (err)\r
+        return 0;\r
+    \r
+    return 1;\r
+}\r
+\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+static int __private_tls_is_point(ecc_key *key) {\r
+    void *prime, *b, *t1, *t2;\r
+    int  err;\r
+    \r
+    if ((err = mp_init_multi(&prime, &b, &t1, &t2, NULL)) != CRYPT_OK) {\r
+        return err;\r
+    }\r
+    \r
+    /* load prime and b */\r
+    if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    \r
+    /* compute y^2 */\r
+    if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    \r
+    /* compute x^3 */\r
+    if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    \r
+    /* compute y^2 - x^3 */\r
+    if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    \r
+    /* compute y^2 - x^3 + 3x */\r
+    if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) {\r
+        goto error;\r
+    }\r
+    while (mp_cmp_d(t1, 0) == LTC_MP_LT) {\r
+        if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) {\r
+            goto error;\r
+        }\r
+    }\r
+    while (mp_cmp(t1, prime) != LTC_MP_LT) {\r
+        if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) {\r
+            goto error;\r
+        }\r
+    }\r
+    \r
+    /* compare to b */\r
+    if (mp_cmp(t1, b) != LTC_MP_EQ) {\r
+        err = CRYPT_INVALID_PACKET;\r
+    } else {\r
+        err = CRYPT_OK;\r
+    }\r
+    \r
+error:\r
+    mp_clear_multi(prime, b, t1, t2, NULL);\r
+    return err;\r
+}\r
+\r
+int __private_tls_ecc_import_key(const unsigned char *private_key, int private_len, const unsigned char *public_key, int public_len, ecc_key *key, const ltc_ecc_set_type *dp) {\r
+    int           err;\r
+    \r
+    if ((!key) || (!ltc_mp.name))\r
+        return CRYPT_MEM;\r
+        \r
+    key->type = PK_PRIVATE;\r
+    \r
+    if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL) != CRYPT_OK)\r
+        return CRYPT_MEM;\r
+    \r
+    if ((public_len) && (!public_key[0])) {\r
+        public_key++;\r
+        public_len--;\r
+    }\r
+    if ((err = mp_read_unsigned_bin(key->pubkey.x, (unsigned char *)public_key + 1, (public_len - 1) >> 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    if ((err = mp_read_unsigned_bin(key->pubkey.y, (unsigned char *)public_key + 1 + ((public_len - 1) >> 1), (public_len - 1) >> 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)private_key, private_len)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    key->idx = -1;\r
+    key->dp  = dp;\r
+    \r
+    /* set z */\r
+    if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    /* is it a point on the curve?  */\r
+    if ((err = __private_tls_is_point(key)) != CRYPT_OK) {\r
+        DEBUG_PRINT("KEY IS NOT ON CURVE\n");\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    /* we're good */\r
+    return CRYPT_OK;\r
+}\r
+\r
+int __private_tls_sign_ecdsa(struct TLSContext *context, unsigned int hash_type, const unsigned char *message, unsigned int message_len, unsigned char *out, unsigned long *outlen) {\r
+    if ((!outlen) || (!context) || (!out) || (!outlen) || (!context->ec_private_key) ||\r
+        (!context->ec_private_key->priv) || (!context->ec_private_key->priv_len) || (!context->ec_private_key->pk) || (!context->ec_private_key->pk_len)) {\r
+        DEBUG_PRINT("No private ECDSA key set\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    const struct ECCCurveParameters *curve = NULL;\r
+    \r
+    switch (context->ec_private_key->ec_algorithm) {\r
+        case 19:\r
+            curve = &secp192r1;\r
+            break;\r
+        case 20:\r
+            curve = &secp224k1;\r
+            break;\r
+        case 21:\r
+            curve = &secp224r1;\r
+            break;\r
+        case 22:\r
+            curve = &secp256k1;\r
+            break;\r
+        case 23:\r
+            curve = &secp256r1;\r
+            break;\r
+        case 24:\r
+            curve = &secp384r1;\r
+            break;\r
+        case 25:\r
+            curve = &secp521r1;\r
+            break;\r
+        default:\r
+            DEBUG_PRINT("UNSUPPORTED CURVE\n");\r
+            return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    if (!curve)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    tls_init();\r
+    ecc_key key;\r
+    int err;\r
+    \r
+    ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&curve->dp;\r
+    \r
+    // broken ... fix this\r
+    err = __private_tls_ecc_import_key(context->ec_private_key->priv, context->ec_private_key->priv_len, context->ec_private_key->pk, context->ec_private_key->pk_len, &key, dp);\r
+    if (err) {\r
+        DEBUG_PRINT("Error importing ECC certificate (code: %i)\n", (int)err);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int hash_idx = -1;\r
+    unsigned char hash[__TLS_MAX_HASH_LEN];\r
+    unsigned int hash_len = 0;\r
+    hash_state state;\r
+    switch (hash_type) {\r
+        case md5:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_len = 16;\r
+            break;\r
+        case sha1:\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash);\r
+            }\r
+            hash_len = 20;\r
+            break;\r
+        case sha256:\r
+            hash_idx = find_hash("sha256");\r
+            err = sha256_init(&state);\r
+            if (!err) {\r
+                err = sha256_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha256_done(&state, hash);\r
+            }\r
+            hash_len = 32;\r
+            break;\r
+        case sha384:\r
+            hash_idx = find_hash("sha384");\r
+            err = sha384_init(&state);\r
+            if (!err) {\r
+                err = sha384_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha384_done(&state, hash);\r
+            }\r
+            hash_len = 48;\r
+            break;\r
+        case sha512:\r
+            hash_idx = find_hash("sha512");\r
+            err = sha512_init(&state);\r
+            if (!err) {\r
+                err = sha512_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha512_done(&state, hash);\r
+            }\r
+            hash_len = 64;\r
+            break;\r
+        case __md5_sha1:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            break;\r
+    }\r
+    \r
+    if ((hash_idx < 0) || (err)) {\r
+        DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    // "Let z be the Ln leftmost bits of e, where Ln is the bit length of the group order n."\r
+    if (hash_len > curve->size)\r
+        hash_len = curve->size;\r
+    err = ecc_sign_hash(hash, hash_len, out, outlen, NULL, find_prng("sprng"), &key);\r
+    DEBUG_DUMP_HEX_LABEL("ECC SIGNATURE", out, *outlen);\r
+    ecc_free(&key);\r
+    if (err)\r
+        return 0;\r
+    \r
+    return 1;\r
+}\r
+\r
+#ifdef TLS_CLIENT_ECDSA\r
+int __private_tls_ecc_import_pk(const unsigned char *public_key, int public_len, ecc_key *key, const ltc_ecc_set_type *dp) {\r
+    int           err;\r
+    \r
+    if ((!key) || (!ltc_mp.name))\r
+        return CRYPT_MEM;\r
+        \r
+    key->type = PK_PUBLIC;\r
+    \r
+    if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL) != CRYPT_OK)\r
+        return CRYPT_MEM;\r
+    \r
+    if ((public_len) && (!public_key[0])) {\r
+        public_key++;\r
+        public_len--;\r
+    }\r
+    if ((err = mp_read_unsigned_bin(key->pubkey.x, (unsigned char *)public_key + 1, (public_len - 1) >> 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    if ((err = mp_read_unsigned_bin(key->pubkey.y, (unsigned char *)public_key + 1 + ((public_len - 1) >> 1), (public_len - 1) >> 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    \r
+    key->idx = -1;\r
+    key->dp  = dp;\r
+    \r
+    /* set z */\r
+    if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) {\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    /* is it a point on the curve?  */\r
+    if ((err = __private_tls_is_point(key)) != CRYPT_OK) {\r
+        DEBUG_PRINT("KEY IS NOT ON CURVE\n");\r
+        mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);\r
+        return err;\r
+    }\r
+    \r
+    /* we're good */\r
+    return CRYPT_OK;\r
+}\r
+\r
+int __private_tls_verify_ecdsa(struct TLSContext *context, unsigned int hash_type, const unsigned char *buffer, unsigned int len, const unsigned char *message, unsigned int message_len) {\r
+    tls_init();\r
+    ecc_key key;\r
+    int err;\r
+    \r
+    if (context->is_server) {\r
+        if ((!len) || (!context) || (!context->client_certificates) || (!context->client_certificates_count) || (!context->client_certificates[0]) ||\r
+            (!context->client_certificates[0]->pk) || (!context->client_certificates[0]->pk_len) || (!context->curve)) {\r
+            DEBUG_PRINT("No client certificate set\n");\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = __private_tls_ecc_import_pk(context->client_certificates[0]->pk, context->client_certificates[0]->pk_len, &key, (ltc_ecc_set_type *)&context->curve->dp);\r
+    } else {\r
+        if ((!len) || (!context) || (!context->certificates) || (!context->certificates_count) || (!context->certificates[0]) ||\r
+            (!context->certificates[0]->pk) || (!context->certificates[0]->pk_len) || (!context->curve)) {\r
+            DEBUG_PRINT("No server certificate set\n");\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        err = __private_tls_ecc_import_pk(context->certificates[0]->pk, context->certificates[0]->pk_len, &key, (ltc_ecc_set_type *)&context->curve->dp);\r
+    }\r
+    if (err) {\r
+        DEBUG_PRINT("Error importing ECC certificate (code: %i)", err);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int hash_idx = -1;\r
+    unsigned char hash[__TLS_MAX_HASH_LEN];\r
+    unsigned int hash_len = 0;\r
+    hash_state state;\r
+    switch (hash_type) {\r
+        case md5:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_len = 16;\r
+            break;\r
+        case sha1:\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash);\r
+            }\r
+            hash_len = 20;\r
+            break;\r
+        case sha256:\r
+            hash_idx = find_hash("sha256");\r
+            err = sha256_init(&state);\r
+            if (!err) {\r
+                err = sha256_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha256_done(&state, hash);\r
+            }\r
+            hash_len = 32;\r
+            break;\r
+        case sha384:\r
+            hash_idx = find_hash("sha384");\r
+            err = sha384_init(&state);\r
+            if (!err) {\r
+                err = sha384_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha384_done(&state, hash);\r
+            }\r
+            hash_len = 48;\r
+            break;\r
+        case sha512:\r
+            hash_idx = find_hash("sha512");\r
+            err = sha512_init(&state);\r
+            if (!err) {\r
+                err = sha512_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha512_done(&state, hash);\r
+            }\r
+            hash_len = 64;\r
+            break;\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        case __md5_sha1:\r
+            hash_idx = find_hash("md5");\r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            hash_idx = find_hash("sha1");\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash + 16);\r
+            }\r
+            hash_len = 36;\r
+            break;\r
+#endif\r
+    }\r
+    if ((hash_idx < 0) || (err)) {\r
+        DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    int ecc_stat = 0;\r
+    err = ecc_verify_hash(buffer, len, hash, hash_len, &ecc_stat, &key);\r
+    ecc_free(&key);\r
+    if (err)\r
+        return 0;\r
+    return ecc_stat;\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+unsigned int __private_tls_random_int(int limit) {\r
+    unsigned int res = 0;\r
+    tls_random((unsigned char *)&res, sizeof(int));\r
+    if (limit)\r
+        res %= limit;\r
+    return res;\r
+}\r
+\r
+void __private_tls_sleep(unsigned int microseconds) {\r
+#ifdef _WIN32\r
+    Sleep(microseconds/1000);\r
+#else\r
+    struct timespec ts;\r
+    \r
+    ts.tv_sec = (unsigned int) (microseconds / 1000000);\r
+    ts.tv_nsec = (unsigned int) (microseconds % 1000000) * 1000ul;\r
+    \r
+    nanosleep(&ts, NULL);\r
+#endif\r
+}\r
+\r
+void __private_random_sleep(struct TLSContext *context, int max_microseconds) {\r
+    if (context)\r
+        context->sleep_until = time(NULL) + __private_tls_random_int(max_microseconds/1000000 * __TLS_MAX_ERROR_IDLE_S);\r
+    else\r
+        __private_tls_sleep(__private_tls_random_int(max_microseconds));\r
+}\r
+\r
+void __private_tls_prf_helper(int hash_idx, unsigned long dlen, unsigned char *output, unsigned int outlen, const unsigned char *secret, const unsigned int secret_len,\r
+                              const unsigned char *label, unsigned int label_len, unsigned char *seed, unsigned int seed_len,\r
+                              unsigned char *seed_b, unsigned int seed_b_len) {\r
+    unsigned char digest_out0[__TLS_MAX_HASH_LEN];\r
+    unsigned char digest_out1[__TLS_MAX_HASH_LEN];\r
+    unsigned int i;\r
+    hmac_state hmac;\r
+    \r
+    hmac_init(&hmac, hash_idx, secret, secret_len);\r
+    hmac_process(&hmac, label, label_len);\r
+    \r
+    hmac_process(&hmac, seed, seed_len);\r
+    if ((seed_b) && (seed_b_len))\r
+        hmac_process(&hmac, seed_b, seed_b_len);\r
+    hmac_done(&hmac, digest_out0, &dlen);\r
+    int idx = 0;\r
+    while (outlen) {\r
+        hmac_init(&hmac, hash_idx, secret, secret_len);\r
+        hmac_process(&hmac, digest_out0, dlen);\r
+        hmac_process(&hmac, label, label_len);\r
+        hmac_process(&hmac, seed, seed_len);\r
+        if ((seed_b) && (seed_b_len))\r
+            hmac_process(&hmac, seed_b, seed_b_len);\r
+        hmac_done(&hmac, digest_out1, &dlen);\r
+        \r
+        unsigned int copylen = outlen;\r
+        if (copylen > dlen)\r
+            copylen = dlen;\r
+        \r
+        for (i = 0; i < copylen; i++) {\r
+            output[idx++] ^= digest_out1[i];\r
+            outlen--;\r
+        }\r
+        \r
+        if (!outlen)\r
+            break;\r
+        \r
+        hmac_init(&hmac, hash_idx, secret, secret_len);\r
+        hmac_process(&hmac, digest_out0, dlen);\r
+        hmac_done(&hmac, digest_out0, &dlen);\r
+    }\r
+}\r
+\r
+void __private_tls_prf(struct TLSContext *context,\r
+                       unsigned char *output, unsigned int outlen, const unsigned char *secret, const unsigned int secret_len,\r
+                       const unsigned char *label, unsigned int label_len, unsigned char *seed, unsigned int seed_len,\r
+                       unsigned char *seed_b, unsigned int seed_b_len) {\r
+    if ((!secret) || (!secret_len)) {\r
+        DEBUG_PRINT("NULL SECRET\n");\r
+        return;\r
+    }\r
+    if ((context->version != TLS_V12) && (context->version != DTLS_V12)) {\r
+        int md5_hash_idx = find_hash("md5");\r
+        int sha1_hash_idx = find_hash("sha1");\r
+        int half_secret = (secret_len + 1) / 2;\r
+        \r
+        memset(output, 0, outlen);\r
+        __private_tls_prf_helper(md5_hash_idx, 16, output, outlen, secret, half_secret, label, label_len, seed, seed_len, seed_b, seed_b_len);\r
+        __private_tls_prf_helper(sha1_hash_idx, 20, output, outlen, secret + (secret_len - half_secret), secret_len - half_secret, label, label_len, seed, seed_len, seed_b, seed_b_len);\r
+    } else {\r
+        // sha256_hmac\r
+        unsigned char digest_out0[__TLS_MAX_HASH_LEN];\r
+        unsigned char digest_out1[__TLS_MAX_HASH_LEN];\r
+        unsigned long dlen = 32;\r
+        int hash_idx;\r
+        unsigned int mac_length = __private_tls_mac_length(context);\r
+        if (mac_length == __TLS_SHA384_MAC_SIZE) {\r
+            hash_idx = find_hash("sha384");\r
+            dlen = mac_length;\r
+        } else\r
+            hash_idx = find_hash("sha256");\r
+        unsigned int i;\r
+        hmac_state hmac;\r
+        \r
+        hmac_init(&hmac, hash_idx, secret, secret_len);\r
+        hmac_process(&hmac, label, label_len);\r
+        \r
+        hmac_process(&hmac, seed, seed_len);\r
+        if ((seed_b) && (seed_b_len))\r
+            hmac_process(&hmac, seed_b, seed_b_len);\r
+        hmac_done(&hmac, digest_out0, &dlen);\r
+        int idx = 0;\r
+        while (outlen) {\r
+            hmac_init(&hmac, hash_idx, secret, secret_len);\r
+            hmac_process(&hmac, digest_out0, dlen);\r
+            hmac_process(&hmac, label, label_len);\r
+            hmac_process(&hmac, seed, seed_len);\r
+            if ((seed_b) && (seed_b_len))\r
+                hmac_process(&hmac, seed_b, seed_b_len);\r
+            hmac_done(&hmac, digest_out1, &dlen);\r
+            \r
+            unsigned int copylen = outlen;\r
+            if (copylen > dlen)\r
+                copylen = (unsigned int)dlen;\r
+            \r
+            for (i = 0; i < copylen; i++) {\r
+                output[idx++] = digest_out1[i];\r
+                outlen--;\r
+            }\r
+            \r
+            if (!outlen)\r
+                break;\r
+            \r
+            hmac_init(&hmac, hash_idx, secret, secret_len);\r
+            hmac_process(&hmac, digest_out0, dlen);\r
+            hmac_done(&hmac, digest_out0, &dlen);\r
+        }\r
+    }\r
+}\r
+\r
+int __private_tls_key_length(struct TLSContext *context) {\r
+    switch (context->cipher) {\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+            return 16;\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+            return 32;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int __private_tls_is_aead(struct TLSContext *context) {\r
+    switch (context->cipher) {\r
+        case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+            return 1;\r
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+            return 2;\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+\r
+unsigned int __private_tls_mac_length(struct TLSContext *context) {\r
+    switch (context->cipher) {\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+            return __TLS_SHA1_MAC_SIZE;\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+            return __TLS_SHA256_MAC_SIZE;\r
+        case TLS_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+            return __TLS_SHA384_MAC_SIZE;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int __private_tls_expand_key(struct TLSContext *context) {\r
+    unsigned char key[__TLS_MAX_KEY_EXPANSION_SIZE];\r
+    \r
+    if ((!context->master_key) || (!context->master_key_len))\r
+        return 0;\r
+    \r
+    int key_length = __private_tls_key_length(context);\r
+    int mac_length = __private_tls_mac_length(context);\r
+    \r
+    if ((!key_length) || (!mac_length)) {\r
+        DEBUG_PRINT("KEY EXPANSION FAILED, KEY LENGTH: %i, MAC LENGTH: %i\n", key_length, mac_length);\r
+        return 0;\r
+    }\r
+\r
+    if (context->is_server)\r
+        __private_tls_prf(context, key, sizeof(key), context->master_key, context->master_key_len, (unsigned char *)"key expansion", 13, context->local_random, __TLS_SERVER_RANDOM_SIZE, context->remote_random, __TLS_CLIENT_RANDOM_SIZE);\r
+    else\r
+        __private_tls_prf(context, key, sizeof(key), context->master_key, context->master_key_len, (unsigned char *)"key expansion", 13, context->remote_random, __TLS_SERVER_RANDOM_SIZE, context->local_random, __TLS_CLIENT_RANDOM_SIZE);\r
+    \r
+    DEBUG_DUMP_HEX_LABEL("LOCAL RANDOM ", context->local_random, __TLS_SERVER_RANDOM_SIZE);\r
+    DEBUG_DUMP_HEX_LABEL("REMOTE RANDOM", context->remote_random, __TLS_CLIENT_RANDOM_SIZE);\r
+    DEBUG_PRINT("\n=========== EXPANSION ===========\n");\r
+    DEBUG_DUMP_HEX(key, __TLS_MAX_KEY_EXPANSION_SIZE);\r
+    DEBUG_PRINT("\n");\r
+    \r
+    unsigned char *clientkey = NULL;\r
+    unsigned char *serverkey = NULL;\r
+    unsigned char *clientiv = NULL;\r
+    unsigned char *serveriv = NULL;\r
+    int iv_length = __TLS_AES_IV_LENGTH;\r
+    \r
+    int pos = 0;\r
+    int is_aead = __private_tls_is_aead(context);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+    if (is_aead == 2) {\r
+        iv_length = __TLS_CHACHA20_IV_LENGTH;\r
+    } else\r
+#endif\r
+    if (is_aead)\r
+        iv_length = __TLS_AES_GCM_IV_LENGTH;\r
+    else {\r
+        if (context->is_server) {\r
+            memcpy(context->crypto.ctx_remote_mac.remote_mac, &key[pos], mac_length);\r
+            pos += mac_length;\r
+            memcpy(context->crypto.ctx_local_mac.local_mac, &key[pos], mac_length);\r
+            pos += mac_length;\r
+        } else {\r
+            memcpy(context->crypto.ctx_local_mac.local_mac, &key[pos], mac_length);\r
+            pos += mac_length;\r
+            memcpy(context->crypto.ctx_remote_mac.remote_mac, &key[pos], mac_length);\r
+            pos += mac_length;\r
+        }\r
+    }\r
+    \r
+    clientkey = &key[pos];\r
+    pos += key_length;\r
+    serverkey = &key[pos];\r
+    pos += key_length;\r
+    clientiv = &key[pos];\r
+    pos += iv_length;\r
+    serveriv = &key[pos];\r
+    pos += iv_length;\r
+    \r
+    DEBUG_PRINT("EXPANSION %i/%i\n", (int)pos, (int)__TLS_MAX_KEY_EXPANSION_SIZE);\r
+    DEBUG_DUMP_HEX_LABEL("CLIENT KEY", clientkey, key_length)\r
+    DEBUG_DUMP_HEX_LABEL("CLIENT IV", clientiv, iv_length)\r
+    DEBUG_DUMP_HEX_LABEL("CLIENT MAC KEY", context->is_server ? context->crypto.ctx_remote_mac.remote_mac : context->crypto.ctx_local_mac.local_mac, mac_length)\r
+    DEBUG_DUMP_HEX_LABEL("SERVER KEY", serverkey, key_length)\r
+    DEBUG_DUMP_HEX_LABEL("SERVER IV", serveriv, iv_length)\r
+    DEBUG_DUMP_HEX_LABEL("SERVER MAC KEY", context->is_server ? context->crypto.ctx_local_mac.local_mac : context->crypto.ctx_remote_mac.remote_mac, mac_length)\r
+    \r
+    if (context->is_server) {\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        if (is_aead == 2) {\r
+            memcpy(context->crypto.ctx_remote_mac.remote_nonce, clientiv, iv_length);\r
+            memcpy(context->crypto.ctx_local_mac.local_nonce, serveriv, iv_length);\r
+        } else\r
+#endif\r
+        if (is_aead) {\r
+            memcpy(context->crypto.ctx_remote_mac.remote_aead_iv, clientiv, iv_length);\r
+            memcpy(context->crypto.ctx_local_mac.local_aead_iv, serveriv, iv_length);\r
+        }\r
+        if (__private_tls_crypto_create(context, key_length, iv_length, serverkey, serveriv, clientkey, clientiv))\r
+            return 0;\r
+    } else {\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        if (is_aead == 2) {\r
+            memcpy(context->crypto.ctx_local_mac.local_nonce, clientiv, iv_length);\r
+            memcpy(context->crypto.ctx_remote_mac.remote_nonce, serveriv, iv_length);\r
+        } else\r
+#endif\r
+        if (is_aead) {\r
+            memcpy(context->crypto.ctx_local_mac.local_aead_iv, clientiv, iv_length);\r
+            memcpy(context->crypto.ctx_remote_mac.remote_aead_iv, serveriv, iv_length);\r
+        }\r
+        if (__private_tls_crypto_create(context, key_length, iv_length, clientkey, clientiv, serverkey, serveriv))\r
+            return 0;\r
+    }\r
+    \r
+    if (context->exportable) {\r
+        TLS_FREE(context->exportable_keys);\r
+        context->exportable_keys = (unsigned char *)TLS_MALLOC(key_length * 2);\r
+        if (context->exportable_keys) {\r
+            if (context->is_server) {\r
+                memcpy(context->exportable_keys, serverkey, key_length);\r
+                memcpy(context->exportable_keys + key_length, clientkey, key_length);\r
+            } else {\r
+                memcpy(context->exportable_keys, clientkey, key_length);\r
+                memcpy(context->exportable_keys + key_length, serverkey, key_length);\r
+            }\r
+            context->exportable_size = key_length * 2;\r
+        }\r
+    }\r
+    \r
+    // extract client_mac_key(mac_key_length)\r
+    // extract server_mac_key(mac_key_length)\r
+    // extract client_key(enc_key_length)\r
+    // extract server_key(enc_key_length)\r
+    // extract client_iv(fixed_iv_lengh)\r
+    // extract server_iv(fixed_iv_length)\r
+    return 1;\r
+}\r
+\r
+int __private_tls_compute_key(struct TLSContext *context, unsigned int key_len) {\r
+    if ((!context) || (!context->premaster_key) || (!context->premaster_key_len) || (key_len < 48)) {\r
+        DEBUG_PRINT("CANNOT COMPUTE MASTER SECRET\n");\r
+        return 0;\r
+    }\r
+    \r
+    unsigned char master_secret_label[] = "master secret";\r
+#ifdef __TLS_CHECK_PREMASTER_KEY\r
+    if (!tls_cipher_is_ephemeral(context)) {\r
+        unsigned short version = ntohs(*(unsigned short *)context->premaster_key);\r
+        // this check is not true for DHE/ECDHE ciphers\r
+        if (context->version > version) {\r
+            DEBUG_PRINT("Mismatch protocol version 0x(%x)\n", version);\r
+            return 0;\r
+        }\r
+    }\r
+#endif\r
+    TLS_FREE(context->master_key);\r
+    context->master_key_len = 0;\r
+    context->master_key = NULL;\r
+    if ((context->version == TLS_V12) || (context->version == TLS_V11) || (context->version == TLS_V10) ||  (context->version == DTLS_V12) || (context->version == DTLS_V10)) {\r
+        context->master_key = (unsigned char *)TLS_MALLOC(key_len);\r
+        if (!context->master_key)\r
+            return 0;\r
+        context->master_key_len = key_len;\r
+        if (context->is_server) {\r
+            __private_tls_prf(context,\r
+                              context->master_key, context->master_key_len,\r
+                              context->premaster_key, context->premaster_key_len,\r
+                              master_secret_label, 13,\r
+                              context->remote_random, __TLS_CLIENT_RANDOM_SIZE,\r
+                              context->local_random, __TLS_SERVER_RANDOM_SIZE\r
+            );\r
+        } else {\r
+            __private_tls_prf(context,\r
+                              context->master_key, context->master_key_len,\r
+                              context->premaster_key, context->premaster_key_len,\r
+                              master_secret_label, 13,\r
+                              context->local_random, __TLS_CLIENT_RANDOM_SIZE,\r
+                              context->remote_random, __TLS_SERVER_RANDOM_SIZE\r
+            );\r
+        }\r
+        TLS_FREE(context->premaster_key);\r
+        context->premaster_key = NULL;\r
+        context->premaster_key_len = 0;\r
+        DEBUG_PRINT("\n=========== Master key ===========\n");\r
+        DEBUG_DUMP_HEX(context->master_key, context->master_key_len);\r
+        DEBUG_PRINT("\n");\r
+        __private_tls_expand_key(context);\r
+        return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+unsigned char *tls_pem_decode(const unsigned char *data_in, unsigned int input_length, int cert_index, unsigned int *output_len) {\r
+    unsigned int i;\r
+    *output_len = 0;\r
+    int alloc_len = input_length / 4 * 3;\r
+    unsigned char *output = (unsigned char *)TLS_MALLOC(alloc_len);\r
+    if (!output)\r
+        return NULL;\r
+    unsigned int start_at = 0;\r
+    unsigned int idx = 0;\r
+    for (i = 0; i < input_length; i++) {\r
+        if ((data_in[i] == '\n') || (data_in[i] == '\r'))\r
+            continue;\r
+        \r
+        if (data_in[i] != '-')  {\r
+            // read entire line\r
+            while ((i < input_length) && (data_in[i] != '\n'))\r
+                i++;\r
+            continue;\r
+        }\r
+        \r
+        if (data_in[i] == '-') {\r
+            unsigned int end_idx = i;\r
+            //read until end of line\r
+            while ((i < input_length) && (data_in[i] != '\n'))\r
+                i++;\r
+            if (start_at) {\r
+                if (cert_index > 0) {\r
+                    cert_index--;\r
+                    start_at = 0;\r
+                } else {\r
+                    idx = __private_b64_decode((const char *)&data_in[start_at], end_idx - start_at, output);\r
+                    break;\r
+                }\r
+            } else\r
+                start_at = i + 1;\r
+        }\r
+    }\r
+    *output_len = idx;\r
+    if (!idx) {\r
+        TLS_FREE(output);\r
+        return NULL;\r
+    }\r
+    return output;\r
+}\r
+\r
+int __is_oid(const unsigned char *oid, const unsigned char *compare_to, int compare_to_len) {\r
+    int i = 0;\r
+    while ((oid[i]) && (i < compare_to_len)) {\r
+        if (oid[i] != compare_to[i])\r
+            return 0;\r
+        \r
+        i++;\r
+    }\r
+    return 1;\r
+}\r
+\r
+int __is_oid2(const unsigned char *oid, const unsigned char *compare_to, int compare_to_len, int oid_len) {\r
+    int i = 0;\r
+    if (oid_len < compare_to_len)\r
+        compare_to_len = oid_len;\r
+    while (i < compare_to_len) {\r
+        if (oid[i] != compare_to[i])\r
+            return 0;\r
+        \r
+        i++;\r
+    }\r
+    return 1;\r
+}\r
+\r
+struct TLSCertificate *tls_create_certificate() {\r
+    struct TLSCertificate *cert = (struct TLSCertificate *)TLS_MALLOC(sizeof(struct TLSCertificate));\r
+    if (cert)\r
+        memset(cert, 0, sizeof(struct TLSCertificate));\r
+    return cert;\r
+}\r
+\r
+int tls_certificate_valid_subject_name(const unsigned char *cert_subject, const char *subject) {\r
+    // no subjects ...\r
+    if (((!cert_subject) || (!cert_subject[0])) && ((!subject) || (!subject[0])))\r
+        return 0;\r
+    \r
+    if ((!subject) || (!subject[0]))\r
+        return bad_certificate;\r
+    \r
+    if ((!cert_subject) || (!cert_subject[0]))\r
+        return bad_certificate;\r
+    \r
+    // exact match\r
+    if (!strcmp((const char *)cert_subject, subject))\r
+        return 0;\r
+    \r
+    const char *wildcard = strchr((const char *)cert_subject, '*');\r
+    if (wildcard) {\r
+        // 6.4.3 (1) The client SHOULD NOT attempt to match a presented identifier in\r
+        // which the wildcard character comprises a label other than the left-most label\r
+        if (!wildcard[1]) {\r
+            // subject is [*]\r
+            // or\r
+            // subject is [something*] .. invalid\r
+            return bad_certificate;\r
+        }\r
+        wildcard++;\r
+        const char *match = strstr(subject, wildcard);\r
+        if ((!match) && (wildcard[0] == '.')) {\r
+            // check *.domain.com agains domain.com\r
+            wildcard++;\r
+            if (!strcasecmp(subject, wildcard))\r
+                return 0;\r
+        }\r
+        if (match) {\r
+            unsigned long offset = (unsigned long)match - (unsigned long)subject;\r
+            if (offset) {\r
+                // check for foo.*.domain.com against *.domain.com (invalid)\r
+                if (memchr(subject, '.', offset))\r
+                    return bad_certificate;\r
+            }\r
+            // check if exact match\r
+            if (!strcasecmp(match, wildcard))\r
+                return 0;\r
+        }\r
+    }\r
+    \r
+    return bad_certificate;\r
+}\r
+\r
+int tls_certificate_valid_subject(struct TLSCertificate *cert, const char *subject) {\r
+    int i;\r
+    if (!cert)\r
+        return certificate_unknown;\r
+    int err = tls_certificate_valid_subject_name(cert->subject, subject);\r
+    if ((err) && (cert->san)) {\r
+        for (i = 0; i < cert->san_length; i++) {\r
+            err = tls_certificate_valid_subject_name(cert->san[i], subject);\r
+            if (!err)\r
+                return err;\r
+        }\r
+    }\r
+    return err;\r
+}\r
+\r
+int tls_certificate_is_valid(struct TLSCertificate *cert) {\r
+    if (!cert)\r
+        return certificate_unknown;\r
+    if (!cert->not_before)\r
+        return certificate_unknown;\r
+    if (!cert->not_after)\r
+        return certificate_unknown;\r
+    //20160224182300Z//\r
+    char current_time[16];\r
+    time_t t = time(NULL);\r
+    struct tm *utct = gmtime(&t);\r
+    if (utct) {\r
+        current_time[0] = 0;\r
+        snprintf(current_time, sizeof(current_time), "%04d%02d%02d%02d%02d%02dZ", 1900 + utct->tm_year, utct->tm_mon + 1, utct->tm_mday, utct->tm_hour, utct->tm_min, utct->tm_sec);\r
+        if (strcasecmp((char *)cert->not_before, current_time) > 0) {\r
+            DEBUG_PRINT("Certificate is not yer valid, now: %s (validity: %s - %s)\n", current_time, cert->not_before, cert->not_after);\r
+            return certificate_expired;\r
+        }\r
+        if (strcasecmp((char *)cert->not_after, current_time) < 0) {\r
+            DEBUG_PRINT("Expired certificate, now: %s (validity: %s - %s)\n", current_time, cert->not_before, cert->not_after);\r
+            return certificate_expired;\r
+        }\r
+        DEBUG_PRINT("Valid certificate, now: %s (validity: %s - %s)\n", current_time, cert->not_before, cert->not_after);\r
+    }\r
+    return 0;\r
+}\r
+\r
+void tls_certificate_set_copy(unsigned char **member, const unsigned char *val, int len) {\r
+    if (!member)\r
+        return;\r
+    TLS_FREE(*member);\r
+    if (len) {\r
+        *member = (unsigned char *)TLS_MALLOC(len + 1);\r
+        if (*member) {\r
+            memcpy(*member, val, len);\r
+            (*member)[len] = 0;\r
+        }\r
+    } else\r
+        *member = NULL;\r
+}\r
+\r
+void tls_certificate_set_copy_date(unsigned char **member, const unsigned char *val, int len) {\r
+    if (!member)\r
+        return;\r
+    TLS_FREE(*member);\r
+    if (len > 4) {\r
+        *member = (unsigned char *)TLS_MALLOC(len + 3);\r
+        if (*member) {\r
+            if (val[0] == '9') {\r
+                (*member)[0]='1';\r
+                (*member)[1]='9';\r
+            } else {\r
+                (*member)[0]='2';\r
+                (*member)[1]='0';\r
+            }\r
+            memcpy(*member + 2, val, len);\r
+            (*member)[len] = 0;\r
+        }\r
+    } else\r
+        *member = NULL;\r
+}\r
+\r
+void tls_certificate_set_key(struct TLSCertificate *cert, const unsigned char *val, int len) {\r
+    if ((!val[0]) && (len % 2)) {\r
+        val++;\r
+        len--;\r
+    }\r
+    tls_certificate_set_copy(&cert->pk, val, len);\r
+    if (cert->pk)\r
+        cert->pk_len = len;\r
+}\r
+\r
+void tls_certificate_set_priv(struct TLSCertificate *cert, const unsigned char *val, int len) {\r
+    tls_certificate_set_copy(&cert->priv, val, len);\r
+    if (cert->priv)\r
+        cert->priv_len = len;\r
+}\r
+\r
+void tls_certificate_set_sign_key(struct TLSCertificate *cert, const unsigned char *val, int len) {\r
+    if ((!val[0]) && (len % 2)) {\r
+        val++;\r
+        len--;\r
+    }\r
+    tls_certificate_set_copy(&cert->sign_key, val, len);\r
+    if (cert->sign_key)\r
+        cert->sign_len = len;\r
+}\r
+\r
+char *tls_certificate_to_string(struct TLSCertificate *cert, char *buffer, int len) {\r
+    unsigned int i;\r
+    if (!buffer)\r
+        return NULL;\r
+    buffer[0] = 0;\r
+    if (cert->version) {\r
+        int res = snprintf(buffer, len, "X.509v%i certificate\n  Issued by: [%s]%s (%s)\n  Issued to: [%s]%s (%s, %s)\n  Subject: %s\n  Validity: %s - %s\n  OCSP: %s\n  Serial number: ",\r
+                           (int)cert->version,\r
+                           cert->issuer_country, cert->issuer_entity, cert->issuer_subject,\r
+                           cert->country, cert->entity, cert->state, cert->location,\r
+                           cert->subject,\r
+                           cert->not_before, cert->not_after,\r
+                           cert->ocsp\r
+                           );\r
+        if (res > 0) {\r
+            for (i = 0; i < cert->serial_len; i++)\r
+                res += snprintf(buffer + res, len - res, "%02x", (int)cert->serial_number[i]);\r
+        }\r
+        if ((cert->san) && (cert->san_length)) {\r
+            res += snprintf(buffer + res, len - res, "\n  Alternative subjects: ");\r
+            for (i = 0; i < cert->san_length; i++) {\r
+                if (i)\r
+                    res += snprintf(buffer + res, len - res, ", %s", cert->san[i]);\r
+                else\r
+                    res += snprintf(buffer + res, len - res, "%s", cert->san[i]);\r
+            }\r
+        }\r
+        res += snprintf(buffer + res, len - res, "\n  Key (%i bits, ", cert->pk_len * 8);\r
+        if (res > 0) {\r
+            switch (cert->key_algorithm) {\r
+                case TLS_RSA_SIGN_RSA:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_RSA");\r
+                    break;\r
+                case TLS_RSA_SIGN_MD5:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_MD5");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA1:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA1");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA256:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA256");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA384:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA384");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA512:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA512");\r
+                    break;\r
+                case TLS_EC_PUBLIC_KEY:\r
+                    res += snprintf(buffer + res, len - res, "EC_PUBLIC_KEY");\r
+                    break;\r
+                default:\r
+                    res += snprintf(buffer + res, len - res, "not supported (%i)", (int)cert->key_algorithm);\r
+            }\r
+        }\r
+        if ((res > 0) && (cert->ec_algorithm)) {\r
+            switch (cert->ec_algorithm) {\r
+                case TLS_EC_prime192v1:\r
+                    res += snprintf(buffer + res, len - res, " prime192v1");\r
+                    break;\r
+                case TLS_EC_prime192v2:\r
+                    res += snprintf(buffer + res, len - res, " prime192v2");\r
+                    break;\r
+                case TLS_EC_prime192v3:\r
+                    res += snprintf(buffer + res, len - res, " prime192v3");\r
+                    break;\r
+                case TLS_EC_prime239v2:\r
+                    res += snprintf(buffer + res, len - res, " prime239v2");\r
+                    break;\r
+                case TLS_EC_secp256r1:\r
+                    res += snprintf(buffer + res, len - res, " EC_secp256r1");\r
+                    break;\r
+                case TLS_EC_secp224r1:\r
+                    res += snprintf(buffer + res, len - res, " EC_secp224r1");\r
+                    break;\r
+                case TLS_EC_secp384r1:\r
+                    res += snprintf(buffer + res, len - res, " EC_secp384r1");\r
+                    break;\r
+                case TLS_EC_secp521r1:\r
+                    res += snprintf(buffer + res, len - res, " EC_secp521r1");\r
+                    break;\r
+                default:\r
+                    res += snprintf(buffer + res, len - res, " unknown(%i)", (int)cert->ec_algorithm);\r
+            }\r
+        }\r
+        res += snprintf(buffer + res, len - res, "):\n");\r
+        if (res > 0) {\r
+            for (i = 0; i < cert->pk_len; i++)\r
+                res += snprintf(buffer + res, len - res, "%02x", (int)cert->pk[i]);\r
+            res += snprintf(buffer + res, len - res, "\n  Signature (%i bits, ", cert->sign_len * 8);\r
+            switch (cert->algorithm) {\r
+                case TLS_RSA_SIGN_RSA:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_RSA):\n");\r
+                    break;\r
+                case TLS_RSA_SIGN_MD5:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_MD5):\n");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA1:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA1):\n");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA256:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA256):\n");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA384:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA384):\n");\r
+                    break;\r
+                case TLS_RSA_SIGN_SHA512:\r
+                    res += snprintf(buffer + res, len - res, "RSA_SIGN_SHA512):\n");\r
+                    break;\r
+                case TLS_EC_PUBLIC_KEY:\r
+                    res += snprintf(buffer + res, len - res, "EC_PUBLIC_KEY):\n");\r
+                    break;\r
+                default:\r
+                    res += snprintf(buffer + res, len - res, "not supported):\n");\r
+            }\r
+            \r
+            for (i = 0; i < cert->sign_len; i++)\r
+                res += snprintf(buffer + res, len - res, "%02x", (int)cert->sign_key[i]);\r
+        }\r
+    } else\r
+    if ((cert->priv) && (cert->priv_len)) {\r
+        int res = snprintf(buffer, len, "X.509 private key\n");\r
+        res += snprintf(buffer + res, len - res, "  Private Key: ");\r
+        if (res > 0) {\r
+            for (i = 0; i < cert->priv_len; i++)\r
+                res += snprintf(buffer + res, len - res, "%02x", (int)cert->priv[i]);\r
+        }\r
+    } else\r
+        snprintf(buffer, len, "Empty ASN1 file");\r
+    return buffer;\r
+}\r
+\r
+void tls_certificate_set_exponent(struct TLSCertificate *cert, const unsigned char *val, int len) {\r
+    tls_certificate_set_copy(&cert->exponent, val, len);\r
+    if (cert->exponent)\r
+        cert->exponent_len = len;\r
+}\r
+\r
+void tls_certificate_set_serial(struct TLSCertificate *cert, const unsigned char *val, int len) {\r
+    tls_certificate_set_copy(&cert->serial_number, val, len);\r
+    if (cert->serial_number)\r
+        cert->serial_len = len;\r
+}\r
+\r
+void tls_certificate_set_algorithm(unsigned int *algorithm, const unsigned char *val, int len) {\r
+    if ((len == 7) && (__is_oid(val, TLS_EC_PUBLIC_KEY_OID, 7))) {\r
+        *algorithm = TLS_EC_PUBLIC_KEY;\r
+        return;\r
+    }\r
+    if (len == 8) {\r
+        if (__is_oid(val, TLS_EC_prime192v1_OID, len)) {\r
+            *algorithm = TLS_EC_prime192v1;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime192v2_OID, len)) {\r
+            *algorithm = TLS_EC_prime192v2;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime192v3_OID, len)) {\r
+            *algorithm = TLS_EC_prime192v3;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime239v1_OID, len)) {\r
+            *algorithm = TLS_EC_prime239v1;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime239v2_OID, len)) {\r
+            *algorithm = TLS_EC_prime239v2;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime239v3_OID, len)) {\r
+            *algorithm = TLS_EC_prime239v3;\r
+            return;\r
+        }\r
+        if (__is_oid(val, TLS_EC_prime256v1_OID, len)) {\r
+            *algorithm = TLS_EC_prime256v1;\r
+            return;\r
+        }\r
+    }\r
+    if (len == 5) {\r
+        if (__is_oid2(val, TLS_EC_secp224r1_OID, len, sizeof(TLS_EC_secp224r1_OID) - 1)) {\r
+            *algorithm = TLS_EC_secp224r1;\r
+            return;\r
+        }\r
+        if (__is_oid2(val, TLS_EC_secp384r1_OID, len, sizeof(TLS_EC_secp384r1_OID) - 1)) {\r
+            *algorithm = TLS_EC_secp384r1;\r
+            return;\r
+        }\r
+        if (__is_oid2(val, TLS_EC_secp521r1_OID, len, sizeof(TLS_EC_secp521r1_OID) - 1)) {\r
+            *algorithm = TLS_EC_secp521r1;\r
+            return;\r
+        }\r
+    }\r
+    if (len != 9)\r
+        return;\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_SHA256_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_SHA256;\r
+        return;\r
+    }\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_RSA_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_RSA;\r
+        return;\r
+    }\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_SHA1_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_SHA1;\r
+        return;\r
+    }\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_SHA512_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_SHA512;\r
+        return;\r
+    }\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_SHA384_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_SHA384;\r
+        return;\r
+    }\r
+    \r
+    if (__is_oid(val, TLS_RSA_SIGN_MD5_OID, 9)) {\r
+        *algorithm = TLS_RSA_SIGN_MD5;\r
+        return;\r
+    }\r
+}\r
+\r
+void tls_destroy_certificate(struct TLSCertificate *cert) {\r
+    if (cert) {\r
+        int i;\r
+        TLS_FREE(cert->exponent);\r
+        TLS_FREE(cert->pk);\r
+        TLS_FREE(cert->issuer_country);\r
+        TLS_FREE(cert->issuer_state);\r
+        TLS_FREE(cert->issuer_location);\r
+        TLS_FREE(cert->issuer_entity);\r
+        TLS_FREE(cert->issuer_subject);\r
+        TLS_FREE(cert->country);\r
+        TLS_FREE(cert->state);\r
+        TLS_FREE(cert->location);\r
+        TLS_FREE(cert->subject);\r
+        for (i = 0; i < cert->san_length; i++) {\r
+            TLS_FREE(cert->san[i]);\r
+        }\r
+        TLS_FREE(cert->san);\r
+        TLS_FREE(cert->ocsp);\r
+        TLS_FREE(cert->serial_number);\r
+        TLS_FREE(cert->entity);\r
+        TLS_FREE(cert->not_before);\r
+        TLS_FREE(cert->not_after);\r
+        TLS_FREE(cert->sign_key);\r
+        TLS_FREE(cert->priv);\r
+        TLS_FREE(cert->der_bytes);\r
+        TLS_FREE(cert->bytes);\r
+        TLS_FREE(cert->fingerprint);\r
+        TLS_FREE(cert);\r
+    }\r
+}\r
+\r
+struct TLSPacket *tls_create_packet(struct TLSContext *context, unsigned char type, unsigned short version, int payload_size_hint) {\r
+    struct TLSPacket *packet = (struct TLSPacket *)TLS_MALLOC(sizeof(struct TLSPacket));\r
+    if (!packet)\r
+        return NULL;\r
+    packet->broken = 0;\r
+    if (payload_size_hint > 0)\r
+        packet->size = payload_size_hint + 10;\r
+    else\r
+        packet->size = __TLS_BLOB_INCREMENT;\r
+    packet->buf = (unsigned char *)TLS_MALLOC(packet->size);\r
+    packet->context = context;\r
+    if (!packet->buf) {\r
+        TLS_FREE(packet);\r
+        return NULL;\r
+    }\r
+    if ((context) && (context->dtls))\r
+        packet->len = 13;\r
+    else\r
+        packet->len = 5;\r
+    packet->buf[0] = type;\r
+    *(unsigned short *)&packet->buf[1] = htons(version);\r
+    return packet;\r
+}\r
+\r
+void tls_destroy_packet(struct TLSPacket *packet) {\r
+    if (packet) {\r
+        if (packet->buf)\r
+            TLS_FREE(packet->buf);\r
+        TLS_FREE(packet);\r
+    }\r
+}\r
+\r
+int __private_tls_crypto_create(struct TLSContext *context, int key_length, int iv_length, unsigned char *localkey, unsigned char *localiv, unsigned char *remotekey, unsigned char *remoteiv) {\r
+    if (context->crypto.created) {\r
+        if (context->crypto.created == 1) {\r
+            cbc_done(&context->crypto.ctx_remote.aes_remote);\r
+            cbc_done(&context->crypto.ctx_local.aes_local);\r
+        } else {\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+            if (context->crypto.created == 2) {\r
+#endif\r
+            unsigned char dummy_buffer[32];\r
+            unsigned long tag_len = 0;\r
+            gcm_done(&context->crypto.ctx_remote.aes_gcm_remote, dummy_buffer, &tag_len);\r
+            gcm_done(&context->crypto.ctx_local.aes_gcm_local, dummy_buffer, &tag_len);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+            }\r
+#endif\r
+        }\r
+        context->crypto.created = 0;\r
+    }\r
+    tls_init();\r
+    int is_aead = __private_tls_is_aead(context);\r
+    int cipherID = find_cipher("aes");\r
+    DEBUG_PRINT("Using cipher ID: %x\n", (int)context->cipher);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+    if (is_aead == 2) {\r
+        unsigned int counter = 1;\r
+\r
+        chacha_keysetup(&context->crypto.ctx_local.chacha_local, localkey, key_length * 8);\r
+        chacha_ivsetup_96bitnonce(&context->crypto.ctx_local.chacha_local, localiv, (unsigned char *)&counter);\r
+\r
+        chacha_keysetup(&context->crypto.ctx_remote.chacha_remote, remotekey, key_length * 8);\r
+        chacha_ivsetup_96bitnonce(&context->crypto.ctx_remote.chacha_remote, remoteiv, (unsigned char *)&counter);\r
+\r
+        context->crypto.created = 3;\r
+    } else\r
+#endif\r
+    if (is_aead) {\r
+        int res1 = gcm_init(&context->crypto.ctx_local.aes_gcm_local, cipherID, localkey, key_length);\r
+        int res2 = gcm_init(&context->crypto.ctx_remote.aes_gcm_remote, cipherID, remotekey, key_length);\r
+        \r
+        if ((res1) || (res2))\r
+            return TLS_GENERIC_ERROR;\r
+        context->crypto.created = 2;\r
+    } else {\r
+        int res1 = cbc_start(cipherID, localiv, localkey, key_length, 0, &context->crypto.ctx_local.aes_local);\r
+        int res2 = cbc_start(cipherID, remoteiv, remotekey, key_length, 0, &context->crypto.ctx_remote.aes_remote);\r
+        \r
+        if ((res1) || (res2))\r
+            return TLS_GENERIC_ERROR;\r
+        context->crypto.created = 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int __private_tls_crypto_encrypt(struct TLSContext *context, unsigned char *buf, unsigned char *ct, unsigned int len) {\r
+    if (context->crypto.created == 1)\r
+        return cbc_encrypt(buf, ct, len, &context->crypto.ctx_local.aes_local);\r
+\r
+    memset(ct, 0, len);\r
+    return TLS_GENERIC_ERROR;\r
+}\r
+\r
+int __private_tls_crypto_decrypt(struct TLSContext *context, unsigned char *buf, unsigned char *pt, unsigned int len) {\r
+    if (context->crypto.created == 1)\r
+        return cbc_decrypt(buf, pt, len, &context->crypto.ctx_remote.aes_remote);\r
+    \r
+    memset(pt, 0, len);\r
+    return TLS_GENERIC_ERROR;\r
+}\r
+\r
+void __private_tls_crypto_done(struct TLSContext *context) {\r
+    unsigned char dummy_buffer[32];\r
+    unsigned long tag_len = 0;\r
+    switch (context->crypto.created) {\r
+        case 1:\r
+            cbc_done(&context->crypto.ctx_remote.aes_remote);\r
+            cbc_done(&context->crypto.ctx_local.aes_local);\r
+            break;\r
+        case 2:\r
+            gcm_done(&context->crypto.ctx_remote.aes_gcm_remote, dummy_buffer, &tag_len);\r
+            gcm_done(&context->crypto.ctx_local.aes_gcm_local, dummy_buffer, &tag_len);\r
+            break;\r
+    }\r
+    context->crypto.created = 0;\r
+}\r
+\r
+void tls_packet_update(struct TLSPacket *packet) {\r
+    if ((packet) && (!packet->broken)) {\r
+        unsigned int header_size = 5;\r
+        if ((packet->context) && (packet->context->dtls)) {\r
+            header_size = 13;\r
+            *(unsigned short *)&packet->buf[3] = htons(packet->context->dtls_epoch_local);\r
+            uint64_t sequence_number = packet->context->local_sequence_number;\r
+            packet->buf[5] = sequence_number / 0x10000000000LL;\r
+            sequence_number %= 0x10000000000LL;\r
+            packet->buf[6] = sequence_number / 0x100000000LL;\r
+            sequence_number %= 0x100000000LL;\r
+            packet->buf[7] = sequence_number / 0x1000000;\r
+            sequence_number %= 0x1000000;\r
+            packet->buf[8] = sequence_number / 0x10000;\r
+            sequence_number %= 0x10000;\r
+            packet->buf[9] = sequence_number / 0x100;\r
+            sequence_number %= 0x100;\r
+            packet->buf[10] = sequence_number;\r
+\r
+            *(unsigned short *)&packet->buf[11] = htons(packet->len - header_size);\r
+        } else\r
+            *(unsigned short *)&packet->buf[3] = htons(packet->len - header_size);\r
+        if (packet->context) {\r
+            if (packet->buf[0] != TLS_CHANGE_CIPHER)  {\r
+                if ((packet->buf[0] == TLS_HANDSHAKE) && (packet->len > header_size)) {\r
+                    unsigned char handshake_type = packet->buf[header_size];\r
+                    if ((handshake_type != 0x00) && (handshake_type != 0x03))\r
+                        __private_tls_update_hash(packet->context, packet->buf + header_size, packet->len - header_size);\r
+                }\r
+                \r
+                if ((packet->context->cipher_spec_set) && (packet->context->crypto.created)) {\r
+                    int block_size = __TLS_AES_BLOCK_SIZE;\r
+                    int mac_size = 0;\r
+                    unsigned int length = 0;\r
+                    unsigned char padding = 0;\r
+                    unsigned int pt_length = packet->len - header_size;\r
+                    \r
+                    if (packet->context->crypto.created == 1) {\r
+                        mac_size = __private_tls_mac_length(packet->context);\r
+#ifdef TLS_LEGACY_SUPPORT\r
+                        if (packet->context->version == TLS_V10)\r
+                            length = packet->len - header_size + mac_size;\r
+                        else\r
+#endif\r
+                            length = packet->len - header_size + __TLS_AES_IV_LENGTH + mac_size;\r
+                        padding = block_size - length % block_size;\r
+                        length += padding;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                    } else\r
+                    if (packet->context->crypto.created == 3) {\r
+                        mac_size = POLY1305_TAGLEN;\r
+                        length = packet->len - header_size + mac_size;\r
+#endif\r
+                    } else {\r
+                        mac_size = __TLS_GCM_TAG_LEN;\r
+                        length = packet->len - header_size + 8 + mac_size;\r
+                    }\r
+                    \r
+                    \r
+                    if (packet->context->crypto.created == 1) {\r
+                        unsigned char *buf = (unsigned char *)TLS_MALLOC(length);\r
+                        if (buf) {\r
+                            unsigned char *ct = (unsigned char *)TLS_MALLOC(length + header_size);\r
+                            if (ct) {\r
+                                unsigned int buf_pos = 0;\r
+                                memcpy(ct, packet->buf, header_size - 2);\r
+                                *(unsigned short *)&ct[header_size - 2] = htons(length);\r
+#ifdef TLS_LEGACY_SUPPORT\r
+                                if (packet->context->version != TLS_V10)\r
+#endif\r
+                                {\r
+                                    tls_random(buf, __TLS_AES_IV_LENGTH);\r
+                                    buf_pos += __TLS_AES_IV_LENGTH;\r
+                                }\r
+                                // copy payload\r
+                                memcpy(buf + buf_pos, packet->buf + header_size, packet->len - header_size);\r
+                                buf_pos += packet->len - header_size;\r
+                                if (packet->context->dtls) {\r
+                                    unsigned char temp_buf[5];\r
+                                    memcpy(temp_buf, packet->buf, 3);\r
+                                    *(unsigned short *)&temp_buf[3] = *(unsigned short *)&packet->buf[header_size - 2];\r
+                                    uint64_t dtls_sequence_number = ntohll(*(uint64_t *)&packet->buf[3]);\r
+                                    __private_tls_hmac_message(1, packet->context, temp_buf, 5, packet->buf + header_size, packet->len  - header_size, buf + buf_pos, mac_size, dtls_sequence_number);\r
+                                } else\r
+                                    __private_tls_hmac_message(1, packet->context, packet->buf, packet->len, NULL, 0, buf + buf_pos, mac_size, 0);\r
+                                buf_pos += mac_size;\r
+                                \r
+                                memset(buf + buf_pos, padding - 1, padding);\r
+                                buf_pos += padding;\r
+                                \r
+                                //DEBUG_DUMP_HEX_LABEL("PT BUFFER", buf, length);\r
+                                __private_tls_crypto_encrypt(packet->context, buf, ct + header_size, length);\r
+                                TLS_FREE(packet->buf);\r
+                                packet->buf = ct;\r
+                                packet->len = length + header_size;\r
+                                packet->size = packet->len;\r
+                            } else {\r
+                                // invalidate packet\r
+                                memset(packet->buf, 0, packet->len);\r
+                            }\r
+                            TLS_FREE(buf);\r
+                        } else {\r
+                            // invalidate packet\r
+                            memset(packet->buf, 0, packet->len);\r
+                        }\r
+                    } else\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                    if (packet->context->crypto.created >= 2) {\r
+#else\r
+                    if (packet->context->crypto.created == 2) {\r
+#endif\r
+                        int ct_size = length + header_size + 12 + __TLS_MAX_TAG_LEN;\r
+                        unsigned char *ct = (unsigned char *)TLS_MALLOC(ct_size);\r
+                        if (ct) {\r
+                            memset(ct, 0, ct_size);\r
+                            // AEAD\r
+                            // sequence number (8 bytes)\r
+                            // content type (1 byte)\r
+                            // version (2 bytes)\r
+                            // length (2 bytes)\r
+                            unsigned char aad[13];\r
+                            if (packet->context->dtls)\r
+                                *((uint64_t *)aad) = *(uint64_t *)&packet->buf[3];\r
+                            else\r
+                                *((uint64_t *)aad) = htonll(packet->context->local_sequence_number);\r
+                            aad[8] = packet->buf[0];\r
+                            aad[9] = packet->buf[1];\r
+                            aad[10] = packet->buf[2];\r
+                            *((unsigned short *)&aad[11]) = htons(packet->len - header_size);\r
+\r
+                            int ct_pos = header_size;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                            if (packet->context->crypto.created == 3) {\r
+                                unsigned int counter = 1;\r
+                                unsigned char poly1305_key[POLY1305_KEYLEN];\r
+                                chacha_ivupdate(&packet->context->crypto.ctx_local.chacha_local, packet->context->crypto.ctx_local_mac.local_aead_iv, aad, (u8 *)&counter);\r
+                                chacha20_poly1305_key(&packet->context->crypto.ctx_local.chacha_local, poly1305_key);\r
+                                ct_pos += chacha20_poly1305_aead(&packet->context->crypto.ctx_local.chacha_local, packet->buf + header_size, pt_length, aad, sizeof(aad), poly1305_key, ct + ct_pos);\r
+                            } else {\r
+#endif\r
+                                unsigned char iv[12];\r
+                                memcpy(iv, packet->context->crypto.ctx_local_mac.local_aead_iv, __TLS_AES_GCM_IV_LENGTH);\r
+                                tls_random(iv + __TLS_AES_GCM_IV_LENGTH, 8);\r
+                                memcpy(ct + ct_pos, iv + __TLS_AES_GCM_IV_LENGTH, 8);\r
+                                ct_pos += 8;\r
+\r
+                                gcm_reset(&packet->context->crypto.ctx_local.aes_gcm_local);\r
+                                gcm_add_iv(&packet->context->crypto.ctx_local.aes_gcm_local, iv, 12);\r
+                                gcm_add_aad(&packet->context->crypto.ctx_local.aes_gcm_local, aad, sizeof(aad));\r
+                                \r
+                                gcm_process(&packet->context->crypto.ctx_local.aes_gcm_local, packet->buf + header_size, pt_length, ct + ct_pos, GCM_ENCRYPT);\r
+                                ct_pos += pt_length;\r
+                                \r
+                                unsigned long taglen = __TLS_GCM_TAG_LEN;\r
+                                gcm_done(&packet->context->crypto.ctx_local.aes_gcm_local, ct + ct_pos, &taglen);\r
+                                ct_pos += taglen;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                            }\r
+#endif\r
+                            \r
+                            memcpy(ct, packet->buf, header_size - 2);\r
+                            *(unsigned short *)&ct[header_size - 2] = htons(ct_pos - header_size);\r
+                            TLS_FREE(packet->buf);\r
+                            packet->buf = ct;\r
+                            packet->len = ct_pos;\r
+                            packet->size = ct_pos;\r
+                        } else {\r
+                            // invalidate packet\r
+                            memset(packet->buf, 0, packet->len);\r
+                        }\r
+                    } else {\r
+                        // invalidate packet (never reached)\r
+                        memset(packet->buf, 0, packet->len);\r
+                    }\r
+                }\r
+            } else\r
+                packet->context->dtls_epoch_local++;\r
+            packet->context->local_sequence_number++;\r
+        }\r
+    }\r
+}\r
+\r
+int tls_packet_append(struct TLSPacket *packet, const unsigned char *buf, unsigned int len) {\r
+    if ((!packet) || (packet->broken))\r
+        return -1;\r
+    \r
+    if (!len)\r
+        return 0;\r
+    \r
+    unsigned int new_len = packet->len + len;\r
+    \r
+    if (new_len > packet->size) {\r
+        packet->size = (new_len / __TLS_BLOB_INCREMENT + 1) * __TLS_BLOB_INCREMENT;\r
+        packet->buf = (unsigned char *)TLS_REALLOC(packet->buf, packet->size);\r
+        if (!packet->buf) {\r
+            packet->size = 0;\r
+            packet->len = 0;\r
+            packet->broken = 1;\r
+            return -1;\r
+        }\r
+    }\r
+    memcpy(packet->buf + packet->len, buf, len);\r
+    packet->len = new_len;\r
+    return new_len;\r
+}\r
+\r
+int tls_packet_uint8(struct TLSPacket *packet, unsigned char i) {\r
+    return tls_packet_append(packet, &i, 1);\r
+}\r
+\r
+int tls_packet_uint16(struct TLSPacket *packet, unsigned short i) {\r
+    unsigned short ni = htons(i);\r
+    return tls_packet_append(packet, (unsigned char *)&ni, 2);\r
+}\r
+\r
+int tls_packet_uint32(struct TLSPacket *packet, unsigned int i) {\r
+    unsigned int ni = htonl(i);\r
+    return tls_packet_append(packet, (unsigned char *)&ni, 4);\r
+}\r
+\r
+int tls_packet_uint24(struct TLSPacket *packet, unsigned int i) {\r
+    unsigned char buf[3];\r
+    buf[0] = i / 0x10000;\r
+    i %= 0x10000;\r
+    buf[1] = i / 0x100;\r
+    i %= 0x100;\r
+    buf[2] = i;\r
+    \r
+    return tls_packet_append(packet, buf, 3);\r
+}\r
+\r
+int tls_random(unsigned char *key, int len) {\r
+#ifdef __APPLE__\r
+    for (int i = 0; i < len; i++) {\r
+        unsigned int v = arc4random() % 0x100;\r
+        key[i] = (char)v;\r
+    }\r
+    return 1;\r
+#else\r
+#ifdef _WIN32\r
+    HCRYPTPROV hProvider = 0;\r
+    if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {\r
+        if (CryptGenRandom(hProvider, len, (BYTE *)key)) {\r
+            CryptReleaseContext(hProvider, 0);\r
+            return 1;\r
+        }\r
+        CryptReleaseContext(hProvider, 0);\r
+    }\r
+#else\r
+    FILE *fp = fopen("/dev/urandom", "r");\r
+    if (fp) {\r
+        int key_len = fread(key, 1, len, fp);\r
+        fclose(fp);\r
+        if (key_len == len)\r
+            return 1;\r
+    }\r
+#endif\r
+#endif\r
+    return 0;\r
+}\r
+\r
+TLSHash *__private_tls_ensure_hash(struct TLSContext *context) {\r
+    TLSHash *hash = context->handshake_hash;\r
+    if (!hash) {\r
+        hash = (TLSHash *)TLS_MALLOC(sizeof(TLSHash));\r
+        if (hash)\r
+            memset(hash, 0, sizeof(TLSHash));\r
+        context->handshake_hash = hash;\r
+    }\r
+    return hash;\r
+}\r
+\r
+void __private_tls_destroy_hash(struct TLSContext *context) {\r
+    if (context) {\r
+        TLS_FREE(context->handshake_hash);\r
+        context->handshake_hash = NULL;\r
+    }\r
+}\r
+\r
+void __private_tls_create_hash(struct TLSContext *context) {\r
+    if (!context)\r
+        return;\r
+    \r
+    TLSHash *hash = __private_tls_ensure_hash(context);\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        int hash_size = __private_tls_mac_length(context);\r
+        if (hash->created) {\r
+            unsigned char temp[__TLS_MAX_SHA_SIZE];\r
+            if (hash_size == __TLS_SHA384_MAC_SIZE)\r
+                sha384_done(&hash->hash, temp);\r
+            else\r
+                sha256_done(&hash->hash, temp);\r
+        }\r
+        if (hash_size == __TLS_SHA384_MAC_SIZE)\r
+            sha384_init(&hash->hash);\r
+        else\r
+            sha256_init(&hash->hash);\r
+        hash->created = 1;\r
+    } else {\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        // TLS_V11\r
+        if (hash->created) {\r
+            unsigned char temp[__TLS_V11_HASH_SIZE];\r
+            md5_done(&hash->hash, temp);\r
+            sha1_done(&hash->hash2, temp);\r
+        }\r
+        md5_init(&hash->hash);\r
+        sha1_init(&hash->hash2);\r
+        hash->created = 1;\r
+#endif\r
+    }\r
+}\r
+\r
+int __private_tls_update_hash(struct TLSContext *context, const unsigned char *in, unsigned int len) {\r
+    if (!context)\r
+        return 0;\r
+    TLSHash *hash = __private_tls_ensure_hash(context);\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        if (!hash->created) {\r
+            __private_tls_create_hash(context);\r
+#ifdef TLS_LEGACY_SUPPORT\r
+            // cache first hello in case of protocol downgrade\r
+            if ((!context->is_server) && (!context->cached_handshake) && (!context->request_client_certificate) && (len)) {\r
+                context->cached_handshake = (unsigned char *)TLS_MALLOC(len);\r
+                if (context->cached_handshake) {\r
+                    memcpy(context->cached_handshake, in, len);\r
+                    context->cached_handshake_len = len;\r
+                }\r
+            }\r
+#endif\r
+        }\r
+        int hash_size = __private_tls_mac_length(context);\r
+        if (hash_size == __TLS_SHA384_MAC_SIZE) {\r
+            sha384_process(&hash->hash, in, len);\r
+        } else {\r
+            sha256_process(&hash->hash, in, len);\r
+            hash_size = __TLS_SHA256_MAC_SIZE;\r
+        }\r
+    } else {\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        if (!hash->created)\r
+            __private_tls_create_hash(context);\r
+        md5_process(&hash->hash, in, len);\r
+        sha1_process(&hash->hash2, in, len);\r
+#endif\r
+    }\r
+    if ((context->request_client_certificate) && (len)) {\r
+        // cache all messages for verification\r
+        int new_len = context->cached_handshake_len + len;\r
+        context->cached_handshake = (unsigned char *)TLS_REALLOC(context->cached_handshake, new_len);\r
+        if (context->cached_handshake) {\r
+            memcpy(context->cached_handshake + context->cached_handshake_len, in, len);\r
+            context->cached_handshake_len = new_len;\r
+        } else\r
+            context->cached_handshake_len = 0;\r
+    }\r
+    return 0;\r
+}\r
+\r
+#ifdef TLS_LEGACY_SUPPORT\r
+int __private_tls_change_hash_type(struct TLSContext *context) {\r
+    if (!context)\r
+        return 0;\r
+    TLSHash *hash = __private_tls_ensure_hash(context);\r
+    if ((hash) && (hash->created) && (context->cached_handshake) && (context->cached_handshake_len)) {\r
+        __private_tls_destroy_hash(context);\r
+        int res = __private_tls_update_hash(context, context->cached_handshake, context->cached_handshake_len);\r
+        TLS_FREE(context->cached_handshake);\r
+        context->cached_handshake = NULL;\r
+        context->cached_handshake_len = 0;\r
+        return res;\r
+    }\r
+    return 0;\r
+}\r
+#endif\r
+\r
+int __private_tls_done_hash(struct TLSContext *context, unsigned char *hout) {\r
+    if (!context)\r
+        return 0;\r
+    \r
+    TLSHash *hash = __private_tls_ensure_hash(context);\r
+    if (!hash->created)\r
+        return 0;\r
+    \r
+    int hash_size = 0;\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        unsigned char temp[__TLS_MAX_SHA_SIZE];\r
+        if (!hout)\r
+            hout = temp;\r
+        //__TLS_HASH_DONE(&hash->hash, hout);\r
+        hash_size = __private_tls_mac_length(context);\r
+        if (hash_size == __TLS_SHA384_MAC_SIZE)\r
+            sha384_done(&hash->hash, hout);\r
+        else {\r
+            sha256_done(&hash->hash, hout);\r
+            hash_size = __TLS_SHA256_MAC_SIZE;\r
+        }\r
+    } else {\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        // TLS_V11\r
+        unsigned char temp[__TLS_V11_HASH_SIZE];\r
+        if (!hout)\r
+            hout = temp;\r
+        md5_done(&hash->hash, hout);\r
+        sha1_done(&hash->hash2, hout + 16);\r
+        hash_size = __TLS_V11_HASH_SIZE;\r
+#endif\r
+    }\r
+    hash->created = 0;\r
+    if (context->cached_handshake) {\r
+        // not needed anymore\r
+        TLS_FREE(context->cached_handshake);\r
+        context->cached_handshake = NULL;\r
+        context->cached_handshake_len = 0;\r
+    }\r
+    return hash_size;\r
+}\r
+\r
+int __private_tls_get_hash(struct TLSContext *context, unsigned char *hout) {\r
+    if (!context)\r
+        return 0;\r
+    \r
+    TLSHash *hash = __private_tls_ensure_hash(context);\r
+    if (!hash->created)\r
+        return 0;\r
+    \r
+    int hash_size = 0;\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        hash_size = __private_tls_mac_length(context);\r
+        hash_state prec;\r
+        memcpy(&prec, &hash->hash, sizeof(hash_state));\r
+        if (hash_size == __TLS_SHA384_MAC_SIZE)\r
+            sha384_done(&hash->hash, hout);\r
+        else {\r
+            hash_size = __TLS_SHA256_MAC_SIZE;\r
+            sha256_done(&hash->hash, hout);\r
+        }\r
+        memcpy(&hash->hash, &prec, sizeof(hash_state));\r
+    } else {\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        // TLS_V11\r
+        hash_state prec;\r
+        \r
+        memcpy(&prec, &hash->hash, sizeof(hash_state));\r
+        md5_done(&hash->hash, hout);\r
+        memcpy(&hash->hash, &prec, sizeof(hash_state));\r
+        \r
+        memcpy(&prec, &hash->hash2, sizeof(hash_state));\r
+        sha1_done(&hash->hash2, hout + 16);\r
+        memcpy(&hash->hash2, &prec, sizeof(hash_state));\r
+        \r
+        hash_size = __TLS_V11_HASH_SIZE;\r
+#endif\r
+    }\r
+    return hash_size;\r
+}\r
+\r
+int __private_tls_write_packet(struct TLSPacket *packet) {\r
+    if (!packet)\r
+        return -1;\r
+    struct TLSContext *context = packet->context;\r
+    if (!context)\r
+        return -1;\r
+    \r
+    if (context->tls_buffer) {\r
+        int len = context->tls_buffer_len + packet->len;\r
+        context->tls_buffer = (unsigned char *)TLS_REALLOC(context->tls_buffer, len);\r
+        if (!context->tls_buffer) {\r
+            context->tls_buffer_len = 0;\r
+            return -1;\r
+        }\r
+        memcpy(context->tls_buffer + context->tls_buffer_len, packet->buf, packet->len);\r
+        context->tls_buffer_len = len;\r
+        int written = packet->len;\r
+        tls_destroy_packet(packet);\r
+        return written;\r
+    }\r
+    context->tls_buffer_len = packet->len;\r
+    context->tls_buffer = packet->buf;\r
+    packet->buf = NULL;\r
+    packet->len = 0;\r
+    packet->size = 0;\r
+    tls_destroy_packet(packet);\r
+    return context->tls_buffer_len;\r
+}\r
+\r
+int __private_tls_write_app_data(struct TLSContext *context, const unsigned char *buf, unsigned int buf_len) {\r
+    if (!context)\r
+        return -1;\r
+    if ((!buf) || (!buf_len))\r
+        return 0;\r
+    \r
+    int len = context->application_buffer_len + buf_len;\r
+    context->application_buffer = (unsigned char *)TLS_REALLOC(context->application_buffer, len);\r
+    if (!context->application_buffer) {\r
+        context->application_buffer_len = 0;\r
+        return -1;\r
+    }\r
+    memcpy(context->application_buffer + context->application_buffer_len, buf, buf_len);\r
+    context->application_buffer_len = len;\r
+    return buf_len;\r
+}\r
+\r
+const unsigned char *tls_get_write_buffer(struct TLSContext *context, unsigned int *outlen) {\r
+    if (!outlen)\r
+        return NULL;\r
+    if (!context) {\r
+        *outlen = 0;\r
+        return NULL;\r
+    }\r
+    // check if any error\r
+    if (context->sleep_until) {\r
+        if (context->sleep_until < time(NULL)) {\r
+            *outlen = 0;\r
+            return NULL;\r
+        }\r
+        context->sleep_until = 0;\r
+    }\r
+    *outlen = context->tls_buffer_len;\r
+    return context->tls_buffer;\r
+}\r
+\r
+const unsigned char *tls_get_message(struct TLSContext *context, unsigned int *outlen, int offset) {\r
+    if (!outlen)\r
+        return NULL;\r
+    if ((!context) || (!context->tls_buffer)) {\r
+        *outlen = 0;\r
+        return NULL;\r
+    }\r
+\r
+    if (offset >= context->tls_buffer_len) {\r
+        *outlen = 0;\r
+        return NULL;\r
+    }\r
+    // check if any error\r
+    if (context->sleep_until) {\r
+        if (context->sleep_until < time(NULL)) {\r
+            *outlen = 0;\r
+            return NULL;\r
+        }\r
+        context->sleep_until = 0;\r
+    }\r
+    unsigned char *tls_buffer = &context->tls_buffer[offset];\r
+    unsigned int tls_buffer_len = context->tls_buffer_len - offset;\r
+    int len = 0;\r
+    if (context->dtls) {\r
+        if (tls_buffer_len < 13) {\r
+            *outlen = 0;\r
+            return NULL;\r
+        }\r
+\r
+        len = ntohs(*(unsigned short *)&tls_buffer[11]) + 13;\r
+    } else {\r
+        if (tls_buffer_len < 5) {\r
+            *outlen = 0;\r
+            return NULL;\r
+        }\r
+        len = ntohs(*(unsigned short *)&tls_buffer[3]) + 5;\r
+    }\r
+    if (len > tls_buffer_len) {\r
+        *outlen = 0;\r
+        return NULL;\r
+    }\r
+\r
+    *outlen = len;\r
+    return tls_buffer;\r
+}\r
+\r
+void tls_buffer_clear(struct TLSContext *context) {\r
+    if ((context) && (context->tls_buffer)) {\r
+        TLS_FREE(context->tls_buffer);\r
+        context->tls_buffer = NULL;\r
+        context->tls_buffer_len = 0;\r
+    }\r
+}\r
+\r
+int tls_established(struct TLSContext *context) {\r
+    if (context) {\r
+        if (context->critical_error)\r
+            return -1;\r
+        \r
+        if (context->connection_status == 0xFF)\r
+            return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+void tls_read_clear(struct TLSContext *context) {\r
+    if ((context) && (context->application_buffer)) {\r
+        TLS_FREE(context->application_buffer);\r
+        context->application_buffer = NULL;\r
+        context->application_buffer_len = 0;\r
+    }\r
+}\r
+\r
+int tls_read(struct TLSContext *context, unsigned char *buf, unsigned int size) {\r
+    if (!context)\r
+        return -1;\r
+    if ((context->application_buffer) && (context->application_buffer_len)) {\r
+        if (context->application_buffer_len < size)\r
+            size = context->application_buffer_len;\r
+        \r
+        memcpy(buf, context->application_buffer, size);\r
+        if (context->application_buffer_len == size) {\r
+            TLS_FREE(context->application_buffer);\r
+            context->application_buffer = NULL;\r
+            context->application_buffer_len = 0;\r
+            return size;\r
+        }\r
+        context->application_buffer_len -= size;\r
+        memmove(context->application_buffer, context->application_buffer + size, context->application_buffer_len);\r
+        return size;\r
+    }\r
+    return 0;\r
+}\r
+\r
+struct TLSContext *tls_create_context(unsigned char is_server, unsigned short version) {\r
+    struct TLSContext *context = (struct TLSContext *)TLS_MALLOC(sizeof(struct TLSContext));\r
+    if (context) {\r
+        memset(context, 0, sizeof(struct TLSContext));\r
+        context->is_server = is_server;\r
+        if ((version == DTLS_V12) || (version == DTLS_V10))\r
+            context->dtls = 1;\r
+        context->version = version;\r
+    }\r
+    return context;\r
+}\r
+\r
+#ifdef TLS_FORWARD_SECRECY\r
+const struct ECCCurveParameters *tls_set_curve(struct TLSContext *context, const struct ECCCurveParameters *curve) {\r
+    if (!context->is_server)\r
+        return NULL;\r
+    const struct ECCCurveParameters *old_curve = context->curve;\r
+    context->curve = curve;\r
+    return old_curve;\r
+}\r
+#endif\r
+\r
+struct TLSContext *tls_accept(struct TLSContext *context) {\r
+    if ((!context) || (!context->is_server))\r
+        return NULL;\r
+    \r
+    struct TLSContext *child = (struct TLSContext *)TLS_MALLOC(sizeof(struct TLSContext));\r
+    if (child) {\r
+        memset(child, 0, sizeof(struct TLSContext));\r
+        child->is_server = 1;\r
+        child->is_child = 1;\r
+        child->dtls = context->dtls;\r
+        child->version = context->version;\r
+        child->certificates = context->certificates;\r
+        child->certificates_count = context->certificates_count;\r
+        child->private_key = context->private_key;\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        child->ec_private_key = context->ec_private_key;\r
+#endif\r
+        child->exportable = context->exportable;\r
+        child->root_certificates = context->root_certificates;\r
+        child->root_count = context->root_count;\r
+#ifdef TLS_FORWARD_SECRECY\r
+        child->default_dhe_p = context->default_dhe_p;\r
+        child->default_dhe_g = context->default_dhe_g;\r
+        child->curve = context->curve;\r
+#endif\r
+        child->alpn = context->alpn;\r
+        child->alpn_count = context->alpn_count;\r
+    }\r
+    return child;\r
+}\r
+\r
+#ifdef TLS_FORWARD_SECRECY\r
+void __private_tls_dhe_free(struct TLSContext *context) {\r
+    if (context->dhe) {\r
+        __private_tls_dh_clear_key(context->dhe);\r
+        TLS_FREE(context->dhe);\r
+        context->dhe = NULL;\r
+    }\r
+}\r
+\r
+void __private_tls_dhe_create(struct TLSContext *context) {\r
+    __private_tls_dhe_free(context);\r
+    context->dhe = (DHKey *)TLS_MALLOC(sizeof(DHKey));\r
+    if (context->dhe)\r
+        memset(context->dhe, 0, sizeof(DHKey));\r
+}\r
+\r
+void __private_tls_ecc_dhe_free(struct TLSContext *context) {\r
+    if (context->ecc_dhe) {\r
+        ecc_free(context->ecc_dhe);\r
+        TLS_FREE(context->ecc_dhe);\r
+        context->ecc_dhe = NULL;\r
+    }\r
+}\r
+\r
+void __private_tls_ecc_dhe_create(struct TLSContext *context) {\r
+    __private_tls_ecc_dhe_free(context);\r
+    context->ecc_dhe = (ecc_key *)TLS_MALLOC(sizeof(ecc_key));\r
+    memset(context->ecc_dhe, 0, sizeof(ecc_key));\r
+}\r
+\r
+int tls_set_default_dhe_pg(struct TLSContext *context, const char *p_hex_str, const char *g_hex_str) {\r
+    if ((!context) || (context->is_child) || (!context->is_server) || (!p_hex_str) || (!g_hex_str))\r
+        return 0;\r
+    \r
+    TLS_FREE(context->default_dhe_p);\r
+    TLS_FREE(context->default_dhe_g);\r
+    \r
+    context->default_dhe_p = NULL;\r
+    context->default_dhe_g = NULL;\r
+    \r
+    int p_len = strlen(p_hex_str);\r
+    int g_len = strlen(g_hex_str);\r
+    if ((p_len <= 0) || (g_len <= 0))\r
+        return 0;\r
+    context->default_dhe_p = (char *)TLS_MALLOC(p_len + 1);\r
+    if (!context->default_dhe_p)\r
+        return 0;\r
+    context->default_dhe_g = (char *)TLS_MALLOC(g_len + 1);\r
+    if (!context->default_dhe_g)\r
+        return 0;\r
+    \r
+    memcpy(context->default_dhe_p, p_hex_str, p_len);\r
+    context->default_dhe_p[p_len] = 0;\r
+    \r
+    memcpy(context->default_dhe_g, g_hex_str, g_len);\r
+    context->default_dhe_g[g_len] = 0;\r
+    return 1;\r
+}\r
+#endif\r
+\r
+const char *tls_alpn(struct TLSContext *context) {\r
+    if (!context)\r
+        return NULL;\r
+    return context->negotiated_alpn;\r
+}\r
+\r
+int tls_add_alpn(struct TLSContext *context, const char *alpn) {\r
+    if ((!context) || (!alpn) || (!alpn[0]) || ((context->is_server) && (context->is_child)))\r
+        return TLS_GENERIC_ERROR;\r
+    int len = strlen(alpn);\r
+    if (tls_alpn_contains(context, alpn, len))\r
+        return 0;\r
+    context->alpn = (char **)TLS_REALLOC(context->alpn, (context->alpn_count + 1) * sizeof(char *));\r
+    if (!context->alpn) {\r
+        context->alpn_count = 0;\r
+        return TLS_NO_MEMORY;\r
+    }\r
+    char *alpn_ref = (char *)TLS_MALLOC(len+1);\r
+    context->alpn[context->alpn_count] = alpn_ref;\r
+    if (alpn_ref) {\r
+        memcpy(alpn_ref, alpn, len);\r
+        alpn_ref[len] = 0;\r
+        context->alpn_count++;\r
+    } else\r
+        return TLS_NO_MEMORY;\r
+    return 0;\r
+}\r
+\r
+int tls_alpn_contains(struct TLSContext *context, const char *alpn, unsigned char alpn_size) {\r
+    if ((!context) || (!alpn) || (!alpn_size))\r
+        return 0;\r
+\r
+    if (context->alpn) {\r
+        int i;\r
+        for (i = 0; i < context->alpn_count; i++) {\r
+            const char *alpn_local = context->alpn[i];\r
+            if (alpn_local) {\r
+                int len = strlen(alpn_local);\r
+                if (alpn_size == len) {\r
+                    if (!memcmp(alpn_local, alpn, alpn_size))\r
+                        return 1;\r
+                }\r
+            }\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+void tls_destroy_context(struct TLSContext *context) {\r
+    unsigned int i;\r
+    if (!context)\r
+        return;\r
+    if (!context->is_child) {\r
+        if (context->certificates) {\r
+            for (i = 0; i < context->certificates_count; i++)\r
+                tls_destroy_certificate(context->certificates[i]);\r
+        }\r
+        if (context->root_certificates) {\r
+            for (i = 0; i < context->root_count; i++)\r
+                tls_destroy_certificate(context->root_certificates[i]);\r
+        }\r
+        if (context->private_key)\r
+            tls_destroy_certificate(context->private_key);\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        if (context->ec_private_key)\r
+            tls_destroy_certificate(context->ec_private_key);\r
+#endif\r
+        TLS_FREE(context->certificates);\r
+#ifdef TLS_FORWARD_SECRECY\r
+        TLS_FREE(context->default_dhe_p);\r
+        TLS_FREE(context->default_dhe_g);\r
+#endif\r
+        if (context->alpn) {\r
+            for (i = 0; i < context->alpn_count; i++)\r
+                TLS_FREE(context->alpn[i]);\r
+            TLS_FREE(context->alpn);\r
+        }\r
+    }\r
+    if (context->client_certificates) {\r
+        for (i = 0; i < context->client_certificates_count; i++)\r
+            tls_destroy_certificate(context->client_certificates[i]);\r
+        TLS_FREE(context->client_certificates);\r
+    }\r
+    context->client_certificates = NULL;\r
+    TLS_FREE(context->master_key);\r
+    TLS_FREE(context->premaster_key);\r
+    if (context->crypto.created)\r
+        __private_tls_crypto_done(context);\r
+    TLS_FREE(context->message_buffer);\r
+    __private_tls_done_hash(context, NULL);\r
+    __private_tls_destroy_hash(context);\r
+    TLS_FREE(context->tls_buffer);\r
+    TLS_FREE(context->application_buffer);\r
+    // zero out the keys before free\r
+    if ((context->exportable_keys) && (context->exportable_size))\r
+        memset(context->exportable_keys, 0, context->exportable_size);\r
+    TLS_FREE(context->exportable_keys);\r
+    TLS_FREE(context->sni);\r
+    TLS_FREE(context->dtls_cookie);\r
+    TLS_FREE(context->cached_handshake);\r
+#ifdef TLS_FORWARD_SECRECY\r
+    __private_tls_dhe_free(context);\r
+    __private_tls_ecc_dhe_free(context);\r
+#endif\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+    TLS_FREE(context->verify_data);\r
+#endif\r
+    TLS_FREE(context->negotiated_alpn);\r
+    TLS_FREE(context);\r
+}\r
+\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+void __private_tls_reset_context(struct TLSContext *context) {\r
+    unsigned int i;\r
+    if (!context)\r
+        return;\r
+    if (!context->is_child) {\r
+        if (context->certificates) {\r
+            for (i = 0; i < context->certificates_count; i++)\r
+                tls_destroy_certificate(context->certificates[i]);\r
+        }\r
+        context->certificates = NULL;\r
+        if (context->private_key) {\r
+            tls_destroy_certificate(context->private_key);\r
+            context->private_key = NULL;\r
+        }\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        if (context->ec_private_key) {\r
+            tls_destroy_certificate(context->ec_private_key);\r
+            context->ec_private_key = NULL;\r
+        }\r
+#endif\r
+        TLS_FREE(context->certificates);\r
+        context->certificates = NULL;\r
+#ifdef TLS_FORWARD_SECRECY\r
+        TLS_FREE(context->default_dhe_p);\r
+        TLS_FREE(context->default_dhe_g);\r
+        context->default_dhe_p = NULL;\r
+        context->default_dhe_g = NULL;\r
+#endif\r
+    }\r
+    if (context->client_certificates) {\r
+        for (i = 0; i < context->client_certificates_count; i++)\r
+            tls_destroy_certificate(context->client_certificates[i]);\r
+        TLS_FREE(context->client_certificates);\r
+    }\r
+    context->client_certificates = NULL;\r
+    TLS_FREE(context->master_key);\r
+    context->master_key = NULL;\r
+    TLS_FREE(context->premaster_key);\r
+    context->premaster_key = NULL;\r
+    if (context->crypto.created)\r
+        __private_tls_crypto_done(context);\r
+    __private_tls_done_hash(context, NULL);\r
+    __private_tls_destroy_hash(context);\r
+    TLS_FREE(context->application_buffer);\r
+    context->application_buffer = NULL;\r
+    // zero out the keys before free\r
+    if ((context->exportable_keys) && (context->exportable_size))\r
+        memset(context->exportable_keys, 0, context->exportable_size);\r
+    TLS_FREE(context->exportable_keys);\r
+    context->exportable_keys =  NULL;\r
+    TLS_FREE(context->sni);\r
+    context->sni = NULL;\r
+    TLS_FREE(context->dtls_cookie);\r
+    context->dtls_cookie = NULL;\r
+    TLS_FREE(context->cached_handshake);\r
+    context->cached_handshake = NULL;\r
+    context->connection_status = 0;\r
+#ifdef TLS_FORWARD_SECRECY\r
+    __private_tls_dhe_free(context);\r
+    __private_tls_ecc_dhe_free(context);\r
+#endif\r
+}\r
+#endif\r
+\r
+int tls_cipher_supported(struct TLSContext *context, unsigned short cipher) {\r
+    if (!context)\r
+        return 0;\r
+    switch (cipher) {\r
+#ifdef TLS_FORWARD_SECRECY\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+#ifdef TLS_CLIENT_ECDSA\r
+            if ((context) && (((context->certificates) && (context->certificates_count) && (context->ec_private_key)) || (!context->is_server)))\r
+#else\r
+            if ((context) && (context->certificates) && (context->certificates_count) && (context->ec_private_key))\r
+#endif\r
+                return 1;\r
+            return 0;\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+#endif\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+#ifdef TLS_CLIENT_ECDSA\r
+                if ((context) && (((context->certificates) && (context->certificates_count) && (context->ec_private_key)) || (!context->is_server)))\r
+#else\r
+                if ((context) && (context->certificates) && (context->certificates_count) && (context->ec_private_key))\r
+#endif\r
+                    return 1;\r
+            }\r
+            return 0;\r
+#endif\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+#endif\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA:\r
+            return 1;\r
+#ifdef TLS_FORWARD_SECRECY\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+#endif\r
+#endif\r
+        case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_RSA_WITH_AES_256_GCM_SHA384:\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12))\r
+                return 1;\r
+            return 0;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int tls_cipher_is_fs(struct TLSContext *context, unsigned short cipher) {\r
+    if (!context)\r
+        return 0;\r
+    switch (cipher) {\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+#endif\r
+            if ((context) && (context->certificates) && (context->certificates_count) && (context->ec_private_key))\r
+                return 1;\r
+            return 0;\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+                if ((context) && (context->certificates) && (context->certificates_count) && (context->ec_private_key))\r
+                    return 1;\r
+            }\r
+            return 0;\r
+#endif\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+            return 1;\r
+        case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+#endif\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12))\r
+                return 1;\r
+            break;\r
+    }\r
+    return 0;\r
+}\r
+\r
+#ifdef WITH_KTLS\r
+int __private_tls_prefer_ktls(struct TLSContext *context, unsigned short cipher) {\r
+    if ((context->version != TLS_V12) && (context->version != DTLS_V12))\r
+        return 0;\r
+\r
+    switch (cipher) {\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+                if ((context) && (context->certificates) && (context->certificates_count) && (context->ec_private_key))\r
+                    return 1;\r
+            }\r
+            break;\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+            return 1;\r
+    }\r
+    return 0;\r
+}\r
+#endif\r
+\r
+int tls_choose_cipher(struct TLSContext *context, const unsigned char *buf, int buf_len, int *scsv_set) {\r
+    int i;\r
+    if (scsv_set)\r
+        *scsv_set = 0;\r
+    if (!context)\r
+        return 0;\r
+    int selected_cipher = TLS_NO_COMMON_CIPHER;\r
+#ifdef TLS_FORWARD_SECRECY\r
+#ifdef WITH_KTLS\r
+    for (i = 0; i < buf_len; i+=2) {\r
+        unsigned short cipher = ntohs(*(unsigned short *)&buf[i]);\r
+        if (__private_tls_prefer_ktls(context, cipher)) {\r
+            selected_cipher = cipher;\r
+            break;\r
+        }\r
+    }\r
+#endif\r
+    if (selected_cipher == TLS_NO_COMMON_CIPHER) {\r
+        for (i = 0; i < buf_len; i+=2) {\r
+            unsigned short cipher = ntohs(*(unsigned short *)&buf[i]);\r
+            if (tls_cipher_is_fs(context, cipher)) {\r
+                selected_cipher = cipher;\r
+                break;\r
+            }\r
+        }\r
+    }\r
+#endif\r
+    for (i = 0; i < buf_len; i+=2) {\r
+        unsigned short cipher = ntohs(*(unsigned short *)&buf[i]);\r
+        if (cipher == TLS_FALLBACK_SCSV) {\r
+            if (scsv_set)\r
+                *scsv_set = 1;\r
+            if (selected_cipher != TLS_NO_COMMON_CIPHER)\r
+                break;\r
+        }\r
+#ifndef TLS_ROBOT_MITIGATION\r
+        else\r
+        if ((selected_cipher == TLS_NO_COMMON_CIPHER) && (tls_cipher_supported(context, cipher)))\r
+            selected_cipher = cipher;\r
+#endif\r
+    }\r
+    return selected_cipher;\r
+}\r
+\r
+int tls_cipher_is_ephemeral(struct TLSContext *context) {\r
+    if (context) {\r
+        switch (context->cipher) {\r
+            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+            case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+            case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+            case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+                return 1;\r
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+            case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+            case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+            case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+            case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+                return 2;\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+const char *tls_cipher_name(struct TLSContext *context) {\r
+    if (context) {\r
+        switch (context->cipher) {\r
+            case TLS_RSA_WITH_AES_128_CBC_SHA:\r
+                return "RSA-AES128CBC-SHA";\r
+            case TLS_RSA_WITH_AES_256_CBC_SHA:\r
+                return "RSA-AES256CBC-SHA";\r
+            case TLS_RSA_WITH_AES_128_CBC_SHA256:\r
+                return "RSA-AES128CBC-SHA256";\r
+            case TLS_RSA_WITH_AES_256_CBC_SHA256:\r
+                return "RSA-AES256CBC-SHA256";\r
+            case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+                return "RSA-AES128GCM-SHA256";\r
+            case TLS_RSA_WITH_AES_256_GCM_SHA384:\r
+                return "RSA-AES256GCM-SHA384";\r
+            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:\r
+                return "DHE-RSA-AES128CBC-SHA";\r
+            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:\r
+                return "DHE-RSA-AES256CBC-SHA";\r
+            case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:\r
+                return "DHE-RSA-AES128CBC-SHA256";\r
+            case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:\r
+                return "DHE-RSA-AES256CBC-SHA256";\r
+            case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+                return "DHE-RSA-AES128GCM-SHA256";\r
+            case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:\r
+                return "DHE-RSA-AES256GCM-SHA384";\r
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:\r
+                return "ECDHE-RSA-AES128CBC-SHA";\r
+            case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:\r
+                return "ECDHE-RSA-AES256CBC-SHA";\r
+            case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:\r
+                return "ECDHE-RSA-AES128CBC-SHA256";\r
+            case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+                return "ECDHE-RSA-AES128GCM-SHA256";\r
+            case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:\r
+                return "ECDHE-RSA-AES256GCM-SHA384";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+                return "ECDHE-ECDSA-AES128CBC-SHA";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+                return "ECDHE-ECDSA-AES256CBC-SHA";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+                return "ECDHE-ECDSA-AES128CBC-SHA256";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+                return "ECDHE-ECDSA-AES256CBC-SHA384";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+                return "ECDHE-ECDSA-AES128GCM-SHA256";\r
+            case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+                return "ECDHE-ECDSA-AES256GCM-SHA384";\r
+            case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+                return "ECDHE-RSA-CHACHA20-POLY1305-SHA256";\r
+            case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+                return "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256";\r
+            case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:\r
+                return "ECDHE-DHE-CHACHA20-POLY1305-SHA256";\r
+        }\r
+    }\r
+    return "UNKNOWN";\r
+}\r
+\r
+#ifdef TLS_FORWARD_SECRECY\r
+int __private_tls_dh_export_pqY(unsigned char *pbuf, unsigned long *plen, unsigned char *gbuf, unsigned long *glen, unsigned char *Ybuf, unsigned long *Ylen, DHKey *key) {\r
+    unsigned long len;\r
+    int err;\r
+    \r
+    if ((pbuf  == NULL) || (plen  == NULL) || (gbuf == NULL) || (glen == NULL) || (Ybuf == NULL) || (Ylen == NULL) || (key == NULL))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    len = mp_unsigned_bin_size(key->y);\r
+    if (len > *Ylen)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    if ((err = mp_to_unsigned_bin(key->y, Ybuf)) != CRYPT_OK)\r
+        return err;\r
+    \r
+    *Ylen = len;\r
+    \r
+    len = mp_unsigned_bin_size(key->p);\r
+    if (len > *plen)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    if ((err = mp_to_unsigned_bin(key->p, pbuf)) != CRYPT_OK)\r
+        return err;\r
+    \r
+    *plen = len;\r
+    \r
+    len = mp_unsigned_bin_size(key->g);\r
+    if (len > *glen)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    if ((err = mp_to_unsigned_bin(key->g, gbuf)) != CRYPT_OK)\r
+        return err;\r
+    \r
+    *glen = len;\r
+    \r
+    return 0;\r
+}\r
+\r
+void __private_tls_dh_clear_key(DHKey *key) {\r
+    mp_clear_multi(key->g, key->p, key->x, key->y, NULL);\r
+    key->g = NULL;\r
+    key->p = NULL;\r
+    key->x = NULL;\r
+    key->y = NULL;\r
+}\r
+\r
+int __private_tls_dh_make_key(int keysize, DHKey *key, const char *pbuf, const char *gbuf, int pbuf_len, int gbuf_len) {\r
+    unsigned char *buf;\r
+    int err;\r
+    if (!key)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    static prng_state prng;\r
+    int wprng = find_prng("sprng");\r
+    if ((err = prng_is_valid(wprng)) != CRYPT_OK)\r
+        return err;\r
+    \r
+    buf = (unsigned char *)TLS_MALLOC(keysize);\r
+    if (!buf)\r
+        return TLS_NO_MEMORY;\r
+    \r
+    if (rng_make_prng(keysize, wprng, &prng, NULL) != CRYPT_OK) {\r
+        TLS_FREE(buf);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    if (prng_descriptor[wprng].read(buf, keysize, &prng) != (unsigned long)keysize) {\r
+        TLS_FREE(buf);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    if ((err = mp_init_multi(&key->g, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) {\r
+        TLS_FREE(buf);\r
+        \r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    if (gbuf_len <= 0) {\r
+        if ((err = mp_read_radix(key->g, gbuf, 16)) != CRYPT_OK) {\r
+            TLS_FREE(buf);\r
+            __private_tls_dh_clear_key(key);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+    } else {\r
+        if ((err = mp_read_unsigned_bin(key->g, (unsigned char *)gbuf, gbuf_len)) != CRYPT_OK) {\r
+            TLS_FREE(buf);\r
+            __private_tls_dh_clear_key(key);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+    }\r
+    \r
+    if (pbuf_len <= 0) {\r
+        if ((err = mp_read_radix(key->p, pbuf, 16)) != CRYPT_OK) {\r
+            TLS_FREE(buf);\r
+            __private_tls_dh_clear_key(key);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+    } else {\r
+        if ((err = mp_read_unsigned_bin(key->p, (unsigned char *)pbuf, pbuf_len)) != CRYPT_OK) {\r
+            TLS_FREE(buf);\r
+            __private_tls_dh_clear_key(key);\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+    }\r
+    \r
+    if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) {\r
+        TLS_FREE(buf);\r
+        __private_tls_dh_clear_key(key);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) {\r
+        TLS_FREE(buf);\r
+        __private_tls_dh_clear_key(key);\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    \r
+    TLS_FREE(buf);\r
+    return 0;\r
+}\r
+#endif\r
+\r
+int tls_is_ecdsa(struct TLSContext *context) {\r
+    if (!context)\r
+        return 0;\r
+    switch (context->cipher) {\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:\r
+#endif\r
+            return 1;\r
+    }\r
+    return 0;\r
+}\r
+\r
+struct TLSPacket *tls_build_client_key_exchange(struct TLSContext *context) {\r
+    if (context->is_server) {\r
+        DEBUG_PRINT("CANNOT BUILD CLIENT KEY EXCHANGE MESSAGE FOR SERVERS\n");\r
+        return NULL;\r
+    }\r
+    \r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);\r
+    tls_packet_uint8(packet, 0x10);\r
+#ifdef TLS_FORWARD_SECRECY\r
+    int ephemeral = tls_cipher_is_ephemeral(context);\r
+    if ((ephemeral) && (context->premaster_key) && (context->premaster_key_len)) {\r
+        if (ephemeral == 1) {\r
+            unsigned char dh_Ys[0xFFF];\r
+            unsigned char dh_p[0xFFF];\r
+            unsigned char dh_g[0xFFF];\r
+            unsigned long dh_p_len = sizeof(dh_p);\r
+            unsigned long dh_g_len = sizeof(dh_g);\r
+            unsigned long dh_Ys_len = sizeof(dh_Ys);\r
+            \r
+            if (__private_tls_dh_export_pqY(dh_p, &dh_p_len, dh_g, &dh_g_len, dh_Ys, &dh_Ys_len, context->dhe)) {\r
+                DEBUG_PRINT("ERROR EXPORTING DHE KEY %p\n", context->dhe);\r
+                TLS_FREE(packet);\r
+                __private_tls_dhe_free(context);\r
+                return NULL;\r
+            }\r
+            __private_tls_dhe_free(context);\r
+            DEBUG_DUMP_HEX_LABEL("Yc", dh_Ys, dh_Ys_len);\r
+            tls_packet_uint24(packet, dh_Ys_len + 2);\r
+            if (context->dtls)\r
+                __private_dtls_handshake_data(context, packet, dh_Ys_len + 2);\r
+            tls_packet_uint16(packet, dh_Ys_len);\r
+            tls_packet_append(packet, dh_Ys, dh_Ys_len);\r
+        } else\r
+        if (context->ecc_dhe) {\r
+            unsigned char out[__TLS_MAX_RSA_KEY];\r
+            unsigned long out_len = __TLS_MAX_RSA_KEY;\r
+            \r
+            if (ecc_ansi_x963_export(context->ecc_dhe, out, &out_len)) {\r
+                DEBUG_PRINT("Error exporting ECC key\n");\r
+                TLS_FREE(packet);\r
+                return NULL;\r
+            }\r
+            __private_tls_ecc_dhe_free(context);\r
+            tls_packet_uint24(packet, out_len + 1);\r
+            if (context->dtls) {\r
+                __private_dtls_handshake_data(context, packet, out_len + 1);\r
+                context->dtls_seq++;\r
+            }\r
+            tls_packet_uint8(packet, out_len);\r
+            tls_packet_append(packet, out, out_len);\r
+        }\r
+        __private_tls_compute_key(context, 48);\r
+    } else\r
+#endif\r
+    __private_tls_build_random(packet);\r
+    context->connection_status = 2;\r
+    tls_packet_update(packet);\r
+    return packet;\r
+}\r
+\r
+void __private_dtls_handshake_data(struct TLSContext *context, struct TLSPacket *packet, unsigned int framelength) {\r
+    // message seq\r
+    tls_packet_uint16(packet, context->dtls_seq);\r
+    // fragment offset\r
+    tls_packet_uint24(packet, 0);\r
+    // fragment length\r
+    tls_packet_uint24(packet, framelength);\r
+}\r
+\r
+void __private_dtls_handshake_copyframesize(struct TLSContext *context, struct TLSPacket *packet) {\r
+    packet->buf[22] = packet->buf[14];\r
+    packet->buf[23] = packet->buf[15];\r
+    packet->buf[24] = packet->buf[16];\r
+}\r
+\r
+struct TLSPacket *tls_build_server_key_exchange(struct TLSContext *context, int method) {\r
+    if (!context->is_server) {\r
+        DEBUG_PRINT("CANNOT BUILD SERVER KEY EXCHANGE MESSAGE FOR CLIENTS\n");\r
+        return NULL;\r
+    }\r
+    \r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);\r
+    tls_packet_uint8(packet, 0x0C);\r
+    unsigned char dummy[3];\r
+    tls_packet_append(packet, dummy, 3);\r
+    if (context->dtls)\r
+        __private_dtls_handshake_data(context, packet, 0);\r
+    int start_len = packet->len;\r
+#ifdef TLS_FORWARD_SECRECY\r
+    if (method == KEA_dhe_rsa) {\r
+        tls_init();\r
+        __private_tls_dhe_create(context);\r
+        \r
+        const char *default_dhe_p = context->default_dhe_p;\r
+        const char *default_dhe_g = context->default_dhe_g;\r
+        int key_size;\r
+        if ((!default_dhe_p) || (!default_dhe_g)) {\r
+            default_dhe_p = TLS_DH_DEFAULT_P;\r
+            default_dhe_g = TLS_DH_DEFAULT_G;\r
+            key_size = __TLS_DHE_KEY_SIZE / 8;\r
+        } else {\r
+            if (default_dhe_p)\r
+                key_size = strlen(default_dhe_p);\r
+            else\r
+                key_size = strlen(default_dhe_g);\r
+        }\r
+        if (__private_tls_dh_make_key(key_size, context->dhe, default_dhe_p, default_dhe_g, 0, 0)) {\r
+            DEBUG_PRINT("ERROR CREATING DHE KEY\n");\r
+            TLS_FREE(packet);\r
+            TLS_FREE(context->dhe);\r
+            context->dhe = NULL;\r
+            return NULL;\r
+        }\r
+        \r
+        unsigned char dh_Ys[0xFFF];\r
+        unsigned char dh_p[0xFFF];\r
+        unsigned char dh_g[0xFFF];\r
+        unsigned long dh_p_len = sizeof(dh_p);\r
+        unsigned long dh_g_len = sizeof(dh_g);\r
+        unsigned long dh_Ys_len = sizeof(dh_Ys);\r
+        \r
+        if (__private_tls_dh_export_pqY(dh_p, &dh_p_len, dh_g, &dh_g_len, dh_Ys, &dh_Ys_len, context->dhe)) {\r
+            DEBUG_PRINT("ERROR EXPORTING DHE KEY\n");\r
+            TLS_FREE(packet);\r
+            return NULL;\r
+        }\r
+        \r
+        DEBUG_PRINT("LEN: %lu (%lu, %lu)\n", dh_Ys_len, dh_p_len, dh_g_len);\r
+        DEBUG_DUMP_HEX_LABEL("DHE PK", dh_Ys, dh_Ys_len);\r
+        DEBUG_DUMP_HEX_LABEL("DHE P", dh_p, dh_p_len);\r
+        DEBUG_DUMP_HEX_LABEL("DHE G", dh_g, dh_g_len);\r
+        \r
+        tls_packet_uint16(packet, dh_p_len);\r
+        tls_packet_append(packet, dh_p, dh_p_len);\r
+        \r
+        tls_packet_uint16(packet, dh_g_len);\r
+        tls_packet_append(packet, dh_g, dh_g_len);\r
+        \r
+        tls_packet_uint16(packet, dh_Ys_len);\r
+        tls_packet_append(packet, dh_Ys, dh_Ys_len);\r
+        //dh_p\r
+        //dh_g\r
+        //dh_Ys\r
+    } else\r
+    if (method == KEA_ec_diffie_hellman) {\r
+        // 3 = named curve\r
+        if (!context->curve)\r
+            context->curve = default_curve;\r
+        tls_packet_uint8(packet, 3);\r
+        tls_packet_uint16(packet, context->curve->iana);\r
+        tls_init();\r
+        __private_tls_ecc_dhe_create(context);\r
+        \r
+        ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&context->curve->dp;\r
+        \r
+        if (ecc_make_key_ex(NULL, find_prng("sprng"), context->ecc_dhe, dp)) {\r
+            TLS_FREE(context->ecc_dhe);\r
+            context->ecc_dhe = NULL;\r
+            DEBUG_PRINT("Error generatic ECC key\n");\r
+            TLS_FREE(packet);\r
+            return NULL;\r
+        }\r
+        unsigned char out[__TLS_MAX_RSA_KEY];\r
+        unsigned long out_len = __TLS_MAX_RSA_KEY;\r
+        if (ecc_ansi_x963_export(context->ecc_dhe, out, &out_len)) {\r
+            DEBUG_PRINT("Error exporting ECC key\n");\r
+            TLS_FREE(packet);\r
+            return NULL;\r
+        }\r
+        tls_packet_uint8(packet, out_len);\r
+        tls_packet_append(packet, out, out_len);\r
+    } else\r
+#endif\r
+    {\r
+        TLS_FREE(packet);\r
+        DEBUG_PRINT("Unsupported ephemeral method: %i\n", method);\r
+        return NULL;\r
+    }\r
+    \r
+    // signature\r
+    unsigned int params_len = packet->len - start_len;\r
+    unsigned int message_len = params_len + __TLS_CLIENT_RANDOM_SIZE + __TLS_SERVER_RANDOM_SIZE;\r
+    unsigned char *message = (unsigned char *)TLS_MALLOC(message_len);\r
+    if (message) {\r
+        unsigned char out[__TLS_MAX_RSA_KEY];\r
+        unsigned long out_len = __TLS_MAX_RSA_KEY;\r
+        \r
+        int hash_algorithm;\r
+        if ((context->version != TLS_V12) && (context->version != DTLS_V12)) {\r
+            hash_algorithm = __md5_sha1;\r
+        } else {\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12))\r
+                hash_algorithm = sha256;\r
+            else\r
+                hash_algorithm = sha1;\r
+            \r
+#ifdef TLS_ECDSA_SUPPORTED\r
+            if (tls_is_ecdsa(context)) {\r
+                if ((context->version == TLS_V12) || (context->version == DTLS_V12))\r
+                    hash_algorithm = sha512;\r
+                tls_packet_uint8(packet, hash_algorithm);\r
+                tls_packet_uint8(packet, ecdsa);\r
+            } else\r
+#endif\r
+            {\r
+                tls_packet_uint8(packet, hash_algorithm);\r
+                tls_packet_uint8(packet, rsa_sign);\r
+            }\r
+        }\r
+        \r
+        memcpy(message, context->remote_random, __TLS_CLIENT_RANDOM_SIZE);\r
+        memcpy(message + __TLS_CLIENT_RANDOM_SIZE, context->local_random, __TLS_SERVER_RANDOM_SIZE);\r
+        memcpy(message + __TLS_CLIENT_RANDOM_SIZE + __TLS_SERVER_RANDOM_SIZE, packet->buf + start_len, params_len);\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        if (tls_is_ecdsa(context)) {\r
+            if (__private_tls_sign_ecdsa(context, hash_algorithm, message, message_len, out, &out_len) == 1) {\r
+                DEBUG_PRINT("Signing OK! (ECDSA, length %lu)\n", out_len);\r
+                tls_packet_uint16(packet, out_len);\r
+                tls_packet_append(packet, out, out_len);\r
+            }\r
+        } else\r
+#endif\r
+        if (__private_tls_sign_rsa(context, hash_algorithm, message, message_len, out, &out_len) == 1) {\r
+            DEBUG_PRINT("Signing OK! (length %lu)\n", out_len);\r
+            tls_packet_uint16(packet, out_len);\r
+            tls_packet_append(packet, out, out_len);\r
+        }\r
+        TLS_FREE(message);\r
+    }\r
+    if ((!packet->broken) && (packet->buf)) {\r
+        int remaining = packet->len - start_len;\r
+        int payload_pos = 6;\r
+        if (context->dtls)\r
+            payload_pos = 14;\r
+        packet->buf[payload_pos] = remaining / 0x10000;\r
+        remaining %= 0x10000;\r
+        packet->buf[payload_pos + 1] = remaining / 0x100;\r
+        remaining %= 0x100;\r
+        packet->buf[payload_pos + 2] = remaining;\r
+        if (context->dtls) {\r
+            __private_dtls_handshake_copyframesize(context, packet);\r
+            context->dtls_seq++;\r
+        }\r
+    }\r
+    tls_packet_update(packet);\r
+    return packet;\r
+}\r
+\r
+void __private_tls_set_session_id(struct TLSContext *context) {\r
+    if (tls_random(context->session, __TLS_MAX_SESSION_ID))\r
+        context->session_size = __TLS_MAX_SESSION_ID;\r
+    else\r
+        context->session_size = 0;\r
+}\r
+\r
+struct TLSPacket *tls_build_hello(struct TLSContext *context) {\r
+    if (!tls_random(context->local_random, __TLS_SERVER_RANDOM_SIZE))\r
+        return NULL;\r
+    \r
+    unsigned short packet_version = context->version;\r
+    unsigned short version = context->version;\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, packet_version, 0);\r
+    if (packet) {\r
+        // hello\r
+        if (context->is_server)\r
+            tls_packet_uint8(packet, 0x02);\r
+        else\r
+            tls_packet_uint8(packet, 0x01);\r
+        unsigned char dummy[3];\r
+        tls_packet_append(packet, dummy, 3);\r
+\r
+        if (context->dtls)\r
+            __private_dtls_handshake_data(context, packet, 0);\r
+\r
+        int start_len = packet->len;\r
+        tls_packet_uint16(packet, version);\r
+        if (context->is_server)\r
+            tls_packet_append(packet, context->local_random, __TLS_SERVER_RANDOM_SIZE);\r
+        else\r
+            tls_packet_append(packet, context->local_random, __TLS_CLIENT_RANDOM_SIZE);\r
+\r
+#ifdef IGNORE_SESSION_ID\r
+        // session size\r
+        tls_packet_uint8(packet, 0);\r
+#else\r
+        __private_tls_set_session_id(context);\r
+        // session size\r
+        tls_packet_uint8(packet, context->session_size);\r
+        if (context->session_size)\r
+            tls_packet_append(packet, context->session, context->session_size);\r
+#endif\r
+\r
+        int extension_len = 0;\r
+        int alpn_len = 0;\r
+        int alpn_negotiated_len = 0;\r
+        int i;\r
+        if ((context->is_server) && (context->negotiated_alpn)) {\r
+            alpn_negotiated_len = strlen(context->negotiated_alpn);\r
+            alpn_len = alpn_negotiated_len + 1;\r
+            extension_len += alpn_len + 6;\r
+        } else\r
+        if ((!context->is_server) && (context->alpn_count)) {\r
+            for (i = 0; i < context->alpn_count;i++) {\r
+                if (context->alpn[i]) {\r
+                    int len = strlen(context->alpn[i]);\r
+                    if (len)\r
+                        alpn_len += len + 1;\r
+                }\r
+            }\r
+            if (alpn_len)\r
+                extension_len += alpn_len + 6;\r
+        }\r
+\r
+        // ciphers\r
+        if (context->is_server) {\r
+            // fallback ... this should never happen\r
+            if (!context->cipher)\r
+                context->cipher = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;\r
+            \r
+            tls_packet_uint16(packet, context->cipher);\r
+            // no compression\r
+            tls_packet_uint8(packet, 0);\r
+#ifndef STRICT_TLS\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+                // extensions size\r
+                tls_packet_uint16(packet, 5 + extension_len);\r
+                // secure renegotation\r
+                // advertise it, but refuse renegotiation\r
+                tls_packet_uint16(packet, 0xff01);\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+                // a little defensive\r
+                if ((context->verify_len) && (!context->verify_data))\r
+                        context->verify_len = 0;\r
+                tls_packet_uint16(packet, context->verify_len + 1);\r
+                tls_packet_uint8(packet, context->verify_len);\r
+                if (context->verify_len)\r
+                    tls_packet_append(packet, (unsigned char *)context->verify_data, context->verify_len);\r
+#else\r
+                tls_packet_uint16(packet, 1);\r
+                tls_packet_uint8(packet, 0);\r
+#endif\r
+                if (alpn_len) {\r
+                    tls_packet_uint16(packet, 0x10);\r
+                    tls_packet_uint16(packet, alpn_len + 2);\r
+                    tls_packet_uint16(packet, alpn_len);\r
+\r
+                    tls_packet_uint8(packet, alpn_negotiated_len);\r
+                    tls_packet_append(packet, (unsigned char *)context->negotiated_alpn, alpn_negotiated_len);\r
+                }\r
+            }\r
+#endif\r
+        } else {\r
+            if (context->dtls) {\r
+                tls_packet_uint8(packet, context->dtls_cookie_len);\r
+                if (context->dtls_cookie_len)\r
+                    tls_packet_append(packet, context->dtls_cookie, context->dtls_cookie_len);\r
+            }\r
+\r
+#ifndef STRICT_TLS\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+#endif\r
+#ifdef TLS_FORWARD_SECRECY\r
+#ifdef TLS_CLIENT_ECDHE\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+    #ifdef TLS_CLIENT_ECDSA\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(16, 5));\r
+    #ifdef TLS_PREFER_CHACHA20\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);\r
+    #endif\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);\r
+    #ifndef TLS_PREFER_CHACHA20\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);\r
+    #endif\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);\r
+    #else\r
+                // sizeof ciphers (16 ciphers * 2 bytes)\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(11, 5));\r
+    #endif\r
+#else\r
+    #ifdef TLS_CLIENT_ECDSA\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(13, 5));\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256);\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);\r
+    #else\r
+                // sizeof ciphers (14 ciphers * 2 bytes)\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(9, 5));\r
+    #endif\r
+#endif\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                #ifdef TLS_PREFER_CHACHA20\r
+                    tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);\r
+                #endif\r
+#endif\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256);\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                #ifndef TLS_PREFER_CHACHA20\r
+                    tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);\r
+                #endif\r
+#endif\r
+#else\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                // sizeof ciphers (11 ciphers * 2 bytes)\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(6, 5));\r
+#else\r
+                // sizeof ciphers (10 ciphers * 2 bytes)\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(5, 5));\r
+#endif\r
+#endif\r
+                // not yet supported, because the first message sent (this one)\r
+                // is already hashed by the client with sha256 (sha384 not yet supported client-side)\r
+                // but is fully suported server-side\r
+                // tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_128_CBC_SHA);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);\r
+#endif\r
+#else\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(0, 5));\r
+#endif\r
+                // tls_packet_uint16(packet, TLS_RSA_WITH_AES_256_GCM_SHA384);\r
+#ifndef TLS_ROBOT_MITIGATION\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_128_GCM_SHA256);\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_256_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_128_CBC_SHA256);\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_128_CBC_SHA);\r
+#endif\r
+#ifndef STRICT_TLS\r
+            } else {\r
+#ifdef TLS_FORWARD_SECRECY\r
+#ifdef TLS_CLIENT_ECDHE\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(5, 2));\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);\r
+#else\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(3, 2));\r
+#endif\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_DHE_RSA_WITH_AES_128_CBC_SHA);\r
+#else\r
+                tls_packet_uint16(packet, TLS_CIPHERS_SIZE(0, 2));\r
+#endif\r
+#ifndef TLS_ROBOT_MITIGATION\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_256_CBC_SHA);\r
+                tls_packet_uint16(packet, TLS_RSA_WITH_AES_128_CBC_SHA);\r
+#endif\r
+            }\r
+#endif\r
+            // compression\r
+            tls_packet_uint8(packet, 1);\r
+            // no compression\r
+            tls_packet_uint8(packet, 0);\r
+            if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+                int sni_len = 0;\r
+                if (context->sni)\r
+                    sni_len = strlen(context->sni);\r
+                \r
+#ifdef TLS_CLIENT_ECDHE\r
+                extension_len += 12;\r
+#endif\r
+                if (sni_len)\r
+                    extension_len += sni_len + 9;\r
+                \r
+                tls_packet_uint16(packet, extension_len);\r
+                \r
+                if (sni_len) {\r
+                    // sni extension\r
+                    tls_packet_uint16(packet, 0x00);\r
+                    // sni extension len\r
+                    tls_packet_uint16(packet, sni_len + 5);\r
+                    // sni len\r
+                    tls_packet_uint16(packet, sni_len + 3);\r
+                    // sni type\r
+                    tls_packet_uint8(packet, 0);\r
+                    // sni host len\r
+                    tls_packet_uint16(packet, sni_len);\r
+                    tls_packet_append(packet, (unsigned char *)context->sni, sni_len);\r
+                }\r
+#ifdef TLS_FORWARD_SECRECY\r
+#ifdef TLS_CLIENT_ECDHE\r
+                // supported groups\r
+                tls_packet_uint16(packet, 0x0A);\r
+                tls_packet_uint16(packet, 8);\r
+                // 3 curves x 2 bytes\r
+                tls_packet_uint16(packet, 6);\r
+                tls_packet_uint16(packet, secp256r1.iana);\r
+                tls_packet_uint16(packet, secp384r1.iana);\r
+                tls_packet_uint16(packet, secp224r1.iana);\r
+#endif\r
+#endif\r
+                if (alpn_len) {\r
+                    tls_packet_uint16(packet, 0x10);\r
+                    tls_packet_uint16(packet, alpn_len + 2);\r
+                    tls_packet_uint16(packet, alpn_len);\r
+\r
+                    for (i = 0; i < context->alpn_count;i++) {\r
+                        if (context->alpn[i]) {\r
+                            int len = strlen(context->alpn[i]);\r
+                            if (len) {\r
+                                tls_packet_uint8(packet, len);\r
+                                tls_packet_append(packet, (unsigned char *)context->alpn[i], len);\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        \r
+        if ((!packet->broken) && (packet->buf)) {\r
+            int remaining = packet->len - start_len;\r
+            int payload_pos = 6;\r
+            if (context->dtls)\r
+                payload_pos = 14;\r
+            packet->buf[payload_pos] = remaining / 0x10000;\r
+            remaining %= 0x10000;\r
+            packet->buf[payload_pos + 1] = remaining / 0x100;\r
+            remaining %= 0x100;\r
+            packet->buf[payload_pos + 2] = remaining;\r
+            if (context->dtls) {\r
+                __private_dtls_handshake_copyframesize(context, packet);\r
+                context->dtls_seq++;\r
+            }\r
+        }\r
+        tls_packet_update(packet);\r
+    }\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_certificate_request(struct TLSContext *context) {\r
+    if ((!context) || (!context->is_server))\r
+        return NULL;\r
+    \r
+    unsigned short packet_version = context->version;\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, packet_version, 0);\r
+    if (packet) {\r
+        // certificate request\r
+        tls_packet_uint8(packet, 0x0D);\r
+        unsigned char dummy[3];\r
+        tls_packet_append(packet, dummy, 3);\r
+        if (context->dtls)\r
+            __private_dtls_handshake_data(context, packet, 0);\r
+        int start_len = packet->len;\r
+        tls_packet_uint8(packet, 1);\r
+        tls_packet_uint8(packet, rsa_sign);\r
+        if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+            // 10 pairs or 2 bytes\r
+            tls_packet_uint16(packet, 10);\r
+            tls_packet_uint8(packet, sha256);\r
+            tls_packet_uint8(packet, rsa);\r
+            tls_packet_uint8(packet, sha1);\r
+            tls_packet_uint8(packet, rsa);\r
+            tls_packet_uint8(packet, sha384);\r
+            tls_packet_uint8(packet, rsa);\r
+            tls_packet_uint8(packet, sha512);\r
+            tls_packet_uint8(packet, rsa);\r
+            tls_packet_uint8(packet, md5);\r
+            tls_packet_uint8(packet, rsa);\r
+        }\r
+        // no DistinguishedName yet\r
+        tls_packet_uint16(packet, 0);\r
+        if ((!packet->broken) && (packet->buf)) {\r
+            int remaining = packet->len - start_len;\r
+            int payload_pos = 6;\r
+            if (context->dtls)\r
+                payload_pos = 14;\r
+            packet->buf[payload_pos] = remaining / 0x10000;\r
+            remaining %= 0x10000;\r
+            packet->buf[payload_pos + 1] = remaining / 0x100;\r
+            remaining %= 0x100;\r
+            packet->buf[payload_pos + 2] = remaining;\r
+\r
+            if (context->dtls) {\r
+                __private_dtls_handshake_copyframesize(context, packet);\r
+                context->dtls_seq++;\r
+            }\r
+        }\r
+        tls_packet_update(packet);\r
+    }\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_build_verify_request(struct TLSContext *context) {\r
+    if ((!context->is_server) || (!context->dtls))\r
+        return NULL;\r
+    \r
+    if ((!context->dtls_cookie) || (!context->dtls_cookie_len)) {\r
+        context->dtls_cookie = (unsigned char *)TLS_MALLOC(__DTLS_COOKIE_SIZE);\r
+        if (!context->dtls_cookie)\r
+            return NULL;\r
+        \r
+        if (!tls_random(context->dtls_cookie, __DTLS_COOKIE_SIZE)) {\r
+            TLS_FREE(context->dtls_cookie);\r
+            context->dtls_cookie = NULL;\r
+            return NULL;\r
+        }\r
+        context->dtls_cookie_len = __DTLS_COOKIE_SIZE;\r
+    }\r
+\r
+    unsigned short packet_version = context->version;\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, packet_version, 0);\r
+    if (packet) {\r
+        // verify request\r
+        tls_packet_uint8(packet, 0x03);\r
+        // 24-bit length\r
+        tls_packet_uint24(packet, context->dtls_cookie_len + 3);\r
+        // 16-bit message_sequence\r
+        tls_packet_uint16(packet, 0);\r
+        // 24-bit fragment_offset\r
+        tls_packet_uint24(packet, 0);\r
+        // 24-bit fragment_offset\r
+        tls_packet_uint24(packet, context->dtls_cookie_len + 3);\r
+        // server_version\r
+        tls_packet_uint16(packet, context->version);\r
+        tls_packet_uint8(packet, context->dtls_cookie_len);\r
+        tls_packet_append(packet, context->dtls_cookie, context->dtls_cookie_len);\r
+        tls_packet_update(packet);\r
+    }\r
+    return packet;\r
+}\r
+\r
+int __private_dtls_check_packet(const unsigned char *buf, int buf_len) {\r
+    CHECK_SIZE(11, buf_len, TLS_NEED_MORE_DATA)\r
+\r
+    unsigned int bytes_to_follow = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    // not used: unsigned short message_seq = ntohs(*(unsigned short *)&buf[3]);\r
+    unsigned int fragment_offset = buf[5] * 0x10000 + buf[6] * 0x100 + buf[7];\r
+    unsigned int fragment_length = buf[8] * 0x10000 + buf[9] * 0x100 + buf[10];\r
+\r
+    if ((fragment_offset) || (fragment_length != bytes_to_follow)) {\r
+        DEBUG_PRINT("FRAGMENTED PACKETS NOT SUPPORTED\n");\r
+        return TLS_FEATURE_NOT_SUPPORTED;\r
+    }\r
+    return bytes_to_follow;\r
+}\r
+\r
+void __private_dtls_reset(struct TLSContext *context) {\r
+    context->dtls_epoch_local = 0;\r
+    context->dtls_epoch_remote = 0;\r
+    context->dtls_seq = 0;\r
+    __private_tls_destroy_hash(context);\r
+    context->connection_status = 0;\r
+}\r
+\r
+int tls_parse_verify_request(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets) {\r
+    *write_packets = 0;\r
+    if ((context->connection_status != 0) || (!context->dtls)) {\r
+        DEBUG_PRINT("UNEXPECTED VERIFY REQUEST MESSAGE\n");\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    }\r
+    int res = 11;\r
+    int bytes_to_follow = __private_dtls_check_packet(buf, buf_len);\r
+    if (bytes_to_follow < 0)\r
+        return bytes_to_follow;\r
+\r
+    CHECK_SIZE(bytes_to_follow, buf_len - res, TLS_NEED_MORE_DATA)\r
+    // not used: unsigned short version = ntohs(*(unsigned short *)&buf[res]);\r
+    res += 2;\r
+    unsigned char len = buf[res];\r
+    res++;\r
+    TLS_FREE(context->dtls_cookie);\r
+    context->dtls_cookie_len = 0;\r
+    if (len) {\r
+        CHECK_SIZE(len, buf_len - res, TLS_NEED_MORE_DATA)\r
+        context->dtls_cookie = (unsigned char *)TLS_MALLOC(len);\r
+        if (!context->dtls_cookie)\r
+            return TLS_NO_MEMORY;\r
+        context->dtls_cookie_len = len;\r
+        memcpy(context->dtls_cookie, &buf[res], len);\r
+        res += len;\r
+        *write_packets = 4;\r
+    }\r
+\r
+    // reset context\r
+    __private_dtls_reset(context);\r
+    return res;\r
+}\r
+\r
+void __private_dtls_reset_cookie(struct TLSContext *context) {\r
+    TLS_FREE(context->dtls_cookie);\r
+    context->dtls_cookie = NULL;\r
+    context->dtls_cookie_len = 0;\r
+}\r
+\r
+int tls_parse_hello(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets, unsigned int *dtls_verified) {\r
+    *write_packets = 0;\r
+    *dtls_verified = 0;\r
+    if (context->connection_status != 0) {\r
+        // ignore multiple hello on dtls\r
+        if (context->dtls) {\r
+            DEBUG_PRINT("RETRANSMITTED HELLO MESSAGE RECEIVED\n");\r
+            return 1;\r
+        }\r
+        DEBUG_PRINT("UNEXPECTED HELLO MESSAGE\n");\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    }\r
+    \r
+    int res = 0;\r
+    int downgraded = 0;\r
+    int hello_min_size = context->dtls ? __TLS_CLIENT_HELLO_MINSIZE + 8 : __TLS_CLIENT_HELLO_MINSIZE;\r
+    CHECK_SIZE(hello_min_size, buf_len, TLS_NEED_MORE_DATA)\r
+    // big endian\r
+    unsigned int bytes_to_follow = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    res += 3;\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        // 16 bit message seq + 24 bit fragment offset + 24 bit fragment length\r
+        res += 8;\r
+    }\r
+    CHECK_SIZE(bytes_to_follow, buf_len - res, TLS_NEED_MORE_DATA)\r
+    \r
+    CHECK_SIZE(2, buf_len - res, TLS_NEED_MORE_DATA)\r
+    unsigned short version = ntohs(*(unsigned short *)&buf[res]);\r
+    \r
+    res += 2;\r
+    VERSION_SUPPORTED(version, TLS_NOT_SAFE)\r
+    DEBUG_PRINT("VERSION REQUIRED BY REMOTE %x, VERSION NOW %x\n", (int)version, (int)context->version);\r
+#ifdef TLS_LEGACY_SUPPORT\r
+    // when no legacy support, don't downgrade\r
+#ifndef TLS_FORCE_LOCAL_VERSION\r
+    // downgrade ?\r
+    if (context->dtls) {\r
+        // for dlts, newer version has lower id (1.0 = FEFF, 1.2 = FEFD)\r
+        if (context->version < version)\r
+            downgraded = 1;\r
+    } else {\r
+        if (context->version > version)\r
+            downgraded = 1;\r
+    }\r
+    if (downgraded) {\r
+        context->version = version;\r
+        if (!context->is_server)\r
+            __private_tls_change_hash_type(context);\r
+    }\r
+#endif\r
+#endif\r
+    memcpy(context->remote_random, &buf[res], __TLS_CLIENT_RANDOM_SIZE);\r
+    res += __TLS_CLIENT_RANDOM_SIZE;\r
+    \r
+    unsigned char session_len = buf[res++];\r
+    CHECK_SIZE(session_len, buf_len - res, TLS_NEED_MORE_DATA)\r
+    if ((session_len) && (session_len <= __TLS_MAX_SESSION_ID)) {\r
+        memcpy(context->session, &buf[res], session_len);\r
+        context->session_size = session_len;\r
+    } else\r
+        context->session_size = 0;\r
+\r
+    res += session_len;\r
+\r
+    if (context->is_server) {\r
+        if (context->dtls) {\r
+            CHECK_SIZE(1, buf_len - res, TLS_NEED_MORE_DATA)\r
+            unsigned char tls_cookie_len = buf[res++];\r
+            if (tls_cookie_len) {\r
+                CHECK_SIZE(tls_cookie_len, buf_len - res, TLS_NEED_MORE_DATA)\r
+                if ((context->dtls_cookie_len != tls_cookie_len) || (!context->dtls_cookie)) {\r
+                    *dtls_verified = 2;\r
+                    __private_dtls_reset_cookie(context);\r
+                    DEBUG_PRINT("INVALID DTLS COOKIE\n");\r
+                    return TLS_BROKEN_PACKET;\r
+                }\r
+                if (memcmp(context->dtls_cookie, &buf[res], tls_cookie_len)) {\r
+                    *dtls_verified = 3;\r
+                    __private_dtls_reset_cookie(context);\r
+                    DEBUG_PRINT("MISMATCH DTLS COOKIE\n");\r
+                    return TLS_BROKEN_PACKET;\r
+                }\r
+                __private_dtls_reset_cookie(context);\r
+                context->dtls_seq++;\r
+                *dtls_verified = 1;\r
+                res += tls_cookie_len;\r
+            } else {\r
+                *write_packets = 2;\r
+                return buf_len;\r
+            }\r
+        }\r
+        CHECK_SIZE(2, buf_len - res, TLS_NEED_MORE_DATA)\r
+        unsigned short cipher_len = ntohs(*(unsigned short *)&buf[res]);\r
+        res += 2;\r
+        CHECK_SIZE(cipher_len, buf_len - res, TLS_NEED_MORE_DATA)\r
+        // faster than cipher_len % 2\r
+        if (cipher_len & 1)\r
+            return TLS_BROKEN_PACKET;\r
+        \r
+        int scsv_set = 0;\r
+        int cipher = tls_choose_cipher(context, &buf[res], cipher_len, &scsv_set);\r
+        if (cipher < 0) {\r
+            DEBUG_PRINT("NO COMMON CIPHERS\n");\r
+            return cipher;\r
+        }\r
+        if ((downgraded) && (scsv_set)) {\r
+            DEBUG_PRINT("NO DOWNGRADE (SCSV SET)\n");\r
+            __private_tls_write_packet(tls_build_alert(context, 1, inappropriate_fallback));\r
+            context->critical_error = 1;\r
+            return TLS_NOT_SAFE;\r
+        }\r
+        context->cipher = cipher;\r
+        res += cipher_len;\r
+        \r
+        CHECK_SIZE(1, buf_len - res, TLS_NEED_MORE_DATA)\r
+        unsigned char compression_list_size = buf[res++];\r
+        CHECK_SIZE(compression_list_size, buf_len - res, TLS_NEED_MORE_DATA)\r
+        \r
+        // no compression support\r
+        res += compression_list_size;\r
+    } else {\r
+        CHECK_SIZE(2, buf_len - res, TLS_NEED_MORE_DATA)\r
+        unsigned short cipher = ntohs(*(unsigned short *)&buf[res]);\r
+        res += 2;\r
+        context->cipher = cipher;\r
+        if (!tls_cipher_supported(context, cipher)) {\r
+            context->cipher = 0;\r
+            DEBUG_PRINT("NO CIPHER SUPPORTED\n");\r
+            return TLS_NO_COMMON_CIPHER;\r
+        }\r
+        DEBUG_PRINT("CIPHER: %s\n", tls_cipher_name(context));\r
+        CHECK_SIZE(1, buf_len - res, TLS_NEED_MORE_DATA)\r
+        unsigned char compression = buf[res++];\r
+        if (compression != 0) {\r
+            DEBUG_PRINT("COMPRESSION NOT SUPPORTED\n");\r
+            return TLS_COMPRESSION_NOT_SUPPORTED;\r
+        }\r
+    }\r
+    \r
+    if (res > 0) {\r
+        if (context->is_server)\r
+            *write_packets = 2;\r
+        context->connection_status = 1;\r
+    }\r
+    \r
+    \r
+    if (res > 2) {\r
+        res += 2;\r
+    }\r
+    // ignore extensions for now\r
+    while (buf_len - res >= 4) {\r
+        // have extensions\r
+        unsigned short extension_type = ntohs(*(unsigned short *)&buf[res]);\r
+        res += 2;\r
+        unsigned short extension_len = ntohs(*(unsigned short *)&buf[res]);\r
+        res += 2;\r
+        DEBUG_PRINT("Extension: 0x0%x (%i), len: %i\n", (int)extension_type, (int)extension_type, (int)extension_len);\r
+        if (extension_len) {\r
+            // SNI extension\r
+            CHECK_SIZE(extension_len, buf_len - res, TLS_NEED_MORE_DATA)\r
+            if (extension_type == 0x00) {\r
+                // unsigned short sni_len = ntohs(*(unsigned short *)&buf[res]);\r
+                // unsigned char sni_type = buf[res + 2];\r
+                unsigned short sni_host_len = ntohs(*(unsigned short *)&buf[res + 3]);\r
+                CHECK_SIZE(sni_host_len, buf_len - res - 5, TLS_NEED_MORE_DATA)\r
+                if (sni_host_len) {\r
+                    TLS_FREE(context->sni);\r
+                    context->sni = (char *)TLS_MALLOC(sni_host_len + 1);\r
+                    if (context->sni) {\r
+                        memcpy(context->sni, &buf[res + 5], sni_host_len);\r
+                        context->sni[sni_host_len] = 0;\r
+                        DEBUG_PRINT("SNI HOST INDICATOR: [%s]\n", context->sni);\r
+                    }\r
+                }\r
+            } else\r
+#ifdef TLS_FORWARD_SECRECY\r
+            if (extension_type == 0x0A) {\r
+                // supported groups\r
+                if (buf_len - res > 2) {\r
+                    unsigned short group_len = ntohs(*(unsigned short *)&buf[res]);\r
+                    if (buf_len - res >= group_len + 2) {\r
+                        DEBUG_DUMP_HEX_LABEL("SUPPORTED GROUPS", &buf[res + 2], group_len);\r
+                        int i;\r
+                        int selected = 0;\r
+                        for (i = 0; i < group_len; i += 2) {\r
+                            unsigned short iana_n = ntohs(*(unsigned short *)&buf[res + 2 + i]);\r
+                            switch (iana_n) {\r
+                                case 23:\r
+                                    context->curve = &secp256r1;\r
+                                    selected = 1;\r
+                                    break;\r
+                                case 24:\r
+                                    context->curve = &secp384r1;\r
+                                    selected = 1;\r
+                                    break;\r
+                                // do not use it anymore\r
+                                // case 25:\r
+                                //    context->curve = &secp521r1;\r
+                                //    selected = 1;\r
+                                //    break;\r
+                            }\r
+                            if (selected) {\r
+                                DEBUG_PRINT("SELECTED CURVE %s\n", context->curve->name);\r
+                                break;\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            } else\r
+#endif\r
+            if ((extension_type == 0x10) && (context->alpn) && (context->alpn_count)) {\r
+                if (buf_len - res > 2) {\r
+                    unsigned short alpn_len = ntohs(*(unsigned short *)&buf[res]);\r
+                    if ((alpn_len) && (alpn_len <= extension_len - 2)) {\r
+                        unsigned char *alpn = (unsigned char *)&buf[res + 2];\r
+                        int alpn_pos = 0;\r
+                        while (alpn_pos < alpn_len) {\r
+                            unsigned char alpn_size = alpn[alpn_pos++];\r
+                            if (alpn_size + alpn_pos >= extension_len)\r
+                                break;\r
+                            if ((alpn_size) && (tls_alpn_contains(context, (char *)&alpn[alpn_pos], alpn_size))) {\r
+                                TLS_FREE(context->negotiated_alpn);\r
+                                context->negotiated_alpn = (char *)TLS_MALLOC(alpn_size + 1);\r
+                                if (context->negotiated_alpn) {\r
+                                    memcpy(context->negotiated_alpn, &alpn[alpn_pos], alpn_size);\r
+                                    context->negotiated_alpn[alpn_size] = 0;\r
+                                    DEBUG_PRINT("NEGOTIATED ALPN: %s\n", context->negotiated_alpn);\r
+                                }\r
+                                break;\r
+                            }\r
+                            alpn_pos += alpn_size;\r
+                            // ServerHello contains just one alpn\r
+                            if (!context->is_server)\r
+                                break;\r
+                        }\r
+                    }\r
+                }\r
+            } else\r
+            if (extension_type == 0x0D) {\r
+                // supported signatures\r
+                DEBUG_DUMP_HEX_LABEL("SUPPORTED SIGNATURES", &buf[res], extension_len);\r
+            } else\r
+            if (extension_type == 0x0B) {\r
+                // supported point formats\r
+                DEBUG_DUMP_HEX_LABEL("SUPPORTED POINT FORMATS", &buf[res], extension_len);\r
+            }\r
+            res += extension_len;\r
+        }\r
+    }\r
+    if (buf_len != res)\r
+        return TLS_NEED_MORE_DATA;\r
+    return res;\r
+}\r
+\r
+int tls_parse_certificate(struct TLSContext *context, const unsigned char *buf, int buf_len, int is_client) {\r
+    int res = 0;\r
+    CHECK_SIZE(3, buf_len, TLS_NEED_MORE_DATA)\r
+    unsigned int size_of_all_certificates = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    \r
+    if (size_of_all_certificates <= 4)\r
+        return 3 + size_of_all_certificates;\r
+    res += 3;\r
+\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        res += 8;\r
+    }\r
+\r
+    CHECK_SIZE(size_of_all_certificates, buf_len - res, TLS_NEED_MORE_DATA);\r
+    int size = size_of_all_certificates;\r
+    \r
+    int idx = 0;\r
+    int valid_certificate = 0;\r
+    while (size > 0) {\r
+        idx++;\r
+        CHECK_SIZE(3, buf_len - res, TLS_NEED_MORE_DATA);\r
+        unsigned int certificate_size = buf[res] * 0x10000 + buf[res + 1] * 0x100 + buf[res + 2];\r
+        res += 3;\r
+        CHECK_SIZE(certificate_size, buf_len - res, TLS_NEED_MORE_DATA)\r
+        // load chain\r
+        int certificates_in_chain = 0;\r
+        int res2 = res;\r
+        unsigned int remaining = certificate_size;\r
+        do {\r
+            if (remaining <= 3)\r
+                break;\r
+            certificates_in_chain++;\r
+            unsigned int certificate_size2 = buf[res2] * 0x10000 + buf[res2 + 1] * 0x100 + buf[res2 + 2];\r
+            res2 += 3;\r
+            remaining -= 3;\r
+            if (certificate_size2 > remaining) {\r
+                DEBUG_PRINT("Invalid certificate size (%i from %i bytes remaining)\n", certificate_size2, remaining);\r
+                break;\r
+            }\r
+            remaining -= certificate_size2;\r
+            \r
+            struct TLSCertificate *cert = asn1_parse(context, &buf[res2], certificate_size2, is_client);\r
+            if (cert) {\r
+                if (certificate_size2) {\r
+                    cert->bytes = (unsigned char *)TLS_MALLOC(certificate_size2);\r
+                    if (cert->bytes) {\r
+                        cert->len = certificate_size2;\r
+                        memcpy(cert->bytes, &buf[res2], certificate_size2);\r
+                    }\r
+                }\r
+                // valid certificate\r
+                if (is_client) {\r
+                    valid_certificate = 1;\r
+                    context->client_certificates = (struct TLSCertificate **)TLS_REALLOC(context->client_certificates, (context->client_certificates_count + 1) * sizeof(struct TLSCertificate));\r
+                    context->client_certificates[context->client_certificates_count] = cert;\r
+                    context->client_certificates_count++;\r
+                } else {\r
+                    context->certificates = (struct TLSCertificate **)TLS_REALLOC(context->certificates, (context->certificates_count + 1) * sizeof(struct TLSCertificate));\r
+                    context->certificates[context->certificates_count] = cert;\r
+                    context->certificates_count++;\r
+                    if ((cert->pk) || (cert->priv))\r
+                        valid_certificate = 1;\r
+                    else\r
+                    if (!context->is_server)\r
+                        valid_certificate = 1;\r
+                }\r
+            }\r
+            res2 += certificate_size2;\r
+        } while (remaining > 0);\r
+        if (remaining)\r
+            DEBUG_PRINT("Extra %i bytes after certificate\n", remaining);\r
+        size -= certificate_size + 3;\r
+        res += certificate_size;\r
+    }\r
+    if (!valid_certificate)\r
+        return TLS_UNSUPPORTED_CERTIFICATE;\r
+    if (res != buf_len) {\r
+        DEBUG_PRINT("Warning: %i bytes read from %i byte buffer\n", (int)res, (int)buf_len);\r
+    }\r
+    return res;\r
+}\r
+\r
+int __private_tls_parse_dh(struct TLSContext *context, const unsigned char *buf, int buf_len, const unsigned char **out, int *out_size) {\r
+    int res = 0;\r
+    *out = NULL;\r
+    *out_size = 0;\r
+    CHECK_SIZE(2, buf_len, TLS_NEED_MORE_DATA)\r
+    unsigned short size = ntohs(*(unsigned short *)buf);\r
+    res += 2;\r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA)\r
+    DEBUG_DUMP_HEX(&buf[res], size);\r
+    *out = &buf[res];\r
+    *out_size = size;\r
+    res += size;\r
+    return res;\r
+}\r
+\r
+int __private_tls_parse_random(struct TLSContext *context, const unsigned char *buf, int buf_len) {\r
+    int res = 0;\r
+    int ephemeral = tls_cipher_is_ephemeral(context);\r
+    unsigned short size;\r
+    if (ephemeral == 2) {\r
+        CHECK_SIZE(1, buf_len, TLS_NEED_MORE_DATA)\r
+        size = buf[0];\r
+        res += 1;\r
+    } else {\r
+        CHECK_SIZE(2, buf_len, TLS_NEED_MORE_DATA)\r
+        size = ntohs(*(unsigned short *)buf);\r
+        res += 2;\r
+    }\r
+    \r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA)\r
+    unsigned int out_len = 0;\r
+    unsigned char *random = NULL;\r
+    switch (ephemeral) {\r
+#ifdef TLS_FORWARD_SECRECY\r
+        case 1:\r
+            random = __private_tls_decrypt_dhe(context, &buf[res], size, &out_len, 1);\r
+            break;\r
+        case 2:\r
+            random = __private_tls_decrypt_ecc_dhe(context, &buf[res], size, &out_len, 1);\r
+            break;\r
+#endif\r
+        default:\r
+            random = __private_tls_decrypt_rsa(context, &buf[res], size, &out_len);\r
+    }\r
+    \r
+    if ((random) && (out_len > 2)) {\r
+        // *(unsigned short *)&random[0] = htons(context->version);\r
+        DEBUG_DUMP_HEX_LABEL("PRE MASTER KEY", random, out_len);\r
+        TLS_FREE(context->premaster_key);\r
+        context->premaster_key = random;\r
+        context->premaster_key_len = out_len;\r
+        __private_tls_compute_key(context, 48);\r
+    } else {\r
+        TLS_FREE(random);\r
+        return 0;\r
+    }\r
+    res += size;\r
+    return res;\r
+}\r
+\r
+int __private_tls_build_random(struct TLSPacket *packet) {\r
+    int res = 0;\r
+    unsigned char rand_bytes[48];\r
+    int bytes = 48;\r
+    if (!tls_random(rand_bytes, bytes))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    // max supported version\r
+    if (packet->context->is_server)\r
+        *(unsigned short *)&rand_bytes[0] = htons(packet->context->version);\r
+    else\r
+    if (packet->context->dtls)\r
+        *(unsigned short *)&rand_bytes[0] = htons(DTLS_V12);\r
+    else\r
+        *(unsigned short *)&rand_bytes[0] = htons(TLS_V12);\r
+    //DEBUG_DUMP_HEX_LABEL("PREMASTER KEY", rand_bytes, bytes);\r
+    \r
+    TLS_FREE(packet->context->premaster_key);\r
+    packet->context->premaster_key = (unsigned char *)TLS_MALLOC(bytes);\r
+    if (!packet->context->premaster_key)\r
+        return TLS_NO_MEMORY;\r
+    \r
+    packet->context->premaster_key_len = bytes;\r
+    memcpy(packet->context->premaster_key, rand_bytes, packet->context->premaster_key_len);\r
+    \r
+    unsigned int out_len;\r
+    unsigned char *random = __private_tls_encrypt_rsa(packet->context, packet->context->premaster_key, packet->context->premaster_key_len, &out_len);\r
+    \r
+    __private_tls_compute_key(packet->context, bytes);\r
+    if ((random) && (out_len > 2)) {\r
+        tls_packet_uint24(packet, out_len + 2);\r
+        if (packet->context->dtls)\r
+            __private_dtls_handshake_data(packet->context, packet, out_len + 2);\r
+        tls_packet_uint16(packet, out_len);\r
+        tls_packet_append(packet, random, out_len);\r
+    } else\r
+        res = TLS_GENERIC_ERROR;\r
+    TLS_FREE(random);\r
+    if (res)\r
+        return res;\r
+    \r
+    return out_len + 2;\r
+}\r
+\r
+const unsigned char *__private_tls_parse_signature(struct TLSContext *context, const unsigned char *buf, int buf_len, int *hash_algorithm, int *sign_algorithm, int *sig_size, int *offset) {\r
+    int res = 0;\r
+    CHECK_SIZE(2, buf_len, NULL)\r
+    *hash_algorithm = __md5_sha1;\r
+    *sign_algorithm = rsa_sign;\r
+    *sig_size = 0;\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        *hash_algorithm = buf[res];\r
+        res++;\r
+        *sign_algorithm = buf[res];\r
+        res++;\r
+    }\r
+    unsigned short size = ntohs(*(unsigned short *)&buf[res]);\r
+    res += 2;\r
+    CHECK_SIZE(size, buf_len - res, NULL)\r
+    DEBUG_DUMP_HEX(&buf[res], size);\r
+    *sig_size = size;\r
+    *offset = res + size;\r
+    return &buf[res];\r
+}\r
+\r
+int tls_parse_server_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len) {\r
+    int res = 0;\r
+    int dh_res = 0;\r
+    CHECK_SIZE(3, buf_len, TLS_NEED_MORE_DATA)\r
+    unsigned int size = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    res += 3;\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        res += 8;\r
+    }\r
+    const unsigned char *packet_ref = buf + res;\r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA);\r
+    \r
+    if (!size)\r
+        return res;\r
+    \r
+    unsigned char has_ds_params = 0;\r
+    unsigned int key_size = 0;\r
+#ifdef TLS_FORWARD_SECRECY\r
+    const struct ECCCurveParameters *curve = NULL;\r
+    const unsigned char *pk_key = NULL;\r
+    int ephemeral = tls_cipher_is_ephemeral(context);\r
+    if (ephemeral) {\r
+        if (ephemeral == 1) {\r
+            has_ds_params = 1;\r
+        } else {\r
+            if (buf[res++] != 3) {\r
+                // named curve\r
+                // any other method is not supported\r
+                return 0;\r
+            }\r
+            CHECK_SIZE(3, buf_len - res, TLS_NEED_MORE_DATA);\r
+            int iana_n = ntohs(*(unsigned short *)&buf[res]);\r
+            res += 2;\r
+            key_size = buf[res];\r
+            res++;\r
+            CHECK_SIZE(key_size, buf_len - res, TLS_NEED_MORE_DATA);\r
+            DEBUG_PRINT("IANA CURVE NUMBER: %i\n", iana_n);\r
+            switch (iana_n) {\r
+                case 19:\r
+                    curve = &secp192r1;\r
+                    break;\r
+                case 20:\r
+                    curve = &secp224k1;\r
+                    break;\r
+                case 21:\r
+                    curve = &secp224r1;\r
+                    break;\r
+                case 22:\r
+                    curve = &secp256k1;\r
+                    break;\r
+                case 23:\r
+                    curve = &secp256r1;\r
+                    break;\r
+                case 24:\r
+                    curve = &secp384r1;\r
+                    break;\r
+                case 25:\r
+                    curve = &secp521r1;\r
+                    break;\r
+                default:\r
+                    DEBUG_PRINT("UNSUPPORTED CURVE\n");\r
+                    return TLS_GENERIC_ERROR;\r
+            }\r
+            pk_key = &buf[res];\r
+            res += key_size;\r
+            context->curve = curve;\r
+        }\r
+    }\r
+#endif\r
+    const unsigned char *dh_p = NULL;\r
+    int dh_p_len = 0;\r
+    const unsigned char *dh_g = NULL;\r
+    int dh_g_len = 0;\r
+    const unsigned char *dh_Ys = NULL;\r
+    int dh_Ys_len = 0;\r
+    if (has_ds_params) {\r
+        DEBUG_PRINT("          dh_p: ");\r
+        dh_res = __private_tls_parse_dh(context, &buf[res], buf_len - res, &dh_p, &dh_p_len);\r
+        if (dh_res <= 0)\r
+            return TLS_BROKEN_PACKET;\r
+        res += dh_res;\r
+        DEBUG_PRINT("\n");\r
+        \r
+        DEBUG_PRINT("          dh_q: ");\r
+        dh_res = __private_tls_parse_dh(context, &buf[res], buf_len - res, &dh_g, &dh_g_len);\r
+        if (dh_res <= 0)\r
+            return TLS_BROKEN_PACKET;\r
+        res += dh_res;\r
+        DEBUG_PRINT("\n");\r
+        \r
+        DEBUG_PRINT("          dh_Ys: ");\r
+        dh_res = __private_tls_parse_dh(context, &buf[res], buf_len - res, &dh_Ys, &dh_Ys_len);\r
+        if (dh_res <= 0)\r
+            return TLS_BROKEN_PACKET;\r
+        res += dh_res;\r
+        DEBUG_PRINT("\n");\r
+    }\r
+    int sign_size;\r
+    int hash_algorithm;\r
+    int sign_algorithm;\r
+    int packet_size = res - 3;\r
+    if (context->dtls)\r
+        packet_size -= 8;\r
+    int offset = 0;\r
+    DEBUG_PRINT("          SIGNATURE (%i/%i/%i): ", packet_size, dh_res, key_size);\r
+    const unsigned char *signature = __private_tls_parse_signature(context, &buf[res], buf_len - res, &hash_algorithm, &sign_algorithm, &sign_size, &offset);\r
+    DEBUG_PRINT("\n");\r
+    if ((sign_size <= 0) || (!signature))\r
+        return TLS_BROKEN_PACKET;\r
+    res += offset;\r
+    // check signature\r
+    unsigned int message_len = packet_size + __TLS_CLIENT_RANDOM_SIZE + __TLS_SERVER_RANDOM_SIZE;\r
+    unsigned char *message = (unsigned char *)TLS_MALLOC(message_len);\r
+    if (message) {        \r
+        memcpy(message, context->local_random, __TLS_CLIENT_RANDOM_SIZE);\r
+        memcpy(message + __TLS_CLIENT_RANDOM_SIZE, context->remote_random, __TLS_SERVER_RANDOM_SIZE);\r
+        memcpy(message + __TLS_CLIENT_RANDOM_SIZE + __TLS_SERVER_RANDOM_SIZE, packet_ref, packet_size);\r
+#ifdef TLS_CLIENT_ECDSA\r
+        if (tls_is_ecdsa(context)) {\r
+            if (__private_tls_verify_ecdsa(context, hash_algorithm, signature, sign_size, message, message_len) != 1) {\r
+                DEBUG_PRINT("ECC Server signature FAILED!\n");\r
+                TLS_FREE(message);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+        } else \r
+#endif\r
+        {\r
+            if (__private_tls_verify_rsa(context, hash_algorithm, signature, sign_size, message, message_len) != 1) {\r
+                DEBUG_PRINT("Server signature FAILED!\n");\r
+                TLS_FREE(message);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+        }\r
+        TLS_FREE(message);\r
+    }\r
+    \r
+    if (buf_len - res) {\r
+        DEBUG_PRINT("EXTRA %i BYTES AT THE END OF MESSAGE\n", buf_len - res);\r
+        DEBUG_DUMP_HEX(&buf[res], buf_len - res);\r
+        DEBUG_PRINT("\n");\r
+    }\r
+#ifdef TLS_FORWARD_SECRECY\r
+    if (ephemeral == 1) {\r
+        __private_tls_dhe_create(context);\r
+        DEBUG_DUMP_HEX_LABEL("DHP", dh_p, dh_p_len);\r
+        DEBUG_DUMP_HEX_LABEL("DHG", dh_g, dh_g_len);\r
+        int dhe_key_size = dh_p_len;\r
+        if (dh_g_len > dh_p_len)\r
+            dhe_key_size = dh_g_len;\r
+        if (__private_tls_dh_make_key(dhe_key_size, context->dhe, (const char *)dh_p, (const char *)dh_g, dh_p_len, dh_g_len)) {\r
+            DEBUG_PRINT("ERROR CREATING DHE KEY\n");\r
+            TLS_FREE(context->dhe);\r
+            context->dhe = NULL;\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        \r
+        unsigned int dh_key_size = 0;\r
+        unsigned char *key = __private_tls_decrypt_dhe(context, dh_Ys, dh_Ys_len, &dh_key_size, 0);\r
+        DEBUG_DUMP_HEX_LABEL("DH COMMON SECRET", key, dh_key_size);\r
+        if ((key) && (dh_key_size)) {\r
+            TLS_FREE(context->premaster_key);\r
+            context->premaster_key = key;\r
+            context->premaster_key_len = dh_key_size;\r
+        }\r
+    } else\r
+    if ((ephemeral == 2) && (curve) && (pk_key) && (key_size)) {\r
+        tls_init();\r
+        __private_tls_ecc_dhe_create(context);\r
+        \r
+        ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&curve->dp;\r
+        if (ecc_make_key_ex(NULL, find_prng("sprng"), context->ecc_dhe, dp)) {\r
+            TLS_FREE(context->ecc_dhe);\r
+            context->ecc_dhe = NULL;\r
+            DEBUG_PRINT("Error generatic ECC key\n");\r
+            return TLS_GENERIC_ERROR;\r
+        }\r
+        \r
+        TLS_FREE(context->premaster_key);\r
+        context->premaster_key_len = 0;\r
+        \r
+        unsigned int out_len = 0;\r
+        context->premaster_key = __private_tls_decrypt_ecc_dhe(context, pk_key, key_size, &out_len, 0);\r
+        if (context->premaster_key)\r
+            context->premaster_key_len = out_len;\r
+    }\r
+#endif\r
+    return res;\r
+}\r
+\r
+int tls_parse_client_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len) {\r
+    if (context->connection_status != 1) {\r
+        DEBUG_PRINT("UNEXPECTED CLIENT KEY EXCHANGE MESSAGE (connections status: %i)\n", (int)context->connection_status);\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    }\r
+\r
+    int res = 0;\r
+    int dh_res = 0;\r
+    CHECK_SIZE(3, buf_len, TLS_NEED_MORE_DATA)\r
+    \r
+    unsigned int size = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    res += 3;\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        res += 8;\r
+    }\r
+\r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA);\r
+\r
+    if (!size)\r
+        return res;\r
+    \r
+    dh_res = __private_tls_parse_random(context, &buf[res], size);\r
+    if (dh_res <= 0) {\r
+        DEBUG_PRINT("broken key\n");\r
+        return TLS_BROKEN_PACKET;\r
+    }\r
+    DEBUG_PRINT("\n");\r
+    \r
+    res += size;\r
+    context->connection_status = 2;\r
+    return res;\r
+}\r
+\r
+int tls_parse_server_hello_done(struct TLSContext *context, const unsigned char *buf, int buf_len) {\r
+    int res = 0;\r
+    CHECK_SIZE(3, buf_len, TLS_NEED_MORE_DATA)\r
+    \r
+    unsigned int size = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    res += 3;\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        res += 8;\r
+    }\r
+    \r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA);\r
+    \r
+    res += size;\r
+    return res;\r
+}\r
+\r
+int tls_parse_finished(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets) {\r
+    if ((context->connection_status < 2) || (context->connection_status == 0xFF))  {\r
+        DEBUG_PRINT("UNEXPECTED HELLO MESSAGE\n");\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    }\r
+    \r
+    int res = 0;\r
+    *write_packets = 0;\r
+    CHECK_SIZE(3, buf_len, TLS_NEED_MORE_DATA)\r
+    \r
+    unsigned int size = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    res += 3;\r
+    if (context->dtls) {\r
+        int dtls_check = __private_dtls_check_packet(buf, buf_len);\r
+        if (dtls_check < 0)\r
+            return dtls_check;\r
+        res += 8;\r
+    }\r
+    \r
+    if (size < __TLS_MIN_FINISHED_OPAQUE_LEN) {\r
+        DEBUG_PRINT("Invalid finished pachet size: %i\n", size);\r
+        return TLS_BROKEN_PACKET;\r
+    }\r
+    \r
+    CHECK_SIZE(size, buf_len - res, TLS_NEED_MORE_DATA);\r
+    \r
+    // verify\r
+    unsigned char *out = (unsigned char *)TLS_MALLOC(size);\r
+    if (!out) {\r
+        DEBUG_PRINT("Error in TLS_MALLOC (%i bytes)\n", (int)size);\r
+        return TLS_NO_MEMORY;\r
+    }\r
+    \r
+    unsigned char hash[__TLS_MAX_SHA_SIZE];\r
+    unsigned int hash_len = __private_tls_get_hash(context, hash);\r
+    // server verifies client's message\r
+    if (context->is_server)\r
+        __private_tls_prf(context, out, size, context->master_key, context->master_key_len, (unsigned char *)"client finished", 15, hash, hash_len, NULL, 0);\r
+    else\r
+        __private_tls_prf(context, out, size, context->master_key, context->master_key_len, (unsigned char *)"server finished", 15, hash, hash_len, NULL, 0);\r
+    \r
+    //unsigned char hash2[__TLS_HASH_SIZE];\r
+    //hash_len = __private_tls_get_hash(context, hash2);\r
+    //int x = memcmp(hash, hash2, __TLS_HASH_SIZE);\r
+    //DEBUG_PRINT("MEMCMP RESULT: %i\n", x);\r
+    if (memcmp(out, &buf[res], size)) {\r
+        TLS_FREE(out);\r
+        DEBUG_PRINT("Finished validation error (sequence number, local: %i, remote: %i)\n", (int)context->local_sequence_number, (int)context->remote_sequence_number);\r
+        DEBUG_DUMP_HEX_LABEL("FINISHED OPAQUE", &buf[res], size);\r
+        DEBUG_DUMP_HEX_LABEL("VERIFY", out, size);\r
+        return TLS_NOT_VERIFIED;\r
+    }\r
+    TLS_FREE(out);\r
+    if (context->is_server)\r
+        *write_packets = 3;\r
+    else\r
+        context->connection_status = 0xFF;\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+    if (size) {\r
+        if (context->is_server) {\r
+            TLS_FREE(context->verify_data);\r
+            context->verify_data = (unsigned char *)TLS_MALLOC(size);\r
+            if (context->verify_data) {\r
+                memcpy(context->verify_data, out, size);\r
+                context->verify_len = size;\r
+            }\r
+        } else {\r
+            // concatenate client verify and server verify\r
+            context->verify_data = (unsigned char *)TLS_REALLOC(context->verify_data, size);\r
+            if (context->verify_data) {\r
+                memcpy(context->verify_data + context->verify_len, out, size);\r
+                context->verify_len += size;\r
+            } else\r
+                context->verify_len = 0;\r
+        }\r
+    }\r
+#endif\r
+    res += size;\r
+    return res;\r
+}\r
+\r
+int tls_parse_verify(struct TLSContext *context, const unsigned char *buf, int buf_len) {\r
+    CHECK_SIZE(7, buf_len, TLS_BAD_CERTIFICATE)\r
+    unsigned int bytes_to_follow = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];\r
+    CHECK_SIZE(bytes_to_follow, buf_len - 3, TLS_BAD_CERTIFICATE)\r
+    int res = -1;\r
+\r
+    if ((context->version == TLS_V12) || (context->version == DTLS_V12)) {\r
+        unsigned int hash = buf[3];\r
+        unsigned int algorithm = buf[4];\r
+        if (algorithm != rsa)\r
+            return TLS_UNSUPPORTED_CERTIFICATE;\r
+        unsigned short size = ntohs(*(unsigned short *)&buf[5]);\r
+        CHECK_SIZE(size, bytes_to_follow - 4, TLS_BAD_CERTIFICATE)\r
+        DEBUG_PRINT("ALGORITHM %i/%i (%i)\n", hash, algorithm, (int)size);\r
+        DEBUG_DUMP_HEX_LABEL("VERIFY", &buf[7], bytes_to_follow - 7);\r
+        \r
+        res = __private_tls_verify_rsa(context, hash, &buf[7], size, context->cached_handshake, context->cached_handshake_len);\r
+    } else {\r
+#ifdef TLS_LEGACY_SUPPORT\r
+        unsigned short size = ntohs(*(unsigned short *)&buf[3]);\r
+        CHECK_SIZE(size, bytes_to_follow - 2, TLS_BAD_CERTIFICATE)\r
+        res = __private_tls_verify_rsa(context, md5, &buf[5], size, context->cached_handshake, context->cached_handshake_len);\r
+#endif\r
+    }\r
+    if (context->cached_handshake) {\r
+        // not needed anymore\r
+        TLS_FREE(context->cached_handshake);\r
+        context->cached_handshake = NULL;\r
+        context->cached_handshake_len = 0;\r
+    }\r
+    if (res == 1) {\r
+        DEBUG_PRINT("Signature OK\n");\r
+        context->client_verified = 1;\r
+    } else {\r
+        DEBUG_PRINT("Signature FAILED\n");\r
+        context->client_verified = 0;\r
+    }\r
+    return 1;\r
+}\r
+\r
+int tls_parse_payload(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify) {\r
+    int orig_len = buf_len;\r
+    if (context->connection_status == 0xFF) {\r
+#ifndef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+        // renegotiation disabled (emit warning alert)\r
+        __private_tls_write_packet(tls_build_alert(context, 0, no_renegotiation));\r
+        return 1;\r
+#endif\r
+    }\r
+\r
+    while ((buf_len >= 4) && (!context->critical_error)) {\r
+        int payload_res = 0;\r
+        unsigned char update_hash = 1;\r
+        CHECK_SIZE(1, buf_len, TLS_NEED_MORE_DATA)\r
+        unsigned char type = buf[0];\r
+        unsigned int write_packets = 0;\r
+        unsigned int dtls_cookie_verified = 0;\r
+        int certificate_verify_alert = no_error;\r
+        unsigned int payload_size = buf[1] * 0x10000 + buf[2] * 0x100 + buf[3] + 3;\r
+        if (context->dtls)\r
+            payload_size += 8;\r
+        CHECK_SIZE(payload_size + 1, buf_len, TLS_NEED_MORE_DATA)\r
+        switch (type) {\r
+                // hello request\r
+            case 0x00:\r
+                CHECK_HANDSHAKE_STATE(context, 0, 1);\r
+                DEBUG_PRINT(" => HELLO REQUEST (RENEGOTIATION?)\n");\r
+                if (context->dtls)\r
+                    context->dtls_seq = 0;\r
+                if (context->is_server)\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                else {\r
+                    if (context->connection_status == 0xFF) {\r
+                        // renegotiation\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+                        if (context->critical_error)\r
+                            payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                        else {\r
+                            __private_tls_reset_context(context);\r
+                            __private_tls_write_packet(tls_build_hello(context));\r
+                            return 1;\r
+                        }\r
+#else\r
+                        payload_res = TLS_NO_RENEGOTIATION;\r
+#endif\r
+                    } else\r
+                        payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                }\r
+                // no payload\r
+                break;\r
+                // client hello\r
+            case 0x01:\r
+                CHECK_HANDSHAKE_STATE(context, 1, (context->dtls ? 2 : 1));\r
+                DEBUG_PRINT(" => CLIENT HELLO\n");\r
+                if (context->is_server) {\r
+                    payload_res = tls_parse_hello(context, buf + 1, payload_size, &write_packets, &dtls_cookie_verified);\r
+                    DEBUG_PRINT(" => DTLS COOKIE VERIFIED: %i (%i)\n", dtls_cookie_verified, payload_res);\r
+                    if ((context->dtls) && (payload_res > 0) && (!dtls_cookie_verified) && (context->connection_status == 1)) {\r
+                        // wait client hello\r
+                        context->connection_status = 0;\r
+                        update_hash = 0;\r
+                    }\r
+                } else\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                break;\r
+                // server hello\r
+            case 0x02:\r
+                CHECK_HANDSHAKE_STATE(context, 2, 1);\r
+                DEBUG_PRINT(" => SERVER HELLO\n");\r
+                if (context->is_server)\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                else\r
+                    payload_res = tls_parse_hello(context, buf + 1, payload_size, &write_packets, &dtls_cookie_verified);\r
+                break;\r
+                // hello verify request\r
+            case 0x03:\r
+                DEBUG_PRINT(" => VERIFY REQUEST\n");\r
+                CHECK_HANDSHAKE_STATE(context, 3, 1);\r
+                if ((context->dtls) && (!context->is_server)) {\r
+                    payload_res = tls_parse_verify_request(context, buf + 1, payload_size, &write_packets);\r
+                    update_hash = 0;\r
+                } else\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                break;\r
+                // certificate\r
+            case 0x0B:\r
+                CHECK_HANDSHAKE_STATE(context, 4, 1);\r
+                DEBUG_PRINT(" => CERTIFICATE\n");\r
+                if (context->connection_status == 1) {\r
+                    if (context->is_server) {\r
+                        // client certificate\r
+                        payload_res = tls_parse_certificate(context, buf + 1, payload_size, 1);\r
+                        if ((certificate_verify) && (context->client_certificates_count))\r
+                            certificate_verify_alert = certificate_verify(context, context->client_certificates, context->client_certificates_count);\r
+                        // empty certificates are permitted for client\r
+                        if (payload_res <= 0)\r
+                            payload_res = 1;\r
+                    } else {\r
+                        payload_res = tls_parse_certificate(context, buf + 1, payload_size, 0);\r
+                        if ((certificate_verify) && (context->certificates_count))\r
+                            certificate_verify_alert = certificate_verify(context, context->certificates, context->certificates_count);\r
+                    }\r
+                } else\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                break;\r
+                // server key exchange\r
+            case 0x0C:\r
+                CHECK_HANDSHAKE_STATE(context, 5, 1);\r
+                DEBUG_PRINT(" => SERVER KEY EXCHANGE\n");\r
+                if (context->is_server)\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                else\r
+                    payload_res = tls_parse_server_key_exchange(context, buf + 1, payload_size);\r
+                break;\r
+                // certificate request\r
+            case 0x0D:\r
+                CHECK_HANDSHAKE_STATE(context, 6, 1);\r
+                // server to client\r
+                if (context->is_server)\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                else\r
+                    context->client_verified = 2;\r
+                DEBUG_PRINT(" => CERTIFICATE REQUEST\n");\r
+                break;\r
+                // server hello done\r
+            case 0x0E:\r
+                CHECK_HANDSHAKE_STATE(context, 7, 1);\r
+                DEBUG_PRINT(" => SERVER HELLO DONE\n");\r
+                if (context->is_server) {\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                } else {\r
+                    payload_res = tls_parse_server_hello_done(context, buf + 1, payload_size);\r
+                    if (payload_res > 0)\r
+                        write_packets = 1;\r
+                }\r
+                break;\r
+                // certificate verify\r
+            case 0x0F:\r
+                CHECK_HANDSHAKE_STATE(context, 8, 1);\r
+                DEBUG_PRINT(" => CERTIFICATE VERIFY\n");\r
+                if (context->connection_status == 2)\r
+                    payload_res = tls_parse_verify(context, buf + 1, payload_size);\r
+                else\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                break;\r
+                // client key exchange\r
+            case 0x10:\r
+                CHECK_HANDSHAKE_STATE(context, 9, 1);\r
+                DEBUG_PRINT(" => CLIENT KEY EXCHANGE\n");\r
+                if (context->is_server)\r
+                    payload_res = tls_parse_client_key_exchange(context, buf + 1, payload_size);\r
+                else\r
+                    payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                break;\r
+                // finished\r
+            case 0x14:\r
+                if (context->cached_handshake) {\r
+                    TLS_FREE(context->cached_handshake);\r
+                    context->cached_handshake = NULL;\r
+                    context->cached_handshake_len = 0;\r
+                }\r
+                CHECK_HANDSHAKE_STATE(context, 10, 1);\r
+                DEBUG_PRINT(" => FINISHED\n");\r
+                payload_res = tls_parse_finished(context, buf + 1, payload_size, &write_packets);\r
+                if (payload_res > 0)\r
+                    memset(context->hs_messages, 0, sizeof(context->hs_messages));\r
+                break;\r
+            default:\r
+                DEBUG_PRINT(" => NOT UNDERSTOOD PAYLOAD TYPE: %x\n", (int)type);\r
+                return TLS_NOT_UNDERSTOOD;\r
+        }\r
+        if ((type != 0x00) && (update_hash))\r
+            __private_tls_update_hash(context, buf, payload_size + 1);\r
+        \r
+        if (certificate_verify_alert != no_error) {\r
+            __private_tls_write_packet(tls_build_alert(context, 1, certificate_verify_alert));\r
+            context->critical_error = 1;\r
+        }\r
+        \r
+        if (payload_res < 0) {\r
+            switch (payload_res) {\r
+                case TLS_UNEXPECTED_MESSAGE:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, unexpected_message));\r
+                    break;\r
+                case TLS_COMPRESSION_NOT_SUPPORTED:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, decompression_failure));\r
+                    break;\r
+                case TLS_BROKEN_PACKET:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, decode_error));\r
+                    break;\r
+                case TLS_NO_MEMORY:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, internal_error));\r
+                    break;\r
+                case TLS_NOT_VERIFIED:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, bad_record_mac));\r
+                    break;\r
+                case TLS_BAD_CERTIFICATE:\r
+                    if (context->is_server) {\r
+                        // bad client certificate, continue\r
+                        __private_tls_write_packet(tls_build_alert(context, 0, bad_certificate));\r
+                        payload_res = 0;\r
+                    } else\r
+                        __private_tls_write_packet(tls_build_alert(context, 1, bad_certificate));\r
+                    break;\r
+                case TLS_UNSUPPORTED_CERTIFICATE:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, unsupported_certificate));\r
+                    break;\r
+                case TLS_NO_COMMON_CIPHER:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, insufficient_security));\r
+                    break;\r
+                case TLS_NOT_UNDERSTOOD:\r
+                    __private_tls_write_packet(tls_build_alert(context, 1, internal_error));\r
+                    break;\r
+                case TLS_NO_RENEGOTIATION:\r
+                    __private_tls_write_packet(tls_build_alert(context, 0, no_renegotiation));\r
+                    payload_res = 0;\r
+                    break;\r
+            }\r
+            if (payload_res < 0)\r
+                return payload_res;\r
+        }\r
+        if (certificate_verify_alert != no_error)\r
+            payload_res = TLS_BAD_CERTIFICATE;\r
+        \r
+        // except renegotiation\r
+        switch (write_packets) {\r
+            case 1:\r
+                if (context->client_verified == 2) {\r
+                    DEBUG_PRINT("<= Building CERTIFICATE \n");\r
+                    __private_tls_write_packet(tls_build_certificate(context));\r
+                    context->client_verified = 0;\r
+                }\r
+                // client handshake\r
+                DEBUG_PRINT("<= Building KEY EXCHANGE\n");\r
+                __private_tls_write_packet(tls_build_client_key_exchange(context));\r
+                DEBUG_PRINT("<= Building CHANGE CIPHER SPEC\n");\r
+                __private_tls_write_packet(tls_build_change_cipher_spec(context));\r
+                context->cipher_spec_set = 1;\r
+                context->local_sequence_number = 0;\r
+                DEBUG_PRINT("<= Building CLIENT FINISHED\n");\r
+                __private_tls_write_packet(tls_build_finished(context));\r
+                context->cipher_spec_set = 0;\r
+                break;\r
+            case 2:\r
+                // server handshake\r
+                if ((context->dtls) && (dtls_cookie_verified == 0)) {\r
+                    __private_tls_write_packet(tls_build_verify_request(context));\r
+                    __private_dtls_reset(context);\r
+                } else {\r
+                    DEBUG_PRINT("<= SENDING SERVER HELLO\n");\r
+                    __private_tls_write_packet(tls_build_hello(context));\r
+                    DEBUG_PRINT("<= SENDING CERTIFICATE\n");\r
+                    __private_tls_write_packet(tls_build_certificate(context));\r
+                    int ephemeral_cipher = tls_cipher_is_ephemeral(context);\r
+                    if (ephemeral_cipher) {\r
+                        DEBUG_PRINT("<= SENDING EPHEMERAL DH KEY\n");\r
+                        __private_tls_write_packet(tls_build_server_key_exchange(context, ephemeral_cipher == 1 ? KEA_dhe_rsa : KEA_ec_diffie_hellman));\r
+                    }\r
+                    if (context->request_client_certificate) {\r
+                        DEBUG_PRINT("<= SENDING CERTIFICATE REQUEST\n");\r
+                        __private_tls_write_packet(tls_certificate_request(context));\r
+                    }\r
+                    DEBUG_PRINT("<= SENDING DONE\n");\r
+                    __private_tls_write_packet(tls_build_done(context));\r
+                }\r
+                break;\r
+            case 3:\r
+                // finished\r
+                __private_tls_write_packet(tls_build_change_cipher_spec(context));\r
+                __private_tls_write_packet(tls_build_finished(context));\r
+                context->connection_status = 0xFF;\r
+                break;\r
+            case 4:\r
+                // dtls only\r
+                context->dtls_seq = 1;\r
+                __private_tls_write_packet(tls_build_hello(context));\r
+                break;\r
+        }\r
+        payload_size++;\r
+        buf += payload_size;\r
+        buf_len -= payload_size;\r
+    }\r
+    return orig_len;\r
+}\r
+\r
+unsigned int __private_tls_hmac_message(unsigned char local, struct TLSContext *context, const unsigned char *buf, int buf_len, const unsigned char *buf2, int buf_len2, unsigned char *out, unsigned int outlen, uint64_t remote_sequence_number) {\r
+    hmac_state hash;\r
+    int mac_size = outlen;\r
+    int hash_idx;\r
+    if (mac_size == __TLS_SHA1_MAC_SIZE)\r
+        hash_idx = find_hash("sha1");\r
+    else\r
+    if (mac_size == __TLS_SHA384_MAC_SIZE)\r
+        hash_idx = find_hash("sha384");\r
+    else\r
+        hash_idx = find_hash("sha256");\r
+    \r
+    if (hmac_init(&hash, hash_idx, local ? context->crypto.ctx_local_mac.local_mac : context->crypto.ctx_remote_mac.remote_mac, mac_size))\r
+        return 0;\r
+\r
+    uint64_t squence_number;\r
+    if (context->dtls)\r
+        squence_number = htonll(remote_sequence_number);\r
+    else\r
+    if (local)\r
+        squence_number = htonll(context->local_sequence_number);\r
+    else\r
+        squence_number = htonll(context->remote_sequence_number);\r
+\r
+    if (hmac_process(&hash, (unsigned char *)&squence_number, sizeof(uint64_t)))\r
+        return 0;\r
+    \r
+    if (hmac_process(&hash, buf, buf_len))\r
+        return 0;\r
+    if ((buf2) && (buf_len2)) {\r
+        if (hmac_process(&hash, buf2, buf_len2))\r
+            return 0;\r
+    }\r
+    unsigned long ref_outlen = outlen;\r
+    if (hmac_done(&hash, out, &ref_outlen))\r
+        return 0;\r
+    \r
+    return (unsigned int)ref_outlen;\r
+}\r
+\r
+int tls_parse_message(struct TLSContext *context, unsigned char *buf, int buf_len, tls_validation_function certificate_verify) {\r
+    int res = 5;\r
+    if (context->dtls)\r
+        res = 13;\r
+    int header_size = res;\r
+    int payload_res = 0;\r
+    \r
+    CHECK_SIZE(res, buf_len, TLS_NEED_MORE_DATA)\r
+    \r
+    unsigned char type = *buf;\r
+\r
+    int buf_pos = 1;\r
+\r
+    unsigned short version = ntohs(*(unsigned short *)&buf[buf_pos]);\r
+    buf_pos += 2;\r
+\r
+    uint64_t dtls_sequence_number = 0;\r
+    if (context->dtls) {\r
+        CHECK_SIZE(buf_pos + 8, buf_len, TLS_NEED_MORE_DATA)\r
+        dtls_sequence_number = ntohll(*(uint64_t *)&buf[buf_pos]);\r
+        buf_pos += 8;\r
+    }\r
+\r
+    VERSION_SUPPORTED(version, TLS_NOT_SAFE)\r
+    unsigned short length;\r
+    length = ntohs(*(unsigned short *)&buf[buf_pos]);\r
+    buf_pos += 2;\r
+\r
+    unsigned char *pt = NULL;\r
+    const unsigned char *ptr = buf + buf_pos;\r
+\r
+    CHECK_SIZE(buf_pos + length, buf_len, TLS_NEED_MORE_DATA)\r
+    DEBUG_PRINT("Message type: %0x, length: %i\n", (int)type, (int)length);\r
+    if (context->cipher_spec_set) {\r
+        DEBUG_DUMP_HEX_LABEL("encrypted", &buf[header_size], length);\r
+        if (!context->crypto.created) {\r
+            DEBUG_PRINT("Encryption context not created\n");\r
+            __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+            return TLS_BROKEN_PACKET;\r
+        }\r
+        pt = (unsigned char *)TLS_MALLOC(length);\r
+        if (!pt) {\r
+            DEBUG_PRINT("Error in TLS_MALLOC (%i bytes)\n", (int)length);\r
+            __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+            return TLS_NO_MEMORY;\r
+        }\r
+        unsigned char aad[16];\r
+        if (context->crypto.created == 2) {\r
+            int pt_length = length - 8 - __TLS_GCM_TAG_LEN;\r
+            if (pt_length < 0) {\r
+                DEBUG_PRINT("Invalid packet length");\r
+                TLS_FREE(pt);\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+            // build aad and iv\r
+            if (context->dtls)\r
+                *((uint64_t *)aad) = htonll(dtls_sequence_number);\r
+            else\r
+                *((uint64_t *)aad) = htonll(context->remote_sequence_number);\r
+            unsigned char iv[12];\r
+            memcpy(iv, context->crypto.ctx_remote_mac.remote_aead_iv, 4);\r
+            memcpy(iv + 4, buf + header_size, 8);\r
+            gcm_reset(&context->crypto.ctx_remote.aes_gcm_remote);\r
+            int res0 = gcm_add_iv(&context->crypto.ctx_remote.aes_gcm_remote, iv, 12);\r
+            \r
+            DEBUG_DUMP_HEX_LABEL("aad iv", iv, 12);\r
+            aad[8] = buf[0];\r
+            aad[9] = buf[1];\r
+            aad[10] = buf[2];\r
+            \r
+            *((unsigned short *)&aad[11]) = htons(pt_length);\r
+            int res1 = gcm_add_aad(&context->crypto.ctx_remote.aes_gcm_remote, aad, 13);\r
+            memset(pt, 0, length);\r
+            DEBUG_PRINT("PT SIZE: %i\n", pt_length);\r
+            int res2 = gcm_process(&context->crypto.ctx_remote.aes_gcm_remote, pt, pt_length, buf + header_size + 8, GCM_DECRYPT);\r
+            unsigned char tag[32];\r
+            unsigned long taglen = 32;\r
+            int res3 = gcm_done(&context->crypto.ctx_remote.aes_gcm_remote, tag, &taglen);\r
+            if ((res0) || (res1) || (res2) || (res3) || (taglen != __TLS_GCM_TAG_LEN)) {\r
+                DEBUG_PRINT("ERROR: gcm_add_iv: %i, gcm_add_aad: %i, gcm_process: %i, gcm_done: %i\n", res0, res1, res2, res3);\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+            DEBUG_DUMP_HEX_LABEL("decrypted", pt, pt_length);\r
+            DEBUG_DUMP_HEX_LABEL("tag", tag, taglen);\r
+            // check tag\r
+            if (memcmp(buf + header_size + 8 + pt_length, tag, taglen)) {\r
+                DEBUG_PRINT("INTEGRITY CHECK FAILED (msg length %i)\n", pt_length);\r
+                DEBUG_DUMP_HEX_LABEL("TAG RECEIVED", buf + header_size + 8 + pt_length, taglen);\r
+                DEBUG_DUMP_HEX_LABEL("TAG COMPUTED", tag, taglen);\r
+                TLS_FREE(pt);\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                __private_tls_write_packet(tls_build_alert(context, 1, bad_record_mac));\r
+                return TLS_INTEGRITY_FAILED;\r
+            }\r
+            ptr = pt;\r
+            length = pt_length;\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        } else\r
+        if (context->crypto.created == 3) {\r
+            int pt_length = length - POLY1305_TAGLEN;\r
+            unsigned int counter = 1;\r
+            unsigned char poly1305_key[POLY1305_KEYLEN];\r
+            unsigned char trail[16];\r
+            unsigned char mac_tag[POLY1305_TAGLEN];\r
+\r
+            if (pt_length < 0) {\r
+                DEBUG_PRINT("Invalid packet length");\r
+                TLS_FREE(pt);\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+            if (context->dtls)\r
+                *((uint64_t *)aad) = htonll(dtls_sequence_number);\r
+            else\r
+                *((uint64_t *)aad) = htonll(context->remote_sequence_number);\r
+            aad[8] = buf[0];\r
+            aad[9] = buf[1];\r
+            aad[10] = buf[2];\r
+            *((unsigned short *)&aad[11]) = htons(pt_length);\r
+            aad[13] = 0;\r
+            aad[14] = 0;\r
+            aad[15] = 0;\r
+\r
+            chacha_ivupdate(&context->crypto.ctx_remote.chacha_remote, context->crypto.ctx_remote_mac.remote_aead_iv, aad, (unsigned char *)&counter);\r
+\r
+            chacha_encrypt_bytes(&context->crypto.ctx_remote.chacha_remote, buf + header_size, pt, pt_length);\r
+            DEBUG_DUMP_HEX_LABEL("decrypted", pt, pt_length);\r
+            ptr = pt;\r
+            length = pt_length;\r
+\r
+            chacha20_poly1305_key(&context->crypto.ctx_remote.chacha_remote, poly1305_key);\r
+            poly1305_context ctx;\r
+            __private_tls_poly1305_init(&ctx, poly1305_key);\r
+            __private_tls_poly1305_update(&ctx, aad, 16);\r
+            __private_tls_poly1305_update(&ctx, buf + header_size, pt_length);\r
+            int rem = pt_length % 16;\r
+            if (rem) {\r
+                static unsigned char zeropad[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\r
+                __private_tls_poly1305_update(&ctx, zeropad, 16 - rem);\r
+            }\r
+            \r
+            __private_tls_U32TO8(&trail[0], 13);\r
+            *(int *)&trail[4] = 0;\r
+            __private_tls_U32TO8(&trail[8], pt_length);\r
+            *(int *)&trail[12] = 0;\r
+\r
+            __private_tls_poly1305_update(&ctx, trail, 16);\r
+            __private_tls_poly1305_finish(&ctx, mac_tag);\r
+            if (memcmp(mac_tag, buf + header_size + pt_length, POLY1305_TAGLEN)) {\r
+                DEBUG_PRINT("INTEGRITY CHECK FAILED (msg length %i)\n", length);\r
+                DEBUG_DUMP_HEX_LABEL("POLY1305 TAG RECEIVED", buf + header_size + pt_length, POLY1305_TAGLEN);\r
+                DEBUG_DUMP_HEX_LABEL("POLY1305 TAG COMPUTED", mac_tag, POLY1305_TAGLEN);\r
+                TLS_FREE(pt);\r
+\r
+                // silently ignore packet for DTLS\r
+                if (context->dtls)\r
+                    return header_size + length;\r
+\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                __private_tls_write_packet(tls_build_alert(context, 1, bad_record_mac));\r
+                return TLS_INTEGRITY_FAILED;\r
+            }\r
+#endif\r
+        } else {\r
+            int err = __private_tls_crypto_decrypt(context, buf + header_size, pt, length);\r
+            if (err) {\r
+                TLS_FREE(pt);\r
+                DEBUG_PRINT("Decryption error %i\n", (int)err);\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+            unsigned char padding_byte = pt[length - 1];\r
+            unsigned char padding = padding_byte + 1;\r
+            \r
+            // poodle check\r
+            int padding_index = length - padding;\r
+            if (padding_index > 0) {\r
+                int i;\r
+                int limit = length - 1;\r
+                for (i = length - padding; i < limit; i++) {\r
+                    if (pt[i] != padding_byte) {\r
+                        TLS_FREE(pt);\r
+                        DEBUG_PRINT("BROKEN PACKET (POODLE ?)\n");\r
+                        __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                        __private_tls_write_packet(tls_build_alert(context, 1, decrypt_error));\r
+                        return TLS_BROKEN_PACKET;\r
+                    }\r
+                }\r
+            }\r
+            \r
+            unsigned int decrypted_length = length;\r
+            if (padding < decrypted_length)\r
+                decrypted_length -= padding;\r
+            \r
+            DEBUG_DUMP_HEX_LABEL("decrypted", pt, decrypted_length);\r
+            ptr = pt;\r
+#ifdef TLS_LEGACY_SUPPORT\r
+            if ((context->version != TLS_V10) && (decrypted_length > __TLS_AES_IV_LENGTH)) {\r
+                decrypted_length -= __TLS_AES_IV_LENGTH;\r
+                ptr += __TLS_AES_IV_LENGTH;\r
+            }\r
+#else\r
+            if (decrypted_length > __TLS_AES_IV_LENGTH) {\r
+                decrypted_length -= __TLS_AES_IV_LENGTH;\r
+                ptr += __TLS_AES_IV_LENGTH;\r
+            }\r
+#endif\r
+            length = decrypted_length;\r
+            \r
+            unsigned int mac_size = __private_tls_mac_length(context);\r
+            if ((length < mac_size) || (!mac_size)) {\r
+                TLS_FREE(pt);\r
+                DEBUG_PRINT("BROKEN PACKET\n");\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                __private_tls_write_packet(tls_build_alert(context, 1, decrypt_error));\r
+                return TLS_BROKEN_PACKET;\r
+            }\r
+            \r
+            length -= mac_size;\r
+            \r
+            const unsigned char *message_hmac = &ptr[length];\r
+            unsigned char hmac_out[__TLS_MAX_MAC_SIZE];\r
+            unsigned char temp_buf[5];\r
+            memcpy(temp_buf, buf, 3);\r
+            *(unsigned short *)&temp_buf[3] = htons(length);\r
+            unsigned int hmac_out_len = __private_tls_hmac_message(0, context, temp_buf, 5, ptr, length, hmac_out, mac_size, dtls_sequence_number);\r
+            if ((hmac_out_len != mac_size) || (memcmp(message_hmac, hmac_out, mac_size))) {\r
+                DEBUG_PRINT("INTEGRITY CHECK FAILED (msg length %i)\n", length);\r
+                DEBUG_DUMP_HEX_LABEL("HMAC RECEIVED", message_hmac, mac_size);\r
+                DEBUG_DUMP_HEX_LABEL("HMAC COMPUTED", hmac_out, hmac_out_len);\r
+                TLS_FREE(pt);\r
+\r
+                // silently ignore packet for DTLS\r
+                if (context->dtls)\r
+                    return header_size + length;\r
+\r
+                __private_random_sleep(context, __TLS_MAX_ERROR_SLEEP_uS);\r
+                __private_tls_write_packet(tls_build_alert(context, 1, bad_record_mac));\r
+\r
+                return TLS_INTEGRITY_FAILED;\r
+            }\r
+        }\r
+    }\r
+    context->remote_sequence_number++;\r
+    \r
+    switch (type) {\r
+            // application data\r
+        case TLS_APPLICATION_DATA:\r
+            if (context->connection_status != 0xFF) {\r
+                DEBUG_PRINT("UNEXPECTED APPLICATION DATA MESSAGE\n");\r
+                payload_res = TLS_UNEXPECTED_MESSAGE;\r
+                __private_tls_write_packet(tls_build_alert(context, 1, unexpected_message));\r
+            } else {\r
+                DEBUG_PRINT("APPLICATION DATA MESSAGE (TLS VERSION: %x):\n", (int)context->version);\r
+                DEBUG_DUMP(ptr, length);\r
+                DEBUG_PRINT("\n");\r
+                __private_tls_write_app_data(context, ptr, length);\r
+            }\r
+            break;\r
+            // handshake\r
+        case TLS_HANDSHAKE:\r
+            DEBUG_PRINT("HANDSHAKE MESSAGE\n");\r
+            payload_res = tls_parse_payload(context, ptr, length, certificate_verify);\r
+            break;\r
+            // change cipher spec\r
+        case TLS_CHANGE_CIPHER:\r
+            context->dtls_epoch_remote++;\r
+            if (context->connection_status != 2) {\r
+                DEBUG_PRINT("UNEXPECTED CHANGE CIPHER SPEC MESSAGE (%i)\n", context->connection_status);\r
+                __private_tls_write_packet(tls_build_alert(context, 1, unexpected_message));\r
+                payload_res = TLS_UNEXPECTED_MESSAGE;\r
+            } else {\r
+                DEBUG_PRINT("CHANGE CIPHER SPEC MESSAGE\n");\r
+                context->cipher_spec_set = 1;\r
+                // reset sequence numbers\r
+                context->remote_sequence_number = 0;\r
+            }\r
+            break;\r
+            // alert\r
+        case TLS_ALERT:\r
+            DEBUG_PRINT("ALERT MESSAGE\n");\r
+            if (length >= 2) {\r
+                DEBUG_DUMP_HEX(ptr, length);\r
+                int level = ptr[0];\r
+                int code = ptr[1];\r
+                if (level == TLS_ALERT_CRITICAL) {\r
+                    context->critical_error = 1;\r
+                    res = TLS_ERROR_ALERT;\r
+                }\r
+                context->error_code = code;\r
+            }\r
+            break;\r
+        default:\r
+            DEBUG_PRINT("NOT UNDERSTOOD MESSAGE TYPE: %x\n", (int)type);\r
+            return TLS_NOT_UNDERSTOOD;\r
+    }\r
+    TLS_FREE(pt);\r
+    \r
+    if (payload_res < 0)\r
+        return payload_res;\r
+    \r
+    if (res > 0)\r
+        return header_size + length;\r
+    \r
+    return res;\r
+}\r
+\r
+unsigned int asn1_get_len(const unsigned char *buffer, int buf_len, unsigned int *octets) {\r
+    *octets = 0;\r
+    \r
+    if (buf_len < 1)\r
+        return 0;\r
+    \r
+    unsigned char size = buffer[0];\r
+    int i;\r
+    if (size & 0x80) {\r
+        *octets = size & 0x7F;\r
+        if ((int)*octets > buf_len - 1)\r
+            return 0;\r
+        // max 32 bits\r
+        unsigned int ref_octets = *octets;\r
+        if (*octets > 4)\r
+            ref_octets = 4;\r
+        if ((int)*octets > buf_len -1)\r
+            return 0;\r
+        unsigned int long_size = 0;\r
+        unsigned int coef = 1;\r
+        \r
+        for (i = ref_octets; i > 0; i--) {\r
+            long_size += buffer[i] * coef;\r
+            coef *= 0x100;\r
+        }\r
+        ++*octets;\r
+        return long_size;\r
+    }\r
+    ++*octets;\r
+    return size;\r
+}\r
+\r
+void print_index(const unsigned int *fields) {\r
+    int i = 0;\r
+    while (fields[i]) {\r
+        if (i)\r
+            DEBUG_PRINT(".");\r
+        DEBUG_PRINT("%i", fields[i]);\r
+        i++;\r
+    }\r
+    while (i < 6) {\r
+        DEBUG_PRINT("  ");\r
+        i++;\r
+    }\r
+}\r
+\r
+int __is_field(const unsigned int *fields, const unsigned int *prefix) {\r
+    int i = 0;\r
+    while (prefix[i]) {\r
+        if (fields[i] != prefix[i])\r
+            return 0;\r
+        i++;\r
+    }\r
+    return 1;\r
+}\r
+\r
+int __private_tls_hash_len(int algorithm) {\r
+    switch (algorithm) {\r
+        case TLS_RSA_SIGN_MD5:\r
+            return 16;\r
+        case TLS_RSA_SIGN_SHA1:\r
+            return 20;\r
+        case TLS_RSA_SIGN_SHA256:\r
+            return 32;\r
+        case TLS_RSA_SIGN_SHA384:\r
+            return 48;\r
+        case TLS_RSA_SIGN_SHA512:\r
+            return 64;\r
+    }\r
+    return 0;\r
+}\r
+\r
+unsigned char *__private_tls_compute_hash(int algorithm, const unsigned char *message, unsigned int message_len) {\r
+    unsigned char *hash = NULL;\r
+    if ((!message) || (!message_len))\r
+        return hash;\r
+    int err;\r
+    hash_state state;\r
+    switch (algorithm) {\r
+        case TLS_RSA_SIGN_MD5:\r
+            DEBUG_PRINT("SIGN MD5\n");\r
+            hash = (unsigned char *)TLS_MALLOC(16);\r
+            if (!hash)\r
+                return NULL;\r
+            \r
+            err = md5_init(&state);\r
+            if (!err) {\r
+                err = md5_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = md5_done(&state, hash);\r
+            }\r
+            break;\r
+        case TLS_RSA_SIGN_SHA1:\r
+            DEBUG_PRINT("SIGN SHA1\n");\r
+            hash = (unsigned char *)TLS_MALLOC(20);\r
+            if (!hash)\r
+                return NULL;\r
+            \r
+            err = sha1_init(&state);\r
+            if (!err) {\r
+                err = sha1_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha1_done(&state, hash);\r
+            }\r
+            break;\r
+        case TLS_RSA_SIGN_SHA256:\r
+            DEBUG_PRINT("SIGN SHA256\n");\r
+            hash = (unsigned char *)TLS_MALLOC(32);\r
+            if (!hash)\r
+                return NULL;\r
+            \r
+            err = sha256_init(&state);\r
+            if (!err) {\r
+                err = sha256_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha256_done(&state, hash);\r
+            }\r
+            break;\r
+        case TLS_RSA_SIGN_SHA384:\r
+            DEBUG_PRINT("SIGN SHA384\n");\r
+            hash = (unsigned char *)TLS_MALLOC(48);\r
+            if (!hash)\r
+                return NULL;\r
+            \r
+            err = sha384_init(&state);\r
+            if (!err) {\r
+                err = sha384_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha384_done(&state, hash);\r
+            }\r
+            break;\r
+        case TLS_RSA_SIGN_SHA512:\r
+            DEBUG_PRINT("SIGN SHA512\n");\r
+            hash = (unsigned char *)TLS_MALLOC(64);\r
+            if (!hash)\r
+                return NULL;\r
+            \r
+            err = sha512_init(&state);\r
+            if (!err) {\r
+                err = sha512_process(&state, message, message_len);\r
+                if (!err)\r
+                    err = sha512_done(&state, hash);\r
+            }\r
+            break;\r
+        default:\r
+            DEBUG_PRINT("UNKNOWN SIGNATURE ALGORITHM\n");\r
+    }\r
+    return hash;\r
+}\r
+\r
+int tls_certificate_verify_signature(struct TLSCertificate *cert, struct TLSCertificate *parent) {\r
+    if ((!cert) || (!parent) || (!cert->sign_key) || (!cert->fingerprint) || (!cert->sign_len) || (!parent->der_bytes) || (!parent->der_len)) {\r
+        DEBUG_PRINT("CANNOT VERIFY SIGNATURE");\r
+        return 0;\r
+    }\r
+    tls_init();\r
+    int hash_len = __private_tls_hash_len(cert->algorithm);\r
+    if (hash_len <= 0)\r
+        return 0;\r
+    \r
+    int hash_index = -1;\r
+    switch (cert->algorithm) {\r
+        case TLS_RSA_SIGN_MD5:\r
+            hash_index = find_hash("md5");\r
+            break;\r
+        case TLS_RSA_SIGN_SHA1:\r
+            hash_index = find_hash("sha1");\r
+            break;\r
+        case TLS_RSA_SIGN_SHA256:\r
+            hash_index = find_hash("sha256");\r
+            break;\r
+        case TLS_RSA_SIGN_SHA384:\r
+            hash_index = find_hash("sha384");\r
+            break;\r
+        case TLS_RSA_SIGN_SHA512:\r
+            hash_index = find_hash("sha512");\r
+            break;\r
+        default:\r
+            DEBUG_PRINT("UNKNOWN SIGNATURE ALGORITHM\n");\r
+            return 0;\r
+    }\r
+    \r
+    rsa_key key;\r
+    int err = rsa_import(parent->der_bytes, parent->der_len, &key);\r
+    if (err) {\r
+        DEBUG_PRINT("Error importing RSA certificate (code: %i)\n", err);\r
+        DEBUG_DUMP_HEX_LABEL("CERTIFICATE", parent->der_bytes, parent->der_len);\r
+        return 0;\r
+    }\r
+    int rsa_stat = 0;\r
+    unsigned char *signature = cert->sign_key;\r
+    int signature_len = cert->sign_len;\r
+    if (!signature[0]) {\r
+        signature++;\r
+        signature_len--;\r
+    }\r
+    err = rsa_verify_hash_ex(signature, signature_len, cert->fingerprint, hash_len, LTC_PKCS_1_V1_5, hash_index, 0, &rsa_stat, &key);\r
+    rsa_free(&key);\r
+    if (err) {\r
+        DEBUG_PRINT("HASH VERIFY ERROR %i\n", err);\r
+        return 0;\r
+    }\r
+    DEBUG_PRINT("CERTIFICATE VALIDATION: %i\n", rsa_stat);\r
+    return rsa_stat;\r
+}\r
+\r
+int tls_certificate_chain_is_valid(struct TLSCertificate **certificates, int len) {\r
+    if ((!certificates) || (!len))\r
+        return bad_certificate;\r
+    \r
+    int i;\r
+    len--;\r
+    \r
+    // expired certificate or not yet valid ?\r
+    if (tls_certificate_is_valid(certificates[0]))\r
+        return bad_certificate;\r
+    \r
+    // check\r
+    for (i = 0; i < len; i++) {\r
+        // certificate in chain is expired ?\r
+        if (tls_certificate_is_valid(certificates[i+1]))\r
+            return bad_certificate;\r
+        if (!tls_certificate_verify_signature(certificates[i], certificates[i+1]))\r
+            return bad_certificate;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int tls_certificate_chain_is_valid_root(struct TLSContext *context, struct TLSCertificate **certificates, int len) {\r
+    if ((!certificates) || (!len) || (!context->root_certificates) || (!context->root_count))\r
+        return bad_certificate;\r
+    int i;\r
+    unsigned int j;\r
+    for (i = 0; i < len; i++) {\r
+        for (j = 0; j < context->root_count; j++) {\r
+            // check if root certificate expired\r
+            if (tls_certificate_is_valid(context->root_certificates[j]))\r
+                continue;\r
+            // if any root validates any certificate in the chain, then is root validated\r
+            if (tls_certificate_verify_signature(certificates[i], context->root_certificates[j]))\r
+                return 0;\r
+        }\r
+    }\r
+    return bad_certificate;\r
+}\r
+\r
+int __private_is_oid(struct __private_OID_chain *ref_chain, const unsigned char *looked_oid, int looked_oid_len) {\r
+    while (ref_chain) {\r
+        if (ref_chain->oid) {\r
+            if (__is_oid2(ref_chain->oid, looked_oid, 16, looked_oid_len))\r
+                return 1;\r
+        }\r
+        ref_chain = (struct __private_OID_chain *)ref_chain->top;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int __private_asn1_parse(struct TLSContext *context, struct TLSCertificate *cert, const unsigned char *buffer, int size, int level, unsigned int *fields, unsigned char *has_key, int client_cert, unsigned char *top_oid, struct __private_OID_chain *chain) {\r
+    struct __private_OID_chain local_chain;\r
+    local_chain.top = chain;\r
+    int pos = 0;\r
+    // X.690\r
+    int idx = 0;\r
+    unsigned char oid[16];\r
+    memset(oid, 0, 16);\r
+    local_chain.oid = oid;\r
+    if (has_key)\r
+        *has_key = 0;\r
+    unsigned char local_has_key = 0;\r
+    const unsigned char *cert_data = NULL;\r
+    unsigned int cert_len = 0;\r
+    while (pos < size) {\r
+        unsigned int start_pos = pos;\r
+        CHECK_SIZE(2, size - pos, TLS_NEED_MORE_DATA)\r
+        unsigned char first = buffer[pos++];\r
+        unsigned char type = first & 0x1F;\r
+        unsigned char constructed = first & 0x20;\r
+        unsigned char element_class = first >> 6;\r
+        unsigned int octets = 0;\r
+        unsigned int temp;\r
+        idx++;\r
+        if (level <= __TLS_ASN1_MAXLEVEL)\r
+            fields[level - 1] = idx;\r
+        unsigned int length = asn1_get_len((unsigned char *)&buffer[pos], size - pos, &octets);\r
+        if ((octets > 4) || (octets > size - pos))  {\r
+            DEBUG_PRINT("CANNOT READ CERTIFICATE\n");\r
+            return pos;\r
+        }\r
+        pos += octets;\r
+        CHECK_SIZE(length, size - pos, TLS_NEED_MORE_DATA)\r
+        //DEBUG_PRINT("FIRST: %x => %x (%i)\n", (int)first, (int)type, length);\r
+        // sequence\r
+        //DEBUG_PRINT("%2i: ", level);\r
+#ifdef DEBUG\r
+        DEBUG_INDEX(fields);\r
+        int i1;\r
+        for (i1 = 1; i1 < level; i1++)\r
+            DEBUG_PRINT("  ");\r
+#endif\r
+        \r
+        if ((length) && (constructed)) {\r
+            switch (type) {\r
+                case 0x03:\r
+                    DEBUG_PRINT("CONSTRUCTED BITSTREAM\n");\r
+                    break;\r
+                case 0x10:\r
+                    DEBUG_PRINT("SEQUENCE\n");\r
+                    if ((level == 2) && (idx == 1)) {\r
+                        cert_len = length + (pos - start_pos);\r
+                        cert_data = &buffer[start_pos];\r
+                    }\r
+                    // private key on server or public key on client\r
+                    if ((!cert->version) && (__is_field(fields, priv_der_id))) {\r
+                        TLS_FREE(cert->der_bytes);\r
+                        temp = length + (pos - start_pos);\r
+                        cert->der_bytes = (unsigned char *)TLS_MALLOC(temp);\r
+                        if (cert->der_bytes) {\r
+                            memcpy(cert->der_bytes, &buffer[start_pos], temp);\r
+                            cert->der_len = temp;\r
+                        } else\r
+                            cert->der_len = 0;\r
+                    }\r
+                    break;\r
+                case 0x11:\r
+                    DEBUG_PRINT("EMBEDDED PDV\n");\r
+                    break;\r
+                case 0x00:\r
+                    if (element_class == 0x02) {\r
+                        DEBUG_PRINT("CONTEXT-SPECIFIC\n");\r
+                        break;\r
+                    }\r
+                default:\r
+                    DEBUG_PRINT("CONSTRUCT TYPE %02X\n", (int)type);\r
+            }\r
+            local_has_key = 0;\r
+            __private_asn1_parse(context, cert, &buffer[pos], length, level + 1, fields, &local_has_key, client_cert, top_oid, &local_chain);\r
+            if ((((local_has_key) && (context) && ((!context->is_server) || (client_cert))) || (!context)) && (__is_field(fields, pk_id))) {\r
+                TLS_FREE(cert->der_bytes);\r
+                temp = length + (pos - start_pos);\r
+                cert->der_bytes = (unsigned char *)TLS_MALLOC(temp);\r
+                if (cert->der_bytes) {\r
+                    memcpy(cert->der_bytes, &buffer[start_pos], temp);\r
+                    cert->der_len = temp;\r
+                } else\r
+                    cert->der_len = 0;\r
+            }\r
+        } else {\r
+            switch (type) {\r
+                case 0x00:\r
+                    // end of content\r
+                    DEBUG_PRINT("END OF CONTENT\n");\r
+                    return pos;\r
+                    break;\r
+                case 0x01:\r
+                    // boolean\r
+                    temp = buffer[pos];\r
+                    DEBUG_PRINT("BOOLEAN: %i\n", temp);\r
+                    break;\r
+                case 0x02:\r
+                    // integer\r
+                    if (__is_field(fields, pk_id)) {\r
+                        if (has_key)\r
+                            *has_key = 1;\r
+                        \r
+                        if (idx == 1)\r
+                            tls_certificate_set_key(cert, &buffer[pos], length);\r
+                        else\r
+                        if (idx == 2)\r
+                            tls_certificate_set_exponent(cert, &buffer[pos], length);\r
+                    } else\r
+                    if (__is_field(fields, serial_id))\r
+                        tls_certificate_set_serial(cert, &buffer[pos], length);\r
+                    if (__is_field(fields, version_id)) {\r
+                        if (length == 1)\r
+                            cert->version = buffer[pos];\r
+#ifdef TLS_X509_V1_SUPPORT\r
+                        else\r
+                            cert->version = 0;\r
+                        idx++;\r
+#endif\r
+                    }\r
+                    if (level >= 2) {\r
+                        unsigned int fields_temp[3];\r
+                        fields_temp[0] = fields[level - 2];\r
+                        fields_temp[1] = fields[level - 1];\r
+                        fields_temp[2] = 0;\r
+                        if (__is_field(fields_temp, priv_id))\r
+                            tls_certificate_set_priv(cert, &buffer[pos], length);\r
+                    }\r
+                    DEBUG_PRINT("INTEGER(%i): ", length);\r
+                    DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                    if ((chain) && (length > 2)) {\r
+                        if (__private_is_oid(chain, san_oid, sizeof(san_oid) - 1)) {\r
+                            cert->san = (unsigned char **)TLS_REALLOC(cert->san, sizeof(unsigned char *) * (cert->san_length + 1));\r
+                            if (cert->san) {\r
+                                cert->san[cert->san_length] = NULL;\r
+                                tls_certificate_set_copy(&cert->san[cert->san_length], &buffer[pos], length);\r
+                                DEBUG_PRINT(" => SUBJECT ALTERNATIVE NAME: %s", cert->san[cert->san_length ]);\r
+                                cert->san_length++;\r
+                            } else\r
+                                cert->san_length = 0;\r
+                        }\r
+                    }\r
+                    DEBUG_PRINT("\n");\r
+                    break;\r
+                case 0x03:\r
+                    if (__is_field(fields, pk_id)) {\r
+                        if (has_key)\r
+                            *has_key = 1;                        \r
+                    }\r
+                    // bitstream\r
+                    DEBUG_PRINT("BITSTREAM(%i): ", length);\r
+                    DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                    DEBUG_PRINT("\n");\r
+                    if (__is_field(fields, sign_id)) {\r
+                        tls_certificate_set_sign_key(cert, &buffer[pos], length);\r
+                    } else\r
+                    if ((cert->ec_algorithm) && (__is_field(fields, pk_id))) {\r
+                        tls_certificate_set_key(cert, &buffer[pos], length);\r
+                    } else {\r
+                        if ((buffer[pos] == 0x00) && (length > 256))\r
+                            __private_asn1_parse(context, cert, &buffer[pos]+1, length - 1, level + 1, fields, &local_has_key, client_cert, top_oid, &local_chain);\r
+                        else\r
+                            __private_asn1_parse(context, cert, &buffer[pos], length, level + 1, fields, &local_has_key, client_cert, top_oid, &local_chain);\r
+#ifdef TLS_FORWARD_SECRECY\r
+    #ifdef TLS_ECDSA_SUPPORTED\r
+                        if (top_oid) {\r
+                            if (__is_oid2(top_oid, TLS_EC_prime256v1_OID, sizeof(oid), sizeof(TLS_EC_prime256v1) - 1)) {\r
+                                cert->ec_algorithm = secp256r1.iana;\r
+                            } else\r
+                            if (__is_oid2(top_oid, TLS_EC_secp224r1_OID, sizeof(oid), sizeof(TLS_EC_secp224r1_OID) - 1)) {\r
+                                cert->ec_algorithm = secp224r1.iana;\r
+                            } else\r
+                            if (__is_oid2(top_oid, TLS_EC_secp384r1_OID, sizeof(oid), sizeof(TLS_EC_secp384r1_OID) - 1)) {\r
+                                cert->ec_algorithm = secp384r1.iana;\r
+                            } else\r
+                            if (__is_oid2(top_oid, TLS_EC_secp521r1_OID, sizeof(oid), sizeof(TLS_EC_secp521r1_OID) - 1)) {\r
+                                cert->ec_algorithm = secp521r1.iana;\r
+                            }\r
+                            if ((cert->ec_algorithm) && (!cert->pk))\r
+                                tls_certificate_set_key(cert, &buffer[pos], length);\r
+                        }\r
+    #endif\r
+#endif\r
+                    }\r
+                    break;\r
+                case 0x04:\r
+                    if ((top_oid) && (__is_field(fields, ecc_priv_id)) && (!cert->priv)) {\r
+                        DEBUG_PRINT("BINARY STRING(%i): ", length);\r
+                        DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                        DEBUG_PRINT("\n");\r
+                        tls_certificate_set_priv(cert, &buffer[pos], length);\r
+                    } else\r
+                        __private_asn1_parse(context, cert, &buffer[pos], length, level + 1, fields, &local_has_key, client_cert, top_oid, &local_chain);\r
+                    break;\r
+                case 0x05:\r
+                    DEBUG_PRINT("NULL\n");\r
+                    break;\r
+                case 0x06:\r
+                    // object identifier\r
+                    if (__is_field(fields, pk_id)) {\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+                        if ((length == 8) || (length == 5))\r
+                            tls_certificate_set_algorithm(&cert->ec_algorithm, &buffer[pos], length);\r
+                        else\r
+#endif\r
+                            tls_certificate_set_algorithm(&cert->key_algorithm, &buffer[pos], length);\r
+                    }\r
+                    if (__is_field(fields, algorithm_id))\r
+                        tls_certificate_set_algorithm(&cert->algorithm, &buffer[pos], length);\r
+                    \r
+                    DEBUG_PRINT("OBJECT IDENTIFIER(%i): ", length);\r
+                    DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                    DEBUG_PRINT("\n");\r
+                    // check previous oid\r
+                    if (__is_oid2(oid, ocsp_oid, 16, sizeof(ocsp_oid) - 1))\r
+                        tls_certificate_set_copy(&cert->ocsp, &buffer[pos], length);\r
+\r
+                    if (length < 16)\r
+                        memcpy(oid, &buffer[pos], length);\r
+                    else\r
+                        memcpy(oid, &buffer[pos], 16);\r
+                    if (top_oid)\r
+                        memcpy(top_oid, oid, 16);\r
+                    break;\r
+                case 0x09:\r
+                    DEBUG_PRINT("REAL NUMBER(%i): ", length);\r
+                    DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                    DEBUG_PRINT("\n");\r
+                    break;\r
+                case 0x17:\r
+                    // utc time\r
+                    DEBUG_PRINT("UTC TIME: [");\r
+                    DEBUG_DUMP(&buffer[pos], length);\r
+                    DEBUG_PRINT("]\n");\r
+                    \r
+                    if (__is_field(fields, validity_id)) {\r
+                        if (idx == 1)\r
+                            tls_certificate_set_copy_date(&cert->not_before, &buffer[pos], length);\r
+                        else\r
+                            tls_certificate_set_copy_date(&cert->not_after, &buffer[pos], length);\r
+                    }\r
+                    break;\r
+                case 0x18:\r
+                    // generalized time\r
+                    DEBUG_PRINT("GENERALIZED TIME: [");\r
+                    DEBUG_DUMP(&buffer[pos], length);\r
+                    DEBUG_PRINT("]\n");\r
+                    break;\r
+                case 0x13:\r
+                    // printable string\r
+                case 0x0C:\r
+                case 0x14:\r
+                case 0x15:\r
+                case 0x16:\r
+                case 0x19:\r
+                case 0x1A:\r
+                case 0x1B:\r
+                case 0x1C:\r
+                case 0x1D:\r
+                case 0x1E:\r
+                    if (__is_field(fields, issurer_id)) {\r
+                        if (__is_oid(oid, country_oid, 3))\r
+                            tls_certificate_set_copy(&cert->issuer_country, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, state_oid, 3))\r
+                            tls_certificate_set_copy(&cert->issuer_state, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, location_oid, 3))\r
+                            tls_certificate_set_copy(&cert->issuer_location, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, entity_oid, 3))\r
+                            tls_certificate_set_copy(&cert->issuer_entity, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, subject_oid, 3))\r
+                            tls_certificate_set_copy(&cert->issuer_subject, &buffer[pos], length);\r
+                    } else\r
+                    if (__is_field(fields, owner_id)) {\r
+                        if (__is_oid(oid, country_oid, 3))\r
+                            tls_certificate_set_copy(&cert->country, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, state_oid, 3))\r
+                            tls_certificate_set_copy(&cert->state, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, location_oid, 3))\r
+                            tls_certificate_set_copy(&cert->location, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, entity_oid, 3))\r
+                            tls_certificate_set_copy(&cert->entity, &buffer[pos], length);\r
+                        else\r
+                        if (__is_oid(oid, subject_oid, 3))\r
+                            tls_certificate_set_copy(&cert->subject, &buffer[pos], length);\r
+                    }\r
+                    DEBUG_PRINT("STR: [");\r
+                    DEBUG_DUMP(&buffer[pos], length);\r
+                    DEBUG_PRINT("]\n");\r
+                    break;\r
+                case 0x10:\r
+                    DEBUG_PRINT("EMPTY SEQUENCE\n");\r
+                    break;\r
+                case 0xA:\r
+                    DEBUG_PRINT("ENUMERATED(%i): ", length);\r
+                    DEBUG_DUMP_HEX(&buffer[pos], length);\r
+                    DEBUG_PRINT("\n");\r
+                    break;\r
+                default:\r
+                    DEBUG_PRINT("========> NOT SUPPORTED %x\n", (int)type);\r
+                    // not supported / needed\r
+                    break;\r
+            }\r
+        }\r
+        pos += length;\r
+    }\r
+    if ((level == 2) && (cert->sign_key) && (cert->sign_len) && (cert_len) && (cert_data)) {\r
+        TLS_FREE(cert->fingerprint);\r
+        cert->fingerprint = __private_tls_compute_hash(cert->algorithm, cert_data, cert_len);\r
+#ifdef DEBUG\r
+        if (cert->fingerprint) {\r
+            DEBUG_DUMP_HEX_LABEL("FINGERPRINT", cert->fingerprint, __private_tls_hash_len(cert->algorithm));\r
+        }\r
+#endif\r
+    }\r
+    return pos;\r
+}\r
+\r
+struct TLSCertificate *asn1_parse(struct TLSContext *context, const unsigned char *buffer, int size, int client_cert) {\r
+    unsigned int fields[__TLS_ASN1_MAXLEVEL];\r
+    memset(fields, 0, sizeof(int) * __TLS_ASN1_MAXLEVEL);\r
+    struct TLSCertificate *cert = tls_create_certificate();\r
+    if (cert) {\r
+        if (client_cert < 0) {\r
+            client_cert = 0;\r
+            // private key\r
+            unsigned char top_oid[16];\r
+            memset(top_oid, 0, sizeof(top_oid));\r
+            __private_asn1_parse(context, cert, buffer, size, 1, fields, NULL, client_cert, top_oid, NULL);\r
+        } else\r
+            __private_asn1_parse(context, cert, buffer, size, 1, fields, NULL, client_cert, NULL, NULL);\r
+    }\r
+    return cert;\r
+}\r
+\r
+int tls_load_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    unsigned int len;\r
+    int idx = 0;\r
+    do {\r
+        unsigned char *data = tls_pem_decode(pem_buffer, pem_size, idx++, &len);\r
+        if ((!data) || (!len))\r
+            break;\r
+        struct TLSCertificate *cert = asn1_parse(context, data, len, 0);\r
+        if (cert) {\r
+            if ((cert->version == 2) \r
+#ifdef TLS_X509_V1_SUPPORT\r
+                || (cert->version == 0)\r
+#endif\r
+            ) {\r
+                TLS_FREE(cert->der_bytes);\r
+                cert->der_bytes = data;\r
+                cert->der_len = len;\r
+                data = NULL;\r
+                if (cert->priv) {\r
+                    DEBUG_PRINT("WARNING - parse error (private key encountered in certificate)\n");\r
+                    TLS_FREE(cert->priv);\r
+                    cert->priv = NULL;\r
+                    cert->priv_len = 0;\r
+                }\r
+                context->certificates = (struct TLSCertificate **)TLS_REALLOC(context->certificates, (context->certificates_count + 1) * sizeof(struct TLSCertificate));\r
+                context->certificates[context->certificates_count] = cert;\r
+                context->certificates_count++;\r
+                DEBUG_PRINT("Loaded certificate: %i\n", (int)context->certificates_count);\r
+            } else {\r
+                DEBUG_PRINT("WARNING - certificate version error (v%i)\n", (int)cert->version);\r
+                tls_destroy_certificate(cert);\r
+            }\r
+        }\r
+        TLS_FREE(data);\r
+    } while (1);\r
+    return context->certificates_count;\r
+}\r
+\r
+int tls_load_private_key(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    unsigned int len;\r
+    int idx = 0;\r
+    do {\r
+        unsigned char *data = tls_pem_decode(pem_buffer, pem_size, idx++, &len);\r
+        if ((!data) || (!len))\r
+            break;\r
+        struct TLSCertificate *cert = asn1_parse(context, data, len, -1);\r
+        if (cert) {\r
+            if (!cert->der_len) {\r
+                TLS_FREE(cert->der_bytes);\r
+                cert->der_bytes = data;\r
+                cert->der_len = len;\r
+            } else\r
+                TLS_FREE(data);\r
+            if ((cert) && (cert->priv) && (cert->priv_len)) {\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+                if (cert->ec_algorithm) {\r
+                    DEBUG_PRINT("Loaded ECC private key\n");\r
+                    if (context->ec_private_key)\r
+                        tls_destroy_certificate(context->ec_private_key);\r
+                    context->ec_private_key = cert;\r
+                    return 1;\r
+                } else\r
+#endif\r
+                {\r
+                    DEBUG_PRINT("Loaded private key\n");\r
+                    if (context->private_key)\r
+                        tls_destroy_certificate(context->private_key);\r
+                    context->private_key = cert;\r
+                    return 1;\r
+                }\r
+            }\r
+            tls_destroy_certificate(cert);\r
+        } else\r
+            TLS_FREE(data);\r
+    } while (1);\r
+    return 0;\r
+}\r
+\r
+int tls_clear_certificates(struct TLSContext *context) {\r
+    int i;\r
+    if ((!context) || (!context->is_server) || (context->is_child))\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    if (context->root_certificates) {\r
+        for (i = 0; i < context->root_count; i++)\r
+            tls_destroy_certificate(context->root_certificates[i]);\r
+    }\r
+    context->root_certificates = NULL;\r
+    context->root_count = 0;\r
+    if (context->private_key)\r
+        tls_destroy_certificate(context->private_key);\r
+    context->private_key = NULL;\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+    if (context->ec_private_key)\r
+        tls_destroy_certificate(context->ec_private_key);\r
+    context->ec_private_key = NULL;\r
+#endif\r
+    TLS_FREE(context->certificates);\r
+    context->certificates = NULL;\r
+    context->certificates_count = 0;\r
+    return 0;\r
+}\r
+\r
+struct TLSPacket *tls_build_certificate(struct TLSContext *context) {\r
+    int i;\r
+    unsigned int all_certificate_size = 0;\r
+    int certificates_count;\r
+    struct TLSCertificate **certificates;\r
+    if (context->is_server) {\r
+        certificates_count = context->certificates_count;\r
+        certificates = context->certificates;\r
+    } else {\r
+        certificates_count = context->client_certificates_count;\r
+        certificates = context->client_certificates;\r
+    }\r
+    \r
+#ifdef TLS_ECDSA_SUPPORTED\r
+    int is_ecdsa = tls_is_ecdsa(context);\r
+    if (is_ecdsa) {\r
+        for (i = 0; i < certificates_count; i++) {\r
+            struct TLSCertificate *cert = certificates[i];\r
+            if ((cert) && (cert->der_len) && (cert->ec_algorithm))\r
+                all_certificate_size += cert->der_len + 3;\r
+        }\r
+    } else {\r
+        for (i = 0; i < certificates_count; i++) {\r
+            struct TLSCertificate *cert = certificates[i];\r
+            if ((cert) && (cert->der_len) && (!cert->ec_algorithm))\r
+                all_certificate_size += cert->der_len + 3;\r
+        }\r
+    }\r
+#else\r
+    for (i = 0; i < certificates_count; i++) {\r
+        struct TLSCertificate *cert = certificates[i];\r
+        if ((cert) && (cert->der_len))\r
+            all_certificate_size += cert->der_len + 3;\r
+    }\r
+#endif\r
+    if (!all_certificate_size) {\r
+        DEBUG_PRINT("NO CERTIFICATE SET\n");\r
+        return NULL;\r
+    }\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);\r
+    tls_packet_uint8(packet, 0x0B);\r
+    if (all_certificate_size) {\r
+        tls_packet_uint24(packet, all_certificate_size + 3);\r
+\r
+        if (context->dtls)\r
+            __private_dtls_handshake_data(context, packet, all_certificate_size + 3);\r
+\r
+        tls_packet_uint24(packet, all_certificate_size);\r
+        for (i = 0; i < certificates_count; i++) {\r
+            struct TLSCertificate *cert = certificates[i];\r
+            if ((cert) && (cert->der_len)) {\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+                // is RSA certificate ?\r
+                if ((is_ecdsa) && (!cert->ec_algorithm))\r
+                    continue;\r
+                // is ECC certificate ?\r
+                if ((!is_ecdsa) && (cert->ec_algorithm))\r
+                    continue;\r
+#endif\r
+                // 2 times -> one certificate\r
+                tls_packet_uint24(packet, cert->der_len);\r
+                tls_packet_append(packet, cert->der_bytes, cert->der_len);\r
+            }\r
+        }\r
+    } else {\r
+        tls_packet_uint24(packet, all_certificate_size);\r
+        if (context->dtls)\r
+            __private_dtls_handshake_data(context, packet, all_certificate_size);\r
+    }\r
+    tls_packet_update(packet);\r
+    if (context->dtls)\r
+        context->dtls_seq++;\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_build_finished(struct TLSContext *context) {\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, __TLS_MIN_FINISHED_OPAQUE_LEN + 64);\r
+    tls_packet_uint8(packet, 0x14);\r
+    tls_packet_uint24(packet, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+    if (context->dtls)\r
+        __private_dtls_handshake_data(context, packet, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+    // verify\r
+    unsigned char hash[__TLS_MAX_HASH_SIZE];\r
+    unsigned char out[__TLS_MIN_FINISHED_OPAQUE_LEN];\r
+    unsigned int hash_len;\r
+    \r
+    // server verifies client's message\r
+    if (context->is_server) {\r
+        hash_len = __private_tls_done_hash(context, hash);\r
+        __private_tls_prf(context, out, __TLS_MIN_FINISHED_OPAQUE_LEN, context->master_key, context->master_key_len, (unsigned char *)"server finished", 15, hash, hash_len, NULL, 0);\r
+        __private_tls_destroy_hash(context);\r
+    } else {\r
+        hash_len = __private_tls_get_hash(context, hash);\r
+        __private_tls_prf(context, out, __TLS_MIN_FINISHED_OPAQUE_LEN, context->master_key, context->master_key_len, (unsigned char *)"client finished", 15, hash, hash_len, NULL, 0);\r
+    }\r
+    tls_packet_append(packet, out, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+    tls_packet_update(packet);\r
+    DEBUG_DUMP_HEX_LABEL("VERIFY DATA", out, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+#ifdef TLS_ACCEPT_SECURE_RENEGOTIATION\r
+    if (context->is_server) {\r
+        // concatenate client verify and server verify\r
+        context->verify_data = (unsigned char *)TLS_REALLOC(context->verify_data, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+        if (context->verify_data) {\r
+            memcpy(context->verify_data + context->verify_len, out, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+            context->verify_len += __TLS_MIN_FINISHED_OPAQUE_LEN;\r
+        } else\r
+            context->verify_len = 0;\r
+    } else {\r
+        TLS_FREE(context->verify_data);\r
+        context->verify_data = (unsigned char *)TLS_MALLOC(__TLS_MIN_FINISHED_OPAQUE_LEN);\r
+        if (context->verify_data) {\r
+            memcpy(context->verify_data, out, __TLS_MIN_FINISHED_OPAQUE_LEN);\r
+            context->verify_len = __TLS_MIN_FINISHED_OPAQUE_LEN;\r
+        }\r
+    }\r
+#endif\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_build_change_cipher_spec(struct TLSContext *context) {\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_CHANGE_CIPHER, context->version, 64);\r
+    tls_packet_uint8(packet, 1);\r
+    tls_packet_update(packet);\r
+    context->local_sequence_number = 0;\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_build_done(struct TLSContext *context) {\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);\r
+    tls_packet_uint8(packet, 0x0E);\r
+    tls_packet_uint24(packet, 0);\r
+    if (context->dtls) {\r
+        __private_dtls_handshake_data(context, packet, 0);\r
+        context->dtls_seq++;\r
+    }\r
+    tls_packet_update(packet);\r
+    return packet;\r
+}\r
+\r
+struct TLSPacket *tls_build_message(struct TLSContext *context, const unsigned char *data, unsigned int len) {\r
+    if ((!data) || (!len))\r
+        return 0;\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_APPLICATION_DATA, context->version, len);\r
+    tls_packet_append(packet, data, len);\r
+    tls_packet_update(packet);\r
+    return packet;\r
+}\r
+\r
+int tls_client_connect(struct TLSContext *context) {\r
+    if ((context->is_server) || (context->critical_error))\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    \r
+    return __private_tls_write_packet(tls_build_hello(context));\r
+}\r
+\r
+int tls_write(struct TLSContext *context, const unsigned char *data, unsigned int len) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    if (context->connection_status != 0xFF)\r
+        return TLS_UNEXPECTED_MESSAGE;\r
+    if (len > __TLS_MAX_TLS_APP_SIZE)\r
+        len = __TLS_MAX_TLS_APP_SIZE;\r
+    int actually_written = __private_tls_write_packet(tls_build_message(context, data, len));\r
+    if (actually_written <= 0)\r
+        return actually_written;\r
+    return len;\r
+}\r
+\r
+struct TLSPacket *tls_build_alert(struct TLSContext *context, char critical, unsigned char code) {\r
+    struct TLSPacket *packet = tls_create_packet(context, TLS_ALERT, context->version, 0);\r
+    tls_packet_uint8(packet, critical ? TLS_ALERT_CRITICAL : TLS_ALERT_WARNING);\r
+    if (critical)\r
+        context->critical_error = 1;\r
+    tls_packet_uint8(packet, code);\r
+    tls_packet_update(packet);\r
+    return packet;\r
+}\r
+\r
+int __private_tls_read_from_file(const char *fname, void *buf, int max_len) {\r
+    FILE *f = fopen(fname, "rb");\r
+    if (f) {\r
+        int size = fread(buf, 1, max_len, f);\r
+        fclose(f);\r
+        return size;\r
+    }\r
+    return 0;\r
+}\r
+\r
+int tls_consume_stream(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    if (context->critical_error)\r
+        return TLS_BROKEN_CONNECTION;\r
+\r
+    if (buf_len <= 0) {\r
+        DEBUG_PRINT("tls_consume_stream called with buf_len %i\n", buf_len);\r
+        return 0;\r
+    }\r
+\r
+    if (!buf) {\r
+        DEBUG_PRINT("tls_consume_stream called NULL buffer\n");\r
+        context->critical_error = 1;\r
+        return TLS_NO_MEMORY;\r
+    }\r
+\r
+    unsigned int orig_len = context->message_buffer_len;\r
+    context->message_buffer_len += buf_len;\r
+    context->message_buffer = (unsigned char *)TLS_REALLOC(context->message_buffer, context->message_buffer_len);\r
+    if (!context->message_buffer) {\r
+        context->message_buffer_len = 0;\r
+        return TLS_NO_MEMORY;\r
+    }\r
+    memcpy(context->message_buffer + orig_len, buf, buf_len);\r
+    unsigned int index = 0;\r
+    unsigned int tls_buffer_len = context->message_buffer_len;\r
+    int err_flag = 0;\r
+    \r
+    int tls_header_size;\r
+    int tls_size_offset;\r
+\r
+    if (context->dtls) {\r
+        tls_size_offset = 11;\r
+        tls_header_size = 13;\r
+    } else {\r
+        tls_size_offset = 3;\r
+        tls_header_size = 5;\r
+    }\r
+    while (tls_buffer_len >= 5) {\r
+        unsigned int length = ntohs(*(unsigned short *)&context->message_buffer[index + tls_size_offset]) + tls_header_size;\r
+        if (length > tls_buffer_len) {\r
+            DEBUG_PRINT("NEED DATA: %i/%i\n", length, tls_buffer_len);\r
+            break;\r
+        }\r
+        int consumed = tls_parse_message(context, &context->message_buffer[index], length, certificate_verify);\r
+        DEBUG_PRINT("Consumed %i bytes\n", consumed);\r
+        if (consumed < 0) {\r
+            if (!context->critical_error)\r
+                context->critical_error = 1;\r
+            err_flag = consumed;\r
+            break;\r
+        }\r
+        index += length;\r
+        tls_buffer_len -= length;\r
+        if (context->critical_error) {\r
+            err_flag = TLS_BROKEN_CONNECTION;\r
+            break;\r
+        }\r
+    }\r
+    if (err_flag) {\r
+        DEBUG_PRINT("ERROR IN CONSUME: %i\n", err_flag);\r
+        context->message_buffer_len = 0;\r
+        TLS_FREE(context->message_buffer);\r
+        context->message_buffer = NULL;\r
+        return err_flag;\r
+    }\r
+    if (index) {\r
+        context->message_buffer_len -= index;\r
+        if (context->message_buffer_len) {\r
+            // no realloc here\r
+            memmove(context->message_buffer, context->message_buffer + index, context->message_buffer_len);\r
+        } else {\r
+            TLS_FREE(context->message_buffer);\r
+            context->message_buffer = NULL;\r
+        }\r
+    }\r
+    return index;\r
+}\r
+\r
+void tls_close_notify(struct TLSContext *context) {\r
+    if ((!context) || (context->critical_error))\r
+        return;\r
+    context->critical_error = 1;\r
+    DEBUG_PRINT("CLOSE\n");\r
+    __private_tls_write_packet(tls_build_alert(context, 0, close_notify));\r
+}\r
+\r
+void tls_alert(struct TLSContext *context, unsigned char critical, int code) {\r
+    if (!context)\r
+        return;\r
+    if ((!context->critical_error) && (critical))\r
+        context->critical_error = 1;\r
+    DEBUG_PRINT("ALERT\n");\r
+    __private_tls_write_packet(tls_build_alert(context, critical, code));\r
+}\r
+\r
+int tls_pending(struct TLSContext *context) {\r
+    if (!context->message_buffer)\r
+        return 0;\r
+    return context->message_buffer_len;\r
+}\r
+\r
+void tls_make_exportable(struct TLSContext *context, unsigned char exportable_flag) {\r
+    context->exportable = exportable_flag;\r
+    if (!exportable_flag) {\r
+        // zero the memory\r
+        if ((context->exportable_keys) && (context->exportable_size))\r
+            memset(context->exportable_keys, 0, context->exportable_size);\r
+        // free the memory, if alocated\r
+        TLS_FREE(context->exportable_keys);\r
+        context->exportable_size = 0;\r
+    }\r
+}\r
+\r
+int tls_export_context(struct TLSContext *context, unsigned char *buffer, unsigned int buf_len, unsigned char small_version) {\r
+    // only negotiated AND exportable connections may be exported\r
+    if ((!context) || (context->critical_error) || (context->connection_status != 0xFF) || (!context->exportable) || (!context->exportable_keys) || (!context->exportable_size) || (!context->crypto.created)) {\r
+        DEBUG_PRINT("CANNOT EXPORT CONTEXT %i\n", (int)context->connection_status);\r
+        return 0;\r
+    }\r
+    \r
+    struct TLSPacket *packet = tls_create_packet(NULL, TLS_SERIALIZED_OBJECT, context->version, 0);\r
+    // export buffer version\r
+    tls_packet_uint8(packet, 0x01);\r
+    tls_packet_uint8(packet, context->connection_status);\r
+    tls_packet_uint16(packet, context->cipher);\r
+    if (context->is_child)\r
+        tls_packet_uint8(packet, 2);\r
+    else\r
+        tls_packet_uint8(packet, context->is_server);\r
+    \r
+    if (context->crypto.created == 2) {\r
+        // aead\r
+        tls_packet_uint8(packet, __TLS_AES_GCM_IV_LENGTH);\r
+        tls_packet_append(packet, context->crypto.ctx_local_mac.local_aead_iv, __TLS_AES_GCM_IV_LENGTH);\r
+        tls_packet_append(packet, context->crypto.ctx_remote_mac.remote_aead_iv, __TLS_AES_GCM_IV_LENGTH);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+    } else\r
+    if (context->crypto.created == 3) {\r
+        // ChaCha20\r
+        tls_packet_uint8(packet, __TLS_CHACHA20_IV_LENGTH);\r
+        tls_packet_append(packet, context->crypto.ctx_local_mac.local_nonce, __TLS_CHACHA20_IV_LENGTH);\r
+        tls_packet_append(packet, context->crypto.ctx_remote_mac.remote_nonce, __TLS_CHACHA20_IV_LENGTH);\r
+#endif\r
+    } else {\r
+        unsigned char iv[__TLS_AES_IV_LENGTH];\r
+        unsigned long len = __TLS_AES_IV_LENGTH;\r
+        \r
+        memset(iv, 0, __TLS_AES_IV_LENGTH);\r
+        cbc_getiv(iv, &len, &context->crypto.ctx_local.aes_local);\r
+        tls_packet_uint8(packet, __TLS_AES_IV_LENGTH);\r
+        tls_packet_append(packet, iv, len);\r
+        \r
+        memset(iv, 0, __TLS_AES_IV_LENGTH);\r
+        cbc_getiv(iv, &len, &context->crypto.ctx_remote.aes_remote);\r
+        tls_packet_append(packet, iv, __TLS_AES_IV_LENGTH);\r
+    }\r
+    \r
+    tls_packet_uint8(packet, context->exportable_size);\r
+    tls_packet_append(packet, context->exportable_keys, context->exportable_size);\r
+    \r
+    if (context->crypto.created == 2) {\r
+        tls_packet_uint8(packet, 0);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+    } else\r
+    if (context->crypto.created == 3) {\r
+        // ChaCha20\r
+        tls_packet_uint8(packet, 0);\r
+        unsigned int i;\r
+        for (i = 0; i < 16; i++)\r
+            tls_packet_uint32(packet, context->crypto.ctx_local.chacha_local.input[i]);\r
+        for (i = 0; i < 16; i++)\r
+            tls_packet_uint32(packet, context->crypto.ctx_remote.chacha_remote.input[i]);\r
+        tls_packet_append(packet, context->crypto.ctx_local.chacha_local.ks, CHACHA_BLOCKLEN);\r
+        tls_packet_append(packet, context->crypto.ctx_remote.chacha_remote.ks, CHACHA_BLOCKLEN);\r
+#endif\r
+    } else {\r
+        unsigned char mac_length = (unsigned char)__private_tls_mac_length(context);\r
+        tls_packet_uint8(packet, mac_length);\r
+        tls_packet_append(packet, context->crypto.ctx_local_mac.local_mac, mac_length);\r
+        tls_packet_append(packet, context->crypto.ctx_remote_mac.remote_mac, mac_length);\r
+    }\r
+    \r
+    if (small_version) {\r
+        tls_packet_uint16(packet, 0);\r
+    } else {\r
+        tls_packet_uint16(packet, context->master_key_len);\r
+        tls_packet_append(packet, context->master_key, context->master_key_len);\r
+    }\r
+    \r
+    uint64_t sequence_number = htonll(context->local_sequence_number);\r
+    tls_packet_append(packet, (unsigned char *)&sequence_number, sizeof(uint64_t));\r
+    sequence_number = htonll(context->remote_sequence_number);\r
+    tls_packet_append(packet, (unsigned char *)&sequence_number, sizeof(uint64_t));\r
+    \r
+    tls_packet_uint32(packet, context->tls_buffer_len);\r
+    tls_packet_append(packet, context->tls_buffer, context->tls_buffer_len);\r
+    \r
+    tls_packet_uint32(packet, context->message_buffer_len);\r
+    tls_packet_append(packet, context->message_buffer, context->message_buffer_len);\r
+    \r
+    tls_packet_uint32(packet, context->application_buffer_len);\r
+    tls_packet_append(packet, context->application_buffer, context->application_buffer_len);\r
+    tls_packet_uint8(packet, context->dtls);\r
+    if (context->dtls) {\r
+        tls_packet_uint16(packet, context->dtls_epoch_local);\r
+        tls_packet_uint16(packet, context->dtls_epoch_remote);\r
+    }\r
+    tls_packet_update(packet);\r
+    unsigned int size = packet->len;\r
+    if ((buffer) && (buf_len)) {\r
+        if (size > buf_len) {\r
+            tls_destroy_packet(packet);\r
+            DEBUG_PRINT("EXPORT BUFFER TO SMALL\n");\r
+            return (int)buf_len - (int)size;\r
+        }\r
+        memcpy(buffer, packet->buf, size);\r
+    }\r
+    tls_destroy_packet(packet);\r
+    return size;\r
+}\r
+\r
+struct TLSContext *tls_import_context(const unsigned char *buffer, unsigned int buf_len) {\r
+    if ((!buffer) || (buf_len < 64) || (buffer[0] != TLS_SERIALIZED_OBJECT) || (buffer[5] != 0x01)) {\r
+        DEBUG_PRINT("CANNOT IMPORT CONTEXT BUFFER\n");\r
+        return NULL;\r
+    }\r
+    // create a context object\r
+    struct TLSContext *context = tls_create_context(0, TLS_V12);\r
+    if (context) {\r
+        unsigned char temp[0xFF];\r
+        context->version = ntohs(*(unsigned short *)&buffer[1]);\r
+        unsigned short length = ntohs(*(unsigned short *)&buffer[3]);\r
+        if (length != buf_len - 5) {\r
+            DEBUG_PRINT("INVALID IMPORT BUFFER SIZE\n");\r
+            tls_destroy_context(context);\r
+            return NULL;\r
+        }\r
+        context->connection_status = buffer[6];\r
+        context->cipher = ntohs(*(unsigned short *)&buffer[7]);\r
+        unsigned char server = buffer[9];\r
+        if (server == 2) {\r
+            context->is_server = 1;\r
+            context->is_child = 1;\r
+        } else\r
+            context->is_server = server;\r
+        \r
+        unsigned char local_iv[__TLS_AES_IV_LENGTH];\r
+        unsigned char remote_iv[__TLS_AES_IV_LENGTH];\r
+        unsigned char iv_len = buffer[10];\r
+        if (iv_len >  __TLS_AES_IV_LENGTH) {\r
+            DEBUG_PRINT("INVALID IV LENGTH\n");\r
+            tls_destroy_context(context);\r
+            return NULL;\r
+        }\r
+        \r
+        // get the initialization vectors\r
+        int buf_pos = 11;\r
+        memcpy(local_iv, &buffer[buf_pos], iv_len);\r
+        buf_pos += iv_len;\r
+        memcpy(remote_iv, &buffer[buf_pos], iv_len);\r
+        buf_pos += iv_len;\r
+        \r
+        unsigned char key_lengths = buffer[buf_pos++];\r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, key_lengths, buf_len)\r
+        memcpy(temp, &buffer[buf_pos], key_lengths);\r
+        buf_pos += key_lengths;\r
+#ifdef TLS_REEXPORTABLE\r
+        context->exportable = 1;\r
+        context->exportable_keys = (unsigned char *)TLS_MALLOC(key_lengths);\r
+        memcpy(context->exportable_keys, temp, key_lengths);\r
+        context->exportable_size = key_lengths;\r
+#else\r
+        context->exportable = 0;\r
+#endif\r
+        int is_aead = __private_tls_is_aead(context);\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        if (is_aead == 2) {\r
+            // ChaCha20\r
+            if (iv_len > __TLS_CHACHA20_IV_LENGTH)\r
+                iv_len = __TLS_CHACHA20_IV_LENGTH;\r
+            memcpy(context->crypto.ctx_local_mac.local_nonce, local_iv, iv_len);\r
+            memcpy(context->crypto.ctx_remote_mac.remote_nonce, remote_iv, iv_len);\r
+        } else\r
+#endif\r
+        if (is_aead) {\r
+            if (iv_len > __TLS_AES_GCM_IV_LENGTH)\r
+                iv_len = __TLS_AES_GCM_IV_LENGTH;\r
+            memcpy(context->crypto.ctx_local_mac.local_aead_iv, local_iv, iv_len);\r
+            memcpy(context->crypto.ctx_remote_mac.remote_aead_iv, remote_iv, iv_len);\r
+        }\r
+        if (context->is_server) {\r
+            if (__private_tls_crypto_create(context, key_lengths / 2, iv_len, temp, local_iv, temp + key_lengths / 2, remote_iv)) {\r
+                DEBUG_PRINT("ERROR CREATING KEY CONTEXT\n");\r
+                tls_destroy_context(context);\r
+                return NULL;\r
+            }\r
+        } else {\r
+            if (__private_tls_crypto_create(context, key_lengths / 2, iv_len, temp + key_lengths / 2, remote_iv, temp, local_iv)) {\r
+                DEBUG_PRINT("ERROR CREATING KEY CONTEXT (CLIENT)\n");\r
+                tls_destroy_context(context);\r
+                return NULL;\r
+            }\r
+        }\r
+        memset(temp, 0, sizeof(temp));\r
+        \r
+        unsigned char mac_length = buffer[buf_pos++];\r
+        if (mac_length > __TLS_MAX_MAC_SIZE) {\r
+            DEBUG_PRINT("INVALID MAC SIZE\n");\r
+            tls_destroy_context(context);\r
+            return NULL;\r
+        }\r
+        \r
+        if (mac_length) {\r
+            TLS_IMPORT_CHECK_SIZE(buf_pos, mac_length, buf_len)\r
+            memcpy(context->crypto.ctx_local_mac.local_mac, &buffer[buf_pos], mac_length);\r
+            buf_pos += mac_length;\r
+            \r
+            TLS_IMPORT_CHECK_SIZE(buf_pos, mac_length, buf_len)\r
+            memcpy(context->crypto.ctx_remote_mac.remote_mac, &buffer[buf_pos], mac_length);\r
+            buf_pos += mac_length;\r
+        } else\r
+#ifdef TLS_WITH_CHACHA20_POLY1305\r
+        if (is_aead == 2) {\r
+            // ChaCha20\r
+            unsigned int i;\r
+            TLS_IMPORT_CHECK_SIZE(buf_pos, 128 + CHACHA_BLOCKLEN * 2, buf_len)\r
+            for (i = 0; i < 16; i++) {\r
+                context->crypto.ctx_local.chacha_local.input[i] = ntohl(*(unsigned int *)&buffer[buf_pos]);\r
+                buf_pos += sizeof(unsigned int);\r
+            }\r
+            for (i = 0; i < 16; i++) {\r
+                context->crypto.ctx_remote.chacha_remote.input[i] = ntohl(*(unsigned int *)&buffer[buf_pos]);\r
+                buf_pos += sizeof(unsigned int);\r
+            }\r
+            memcpy(context->crypto.ctx_local.chacha_local.ks, &buffer[buf_pos], CHACHA_BLOCKLEN);\r
+            buf_pos += CHACHA_BLOCKLEN;\r
+            memcpy(context->crypto.ctx_remote.chacha_remote.ks, &buffer[buf_pos], CHACHA_BLOCKLEN);\r
+            buf_pos += CHACHA_BLOCKLEN;\r
+        }\r
+#endif\r
+        \r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 2, buf_len)\r
+        unsigned short master_key_len = ntohs(*(unsigned short *)&buffer[buf_pos]);\r
+        buf_pos += 2;\r
+        if (master_key_len) {\r
+            TLS_IMPORT_CHECK_SIZE(buf_pos, master_key_len, buf_len)\r
+            context->master_key = (unsigned char *)TLS_MALLOC(master_key_len);\r
+            if (context->master_key) {\r
+                memcpy(context->master_key, &buffer[buf_pos], master_key_len);\r
+                context->master_key_len = master_key_len;\r
+            }\r
+            buf_pos += master_key_len;\r
+        }\r
+        \r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 16, buf_len)\r
+        \r
+        context->local_sequence_number = ntohll(*(uint64_t *)&buffer[buf_pos]);\r
+        buf_pos += 8;\r
+        context->remote_sequence_number = ntohll(*(uint64_t *)&buffer[buf_pos]);\r
+        buf_pos += 8;\r
+        \r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 4, buf_len)\r
+        unsigned int tls_buffer_len = ntohl(*(unsigned int *)&buffer[buf_pos]);\r
+        buf_pos += 4;\r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, tls_buffer_len, buf_len)\r
+        if (tls_buffer_len) {\r
+            context->tls_buffer = (unsigned char *)TLS_MALLOC(tls_buffer_len);\r
+            if (context->tls_buffer) {\r
+                memcpy(context->tls_buffer, &buffer[buf_pos], tls_buffer_len);\r
+                context->tls_buffer_len = tls_buffer_len;\r
+            }\r
+            buf_pos += tls_buffer_len;\r
+        }\r
+        \r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 4, buf_len)\r
+        unsigned int message_buffer_len = ntohl(*(unsigned int *)&buffer[buf_pos]);\r
+        buf_pos += 4;\r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, message_buffer_len, buf_len)\r
+        if (message_buffer_len) {\r
+            context->message_buffer = (unsigned char *)TLS_MALLOC(message_buffer_len);\r
+            if (context->message_buffer) {\r
+                memcpy(context->message_buffer, &buffer[buf_pos], message_buffer_len);\r
+                context->message_buffer_len = message_buffer_len;\r
+            }\r
+            buf_pos += message_buffer_len;\r
+        }\r
+        \r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 4, buf_len)\r
+        unsigned int application_buffer_len = ntohl(*(unsigned int *)&buffer[buf_pos]);\r
+        buf_pos += 4;\r
+        context->cipher_spec_set = 1;\r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, application_buffer_len, buf_len)\r
+        if (application_buffer_len) {\r
+            context->application_buffer = (unsigned char *)TLS_MALLOC(application_buffer_len);\r
+            if (context->application_buffer) {\r
+                memcpy(context->application_buffer, &buffer[buf_pos], application_buffer_len);\r
+                context->application_buffer_len = application_buffer_len;\r
+            }\r
+            buf_pos += application_buffer_len;\r
+        }\r
+        TLS_IMPORT_CHECK_SIZE(buf_pos, 1, buf_len)\r
+        context->dtls = buffer[buf_pos];\r
+        buf_pos++;\r
+        if (context->dtls) {\r
+            TLS_IMPORT_CHECK_SIZE(buf_pos, 4, buf_len)\r
+            context->dtls_epoch_local = ntohs(*(unsigned short *)&buffer[buf_pos]);\r
+            buf_pos += 2;\r
+            context->dtls_epoch_remote = ntohs(*(unsigned short *)&buffer[buf_pos]);\r
+        }\r
+    }\r
+    return context;\r
+}\r
+\r
+int tls_is_broken(struct TLSContext *context) {\r
+    if ((!context) || (context->critical_error))\r
+        return 1;\r
+    return 0;\r
+}\r
+\r
+int tls_request_client_certificate(struct TLSContext *context) {\r
+    if ((!context) || (!context->is_server))\r
+        return 0;\r
+    \r
+    context->request_client_certificate = 1;\r
+    return 1;\r
+}\r
+\r
+int tls_client_verified(struct TLSContext *context) {\r
+    if ((!context) || (context->critical_error))\r
+        return 0;\r
+    \r
+    return (context->client_verified == 1);\r
+}\r
+\r
+const char *tls_sni(struct TLSContext *context) {\r
+    if (!context)\r
+        return NULL;\r
+    return context->sni;\r
+}\r
+\r
+int tls_sni_set(struct TLSContext *context, const char *sni) {\r
+    if ((!context) || (context->is_server) || (context->critical_error) || (context->connection_status != 0))\r
+        return 0;\r
+    TLS_FREE(context->sni);\r
+    context->sni = NULL;\r
+    if (sni) {\r
+        int len = strlen(sni);\r
+        if (len > 0) {\r
+            context->sni = (char *)TLS_MALLOC(len + 1);\r
+            if (context->sni) {\r
+                context->sni[len] = 0;\r
+                memcpy(context->sni, sni, len);\r
+                return 1;\r
+            }\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+int tls_load_root_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    unsigned int len;\r
+    int idx = 0;\r
+    \r
+    do {\r
+        unsigned char *data = tls_pem_decode(pem_buffer, pem_size, idx++, &len);\r
+        if ((!data) || (!len))\r
+            break;\r
+        struct TLSCertificate *cert = asn1_parse(NULL, data, len, 0);\r
+        if (cert) {\r
+            if (cert->version == 2) {\r
+                if (cert->priv) {\r
+                    DEBUG_PRINT("WARNING - parse error (private key encountered in certificate)\n");\r
+                    TLS_FREE(cert->priv);\r
+                    cert->priv = NULL;\r
+                    cert->priv_len = 0;\r
+                }\r
+                context->root_certificates = (struct TLSCertificate **)TLS_REALLOC(context->root_certificates, (context->root_count + 1) * sizeof(struct TLSCertificate));\r
+                if (!context->root_certificates) {\r
+                    context->root_count = 0;\r
+                    return TLS_GENERIC_ERROR;\r
+                }\r
+                context->root_certificates[context->root_count] = cert;\r
+                context->root_count++;\r
+                DEBUG_PRINT("Loaded certificate: %i\n", (int)context->root_count);\r
+            } else {\r
+                DEBUG_PRINT("WARNING - certificate version error (v%i)\n", (int)cert->version);\r
+                tls_destroy_certificate(cert);\r
+            }\r
+        }\r
+        TLS_FREE(data);\r
+    } while (1);\r
+    return context->root_count;\r
+}\r
+\r
+int tls_default_verify(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len) {\r
+    int i;\r
+    int err;\r
+    \r
+    if (certificate_chain) {\r
+        for (i = 0; i < len; i++) {\r
+            struct TLSCertificate *certificate = certificate_chain[i];\r
+            // check validity date\r
+            err = tls_certificate_is_valid(certificate);\r
+            if (err)\r
+                return err;\r
+        }\r
+    }\r
+    // check if chain is valid\r
+    err = tls_certificate_chain_is_valid(certificate_chain, len);\r
+    if (err)\r
+        return err;\r
+    \r
+    // check certificate subject\r
+    if ((!context->is_server) && (context->sni) && (len > 0) && (certificate_chain)) {\r
+        err = tls_certificate_valid_subject(certificate_chain[0], context->sni);\r
+        if (err)\r
+            return err;\r
+    }\r
+    \r
+    err = tls_certificate_chain_is_valid_root(context, certificate_chain, len);\r
+    if (err)\r
+        return err;\r
+    \r
+    DEBUG_PRINT("Certificate OK\n");\r
+    return no_error;\r
+}\r
+\r
+int tls_unmake_ktls(struct TLSContext *context, int socket) {\r
+#ifdef WITH_KTLS\r
+    struct tls12_crypto_info_aes_gcm_128 crypto_info;\r
+    socklen_t crypt_info_size = sizeof(crypto_info);\r
+    if (getsockopt(socket, SOL_TLS, TLS_TX, &crypto_info, &crypt_info_size)) {\r
+        DEBUG_PRINT("ERROR IN getsockopt\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    memcpy(crypto_info.rec_seq, &context->local_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);\r
+    context->local_sequence_number = ntohll(context->local_sequence_number);\r
+    return 0;\r
+#endif\r
+    DEBUG_PRINT("TLSe COMPILED WITHOUT kTLS SUPPORT\n");\r
+    return TLS_FEATURE_NOT_SUPPORTED;\r
+}\r
+\r
+int tls_make_ktls(struct TLSContext *context, int socket) {\r
+    if ((!context) || (context->critical_error) || (context->connection_status != 0xFF) || (!context->crypto.created)) {\r
+        DEBUG_PRINT("CANNOT SWITCH TO kTLS\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    if ((!context->exportable) || (!context->exportable_keys)) {\r
+        DEBUG_PRINT("KEY MUST BE EXPORTABLE TO BE ABLE TO USE kTLS\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    if ((context->version != TLS_V12) && (context->version != DTLS_V12)) {\r
+        DEBUG_PRINT("kTLS IS SUPPORTED ONLY FOR TLS 1.2 AND DTLS 1.2\n");\r
+        return TLS_FEATURE_NOT_SUPPORTED;\r
+    }\r
+    switch (context->cipher) {\r
+        case TLS_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:\r
+        case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:\r
+            break;\r
+        default:\r
+            DEBUG_PRINT("CIPHER UNSUPPORTED: kTLS SUPPORTS ONLY AES 128 GCM CIPHERS\n");\r
+            return TLS_FEATURE_NOT_SUPPORTED;\r
+    }\r
+#ifdef WITH_KTLS\r
+    if (context->exportable_size < TLS_CIPHER_AES_GCM_128_KEY_SIZE) {\r
+        DEBUG_PRINT("INVALID KEY SIZE\n");\r
+        return TLS_GENERIC_ERROR;\r
+    }\r
+    struct tls12_crypto_info_aes_gcm_128 crypto_info;\r
+\r
+    crypto_info.info.version = TLS_1_2_VERSION;\r
+    crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128;\r
\r
+    uint64_t local_sequence_number = htonll(context->local_sequence_number);\r
+    memcpy(crypto_info.iv, &local_sequence_number, TLS_CIPHER_AES_GCM_128_IV_SIZE);\r
+    memcpy(crypto_info.rec_seq, &local_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);\r
+    memcpy(crypto_info.key, context->exportable_keys, TLS_CIPHER_AES_GCM_128_KEY_SIZE);\r
+    memcpy(crypto_info.salt, context->crypto.ctx_local_mac.local_aead_iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE);\r
+    setsockopt(socket, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));\r
+    return setsockopt(socket, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));\r
+#else\r
+    DEBUG_PRINT("TLSe COMPILED WITHOUT kTLS SUPPORT\n");\r
+    return TLS_FEATURE_NOT_SUPPORTED;\r
+#endif\r
+}\r
+\r
+#ifdef DEBUG\r
+void tls_print_certificate(const char *fname) {\r
+    unsigned char buf[0xFFFF];\r
+    char out_buf[0xFFFF];\r
+    int size = __private_tls_read_from_file(fname, buf, 0xFFFF);\r
+    if (size > 0) {\r
+        int idx = 0;\r
+        unsigned int len;\r
+        do {\r
+            unsigned char *data;\r
+            if (buf[0] == '-')  {\r
+                data = tls_pem_decode(buf, size, idx++, &len);\r
+            } else {\r
+                data = buf;\r
+                len = size;\r
+            }\r
+            if ((!data) || (!len))\r
+                return;\r
+            struct TLSCertificate *cert = asn1_parse(NULL, data, len, -1);\r
+            if (data != buf)\r
+                TLS_FREE(data);\r
+            if (cert) {\r
+                fprintf(stderr, "%s", tls_certificate_to_string(cert, out_buf, 0xFFFF));\r
+                tls_destroy_certificate(cert);\r
+            }\r
+            if (data == buf)\r
+                break;\r
+        } while (1);\r
+    }\r
+}\r
+#endif\r
+\r
+#ifdef SSL_COMPATIBLE_INTERFACE\r
+\r
+int  SSL_library_init() {\r
+    // dummy function\r
+    return 1;\r
+}\r
+\r
+void SSL_load_error_strings() {\r
+    // dummy function\r
+}\r
+\r
+void OpenSSL_add_all_algorithms() {\r
+    // dummy function\r
+}\r
+\r
+void OpenSSL_add_all_ciphers() {\r
+    // dummy function\r
+}\r
+\r
+void OpenSSL_add_all_digests() {\r
+    // dummy function\r
+}\r
+\r
+void EVP_cleanup() {\r
+    // dummy function\r
+}\r
+\r
+int __tls_ssl_private_send_pending(int client_sock, struct TLSContext *context) {\r
+    unsigned int out_buffer_len = 0;\r
+    const unsigned char *out_buffer = tls_get_write_buffer(context, &out_buffer_len);\r
+    unsigned int out_buffer_index = 0;\r
+    int send_res = 0;\r
+    SOCKET_SEND_CALLBACK write_cb = NULL;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (ssl_data)\r
+        write_cb = (SOCKET_SEND_CALLBACK)ssl_data->send;\r
+    while ((out_buffer) && (out_buffer_len > 0)) {\r
+        int res;\r
+        if (write_cb)\r
+            res = write_cb(client_sock, (char *)&out_buffer[out_buffer_index], out_buffer_len, 0);\r
+        else\r
+            res = send(client_sock, (char *)&out_buffer[out_buffer_index], out_buffer_len, 0);\r
+        if (res <= 0) {\r
+            send_res = res;\r
+            break;\r
+        }\r
+        out_buffer_len -= res;\r
+        out_buffer_index += res;\r
+        send_res += res;\r
+    }\r
+    tls_buffer_clear(context);\r
+    return send_res;\r
+}\r
+\r
+struct TLSContext *SSL_new(struct TLSContext *context) {\r
+    return tls_accept(context);\r
+}\r
+\r
+int SSLv3_server_method() {\r
+    return 1;\r
+}\r
+\r
+int SSLv3_client_method() {\r
+    return 0;\r
+}\r
+\r
+int SSL_CTX_use_certificate_file(struct TLSContext *context, const char *filename, int dummy) {\r
+    // max 64k buffer\r
+    unsigned char buf[0xFFFF];\r
+    int size = __private_tls_read_from_file(filename, buf, sizeof(buf));\r
+    if (size > 0)\r
+        return tls_load_certificates(context, buf, size);\r
+    return size;\r
+}\r
+\r
+int SSL_CTX_use_PrivateKey_file(struct TLSContext *context, const char *filename, int dummy) {\r
+    unsigned char buf[0xFFFF];\r
+    int size = __private_tls_read_from_file(filename, buf, sizeof(buf));\r
+    if (size > 0)\r
+        return tls_load_private_key(context, buf, size);\r
+    \r
+    return size;\r
+}\r
+\r
+int SSL_CTX_check_private_key(struct TLSContext *context) {\r
+    if ((!context) || (((!context->private_key) || (!context->private_key->der_bytes) || (!context->private_key->der_len))\r
+#ifdef TLS_ECDSA_SUPPORTED\r
+        && ((!context->ec_private_key) || (!context->ec_private_key->der_bytes) || (!context->ec_private_key->der_len))\r
+#endif\r
+    ))\r
+        return 0;\r
+    return 1;\r
+}\r
+\r
+struct TLSContext *SSL_CTX_new(int method) {\r
+    return tls_create_context(method, TLS_V12);\r
+}\r
+\r
+void SSL_free(struct TLSContext *context) {\r
+    if (context) {\r
+        TLS_FREE(context->user_data);\r
+        tls_destroy_context(context);\r
+    }\r
+}\r
+\r
+void SSL_CTX_free(struct TLSContext *context) {\r
+    SSL_free(context);\r
+}\r
+\r
+int SSL_get_error(struct TLSContext *context, int ret) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    return context->critical_error;\r
+}\r
+\r
+int SSL_set_fd(struct TLSContext *context, int socket) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (!ssl_data) {\r
+        ssl_data = (SSLUserData *)TLS_MALLOC(sizeof(SSLUserData));\r
+        if (!ssl_data)\r
+            return TLS_NO_MEMORY;\r
+        memset(ssl_data, 0, sizeof(SSLUserData));\r
+        context->user_data = ssl_data;\r
+    }\r
+    ssl_data->fd = socket;\r
+    return 0;\r
+}\r
+\r
+void *SSL_set_userdata(struct TLSContext *context, void *data) {\r
+    if (!context)\r
+        return NULL;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (!ssl_data) {\r
+        ssl_data = (SSLUserData *)TLS_MALLOC(sizeof(SSLUserData));\r
+        if (!ssl_data)\r
+            return NULL;\r
+        memset(ssl_data, 0, sizeof(SSLUserData));\r
+        context->user_data = ssl_data;\r
+    }\r
+    void *old_data = ssl_data->user_data;\r
+    ssl_data->user_data = data;\r
+    return old_data;\r
+}\r
+\r
+void *SSL_userdata(struct TLSContext *context) {\r
+    if (!context)\r
+        return NULL;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (!ssl_data)\r
+        return NULL;\r
+    \r
+    return ssl_data->user_data;\r
+}\r
+\r
+int SSL_CTX_root_ca(struct TLSContext *context, const char *pem_filename) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    int count = TLS_GENERIC_ERROR;\r
+    FILE *f = fopen(pem_filename, "rb");\r
+    if (f) {\r
+        fseek(f, 0, SEEK_END);\r
+        long size = ftell(f);\r
+        fseek(f, 0, SEEK_SET);\r
+        if (size) {\r
+            unsigned char *buf = (unsigned char *)TLS_MALLOC(size + 1);\r
+            if (buf) {\r
+                buf[size] = 1;\r
+                if (fread(buf, 1, size, f) == size) {\r
+                    count = tls_load_root_certificates(context, buf, size);\r
+                    if (count > 0) {\r
+                        SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+                        if (!ssl_data) {\r
+                            ssl_data = (SSLUserData *)TLS_MALLOC(sizeof(SSLUserData));\r
+                            if (!ssl_data)\r
+                                return TLS_NO_MEMORY;\r
+                            memset(ssl_data, 0, sizeof(SSLUserData));\r
+                            context->user_data = ssl_data;\r
+                        }\r
+                        if (!ssl_data->certificate_verify)\r
+                            ssl_data->certificate_verify = tls_default_verify;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        fclose(f);\r
+    }\r
+    return count;\r
+}\r
+\r
+void SSL_CTX_set_verify(struct TLSContext *context, int mode, tls_validation_function verify_callback) {\r
+    if (!context)\r
+        return;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (!ssl_data) {\r
+        ssl_data = (SSLUserData *)TLS_MALLOC(sizeof(SSLUserData));\r
+        if (!ssl_data)\r
+            return;\r
+        memset(ssl_data, 0, sizeof(SSLUserData));\r
+        context->user_data = ssl_data;\r
+    }\r
+    if (mode == SSL_VERIFY_NONE)\r
+        ssl_data->certificate_verify = NULL;\r
+    else\r
+        ssl_data->certificate_verify = verify_callback;\r
+}\r
+\r
+int __private_tls_safe_read(struct TLSContext *context, void *buffer, int buf_size) {\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0))\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    SOCKET_RECV_CALLBACK read_cb = (SOCKET_RECV_CALLBACK)ssl_data->recv;\r
+    if (read_cb)\r
+        return read_cb(ssl_data->fd, (char *)buffer, buf_size, 0);\r
+    return recv(ssl_data->fd, (char *)buffer, buf_size, 0);\r
+}\r
+\r
+int SSL_accept(struct TLSContext *context) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0))\r
+        return TLS_GENERIC_ERROR;\r
+    if (tls_established(context))\r
+        return 1;\r
+    unsigned char client_message[0xFFFF];\r
+    // accept\r
+    int read_size = 0;\r
+    while ((read_size = __private_tls_safe_read(context, (char *)client_message, sizeof(client_message))) > 0) {\r
+        if (tls_consume_stream(context, client_message, read_size, ssl_data->certificate_verify) >= 0) {\r
+            int res = __tls_ssl_private_send_pending(ssl_data->fd, context);\r
+            if (res < 0)\r
+                return res;\r
+        }\r
+        if (tls_established(context))\r
+            return 1;\r
+    }\r
+    if (read_size <= 0)\r
+        return TLS_BROKEN_CONNECTION;\r
+    return 0;\r
+}\r
+\r
+int SSL_connect(struct TLSContext *context) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0) || (context->critical_error))\r
+        return TLS_GENERIC_ERROR;\r
+    int res = tls_client_connect(context);\r
+    if (res < 0)\r
+        return res;\r
+    res = __tls_ssl_private_send_pending(ssl_data->fd, context);\r
+    if (res < 0)\r
+        return res;\r
+    \r
+    int read_size;\r
+    unsigned char client_message[0xFFFF];\r
+\r
+    while ((read_size = __private_tls_safe_read(context, (char *)client_message, sizeof(client_message))) > 0) {\r
+        if (tls_consume_stream(context, client_message, read_size, ssl_data->certificate_verify) >= 0) {\r
+            res = __tls_ssl_private_send_pending(ssl_data->fd, context);\r
+            if (res < 0)\r
+                return res;\r
+        }\r
+        if (tls_established(context))\r
+            return 1;\r
+        if (context->critical_error)\r
+            return TLS_GENERIC_ERROR;\r
+    }\r
+    return read_size;\r
+}\r
+\r
+int SSL_shutdown(struct TLSContext *context) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    tls_close_notify(context);\r
+    return 0;\r
+}\r
+\r
+int SSL_write(struct TLSContext *context, const void *buf, unsigned int len) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0))\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    int written_size = tls_write(context, (const unsigned char *)buf, len);\r
+    if (written_size > 0) {\r
+        int res = __tls_ssl_private_send_pending(ssl_data->fd, context);\r
+        if (res <= 0)\r
+            return res;\r
+    }\r
+    return written_size;\r
+}\r
+\r
+int SSL_read(struct TLSContext *context, void *buf, unsigned int len) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    if (context->application_buffer_len)\r
+        return tls_read(context, (unsigned char *)buf, len);\r
+\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if ((!ssl_data) || (ssl_data->fd <= 0) || (context->critical_error))\r
+        return TLS_GENERIC_ERROR;\r
+    if (tls_established(context) != 1)\r
+        return TLS_GENERIC_ERROR;\r
+    \r
+    if (!context->application_buffer_len) {\r
+        unsigned char client_message[0xFFFF];\r
+        // accept\r
+        int read_size;\r
+        while ((read_size = __private_tls_safe_read(context, (char *)client_message, sizeof(client_message))) > 0) {\r
+            if (tls_consume_stream(context, client_message, read_size, ssl_data->certificate_verify) > 0) {\r
+                __tls_ssl_private_send_pending(ssl_data->fd, context);\r
+                break;\r
+            }\r
+            if ((context->critical_error) && (!context->application_buffer_len)) {\r
+                return TLS_GENERIC_ERROR;\r
+            }\r
+        }\r
+        if ((read_size <= 0) && (!context->application_buffer_len))\r
+            return read_size;\r
+    }\r
+    \r
+    return tls_read(context, (unsigned char *)buf, len);\r
+}\r
+\r
+int SSL_pending(struct TLSContext *context) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    return context->application_buffer_len;\r
+}\r
+\r
+int SSL_set_io(struct TLSContext *context, void *recv_cb, void *send_cb) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    SSLUserData *ssl_data = (SSLUserData *)context->user_data;\r
+    if (!ssl_data) {\r
+        ssl_data = (SSLUserData *)TLS_MALLOC(sizeof(SSLUserData));\r
+        if (!ssl_data)\r
+            return TLS_NO_MEMORY;\r
+        memset(ssl_data, 0, sizeof(SSLUserData));\r
+        context->user_data = ssl_data;\r
+    }\r
+    ssl_data->recv = recv_cb;\r
+    ssl_data->send = send_cb;\r
+    return 0;\r
+}\r
+#endif // SSL_COMPATIBLE_INTERFACE\r
+\r
+\r
+#ifdef TLS_SRTP\r
+\r
+struct SRTPContext {\r
+    symmetric_CTR aes;\r
+    unsigned int salt[4];\r
+    unsigned char mac[__TLS_SHA1_MAC_SIZE];\r
+    unsigned int tag_size;\r
+    unsigned int roc;\r
+    unsigned short seq;\r
+\r
+    unsigned char mode;\r
+    unsigned char auth_mode;\r
+};\r
+\r
+struct SRTPContext *srtp_init(unsigned char mode, unsigned char auth_mode) {\r
+    struct SRTPContext *context = NULL;\r
+    tls_init();\r
+    switch (mode) {\r
+        case SRTP_NULL:\r
+            break;\r
+        case SRTP_AES_CM:\r
+            break;\r
+        default:\r
+            return NULL;\r
+    }\r
+\r
+    switch (auth_mode) {\r
+        case SRTP_AUTH_NULL:\r
+            break;\r
+        case SRTP_AUTH_HMAC_SHA1:\r
+            break;\r
+        default:\r
+            return NULL;\r
+    }\r
+    context = (struct SRTPContext *)TLS_MALLOC(sizeof(struct SRTPContext));\r
+    if (context) {\r
+        memset(context, 0, sizeof(struct SRTPContext));\r
+        context->mode = mode;\r
+        context->auth_mode = auth_mode;\r
+    }\r
+    return context;\r
+}\r
+\r
+static int __private_tls_srtp_key_derive(const void *key, int keylen, const void *salt, unsigned char label, void *out, int outlen) {\r
+    unsigned char iv[16];\r
+    memcpy(iv, salt, 14);\r
+    iv[14] = iv[15] = 0;\r
+    void *in = TLS_MALLOC(outlen);\r
+    if (!in)\r
+        return TLS_GENERIC_ERROR;\r
+    memset(in, 0, outlen);\r
+\r
+    iv[7] ^= label;\r
+\r
+    symmetric_CTR aes;\r
+\r
+    if (ctr_start(find_cipher("aes"), iv, (const unsigned char *)key, keylen, 0, CTR_COUNTER_BIG_ENDIAN, &aes))\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    ctr_encrypt((unsigned char *)in, (unsigned char *)out, outlen, &aes);\r
+    TLS_FREE(in);\r
+    ctr_done(&aes);\r
+    return 0;\r
+}\r
+\r
+int srtp_key(struct SRTPContext *context, const void *key, int keylen, const void *salt, int saltlen, int tag_bits) {\r
+    if (!context)\r
+        return TLS_GENERIC_ERROR;\r
+    if (context->mode == SRTP_AES_CM) {\r
+        if ((saltlen < 14) || (keylen < 16))\r
+            return TLS_GENERIC_ERROR;\r
+        // key\r
+        unsigned char key_buf[16];\r
+        unsigned char iv[16];\r
+\r
+        memset(iv, 0, sizeof(iv));\r
+\r
+        if (__private_tls_srtp_key_derive(key, keylen, salt, 0, key_buf, sizeof(key_buf)))\r
+            return TLS_GENERIC_ERROR;\r
+\r
+        DEBUG_DUMP_HEX_LABEL("KEY", key_buf, 16)\r
+\r
+        if (__private_tls_srtp_key_derive(key, keylen, salt, 1, context->mac, 20))\r
+            return TLS_GENERIC_ERROR;\r
+\r
+        DEBUG_DUMP_HEX_LABEL("AUTH", context->mac, 20)\r
+\r
+        memset(context->salt, 0, sizeof(context->salt));\r
+        if (__private_tls_srtp_key_derive(key, keylen, salt, 2, context->salt, 14))\r
+            return TLS_GENERIC_ERROR;\r
+\r
+        DEBUG_DUMP_HEX_LABEL("SALT", ((unsigned char *)context->salt), 14)\r
+\r
+        if (ctr_start(find_cipher("aes"), iv, key_buf, sizeof(key_buf), 0, CTR_COUNTER_BIG_ENDIAN, &context->aes))\r
+            return TLS_GENERIC_ERROR;\r
+    }\r
+    if (context->auth_mode)\r
+        context->tag_size = tag_bits / 8;\r
+    return 0;\r
+}\r
+\r
+int srtp_inline(struct SRTPContext *context, const char *b64, int tag_bits) {\r
+    char out_buffer[1024];\r
+\r
+    if (!b64)\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    int len = strlen(b64);\r
+    if (len >= sizeof(out_buffer))\r
+        len = sizeof(out_buffer);\r
+    int size = __private_b64_decode(b64, len, (unsigned char *)out_buffer);\r
+    if (size <= 0)\r
+        return TLS_GENERIC_ERROR;\r
+    switch (context->mode) {\r
+        case SRTP_AES_CM:\r
+            if (size < 30)\r
+                return TLS_BROKEN_PACKET;\r
+            return srtp_key(context, out_buffer, 16, out_buffer + 16, 14, tag_bits);\r
+    }\r
+    return TLS_GENERIC_ERROR;\r
+}\r
+\r
+int srtp_encrypt(struct SRTPContext *context, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len) {\r
+    if ((!context) || (!out) || (!out_buffer_len) || (*out_buffer_len < payload_len))\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    int out_len = payload_len;\r
+\r
+    unsigned short seq = 0;\r
+    unsigned int roc = context->roc;\r
+    unsigned int ssrc = 0;\r
+\r
+    if ((pt_header) && (pt_len >= 12)) {\r
+        seq = ntohs(*((unsigned short *)&pt_header[2]));\r
+        ssrc = ntohl(*((unsigned long *)&pt_header[8]));\r
+    }\r
+\r
+    if (seq < context->seq)\r
+        roc++;\r
+\r
+    unsigned int roc_be = htonl(roc);\r
+    if (context->mode) {\r
+        if (*out_buffer_len < out_len)\r
+            return TLS_NO_MEMORY;\r
+\r
+        unsigned int counter[4];\r
+        counter[0] = context->salt[0];\r
+        counter[1] = context->salt[1] ^ htonl (ssrc);\r
+        counter[2] = context->salt[2] ^ roc_be;\r
+        counter[3] = context->salt[3] ^ htonl (seq << 16);\r
+        ctr_setiv((unsigned char *)&counter, 16, &context->aes);\r
+        if (ctr_encrypt(payload, out, payload_len, &context->aes))\r
+            return TLS_GENERIC_ERROR;\r
+    } else {\r
+        memcpy(out, payload, payload_len);\r
+    }\r
+\r
+    *out_buffer_len = out_len;\r
+\r
+    if (context->auth_mode == SRTP_AUTH_HMAC_SHA1) {\r
+        unsigned char digest_out[__TLS_SHA1_MAC_SIZE];\r
+        unsigned long dlen = __TLS_SHA1_MAC_SIZE;\r
+        hmac_state hmac;\r
+        int err = hmac_init(&hmac, find_hash("sha1"), context->mac, 20);\r
+        if (!err) {\r
+            if (pt_len)\r
+                err = hmac_process(&hmac, pt_header, pt_len);\r
+            if (out_len)\r
+                err = hmac_process(&hmac, out, payload_len);\r
+            err = hmac_process(&hmac, (unsigned char *)&roc_be, 4);\r
+            if (!err)\r
+                err = hmac_done(&hmac, digest_out, &dlen);\r
+        }\r
+        if (err)\r
+            return TLS_GENERIC_ERROR;\r
+        if (dlen > context->tag_size)\r
+            dlen = context->tag_size;\r
+\r
+        *out_buffer_len += dlen;\r
+        memcpy(out + out_len, digest_out, dlen);\r
+    }\r
+    context->roc = roc;\r
+    context->seq = seq;\r
+    return 0;\r
+}\r
+\r
+int srtp_decrypt(struct SRTPContext *context, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len) {\r
+    if ((!context) || (!out) || (!out_buffer_len) || (*out_buffer_len < payload_len) || (payload_len < context->tag_size) || (!pt_header) || (pt_len < 12))\r
+        return TLS_GENERIC_ERROR;\r
+\r
+    int out_len = payload_len;\r
+\r
+    unsigned short seq = ntohs(*((unsigned short *)&pt_header[2]));\r
+    unsigned int roc = context->roc;\r
+    unsigned int ssrc = ntohl(*((unsigned long *)&pt_header[8]));\r
+\r
+    if (seq < context->seq)\r
+        roc++;\r
+\r
+    unsigned int roc_be = htonl(roc);\r
+    if (context->mode) {\r
+        unsigned int counter[4];\r
+        counter[0] = context->salt[0];\r
+        counter[1] = context->salt[1] ^ htonl (ssrc);\r
+        counter[2] = context->salt[2] ^ roc_be;\r
+        counter[3] = context->salt[3] ^ htonl (seq << 16);\r
+        ctr_setiv((unsigned char *)&counter, 16, &context->aes);\r
+\r
+        if (ctr_decrypt(payload, out, payload_len - context->tag_size, &context->aes))\r
+            return TLS_GENERIC_ERROR;\r
+\r
+        if (context->auth_mode == SRTP_AUTH_HMAC_SHA1) {\r
+            unsigned char digest_out[__TLS_SHA1_MAC_SIZE];\r
+            unsigned long dlen = __TLS_SHA1_MAC_SIZE;\r
+            hmac_state hmac;\r
+            int err = hmac_init(&hmac, find_hash("sha1"), context->mac, 20);\r
+            if (!err) {\r
+                if (pt_len)\r
+                    err = hmac_process(&hmac, pt_header, pt_len);\r
+                if (out_len)\r
+                    err = hmac_process(&hmac, payload, payload_len - context->tag_size);\r
+                err = hmac_process(&hmac, (unsigned char *)&roc_be, 4);\r
+                if (!err)\r
+                    err = hmac_done(&hmac, digest_out, &dlen);\r
+            }\r
+            if (err)\r
+                return TLS_GENERIC_ERROR;\r
+            if (dlen > context->tag_size)\r
+                dlen = context->tag_size;\r
+\r
+            if (memcmp(digest_out, payload + payload_len - context->tag_size, dlen))\r
+                return TLS_INTEGRITY_FAILED;\r
+        }\r
+    } else {\r
+        memcpy(out, payload, payload_len - context->tag_size);\r
+    }\r
+    context->seq = seq;\r
+    context->roc = roc;\r
+    *out_buffer_len = payload_len - context->tag_size;\r
+    return 0;\r
+}\r
+\r
+void srtp_destroy(struct SRTPContext *context) {\r
+    if (context) {\r
+        if (context->mode)\r
+            ctr_done(&context->aes);\r
+        TLS_FREE(context);\r
+    }\r
+}\r
+\r
+#endif // TLS_SRTP\r
+\r
+#endif // TLSE_C\r
diff --git a/tlse/tlse.h b/tlse/tlse.h
new file mode 100644 (file)
index 0000000..a0f1c88
--- /dev/null
@@ -0,0 +1,409 @@
+#ifndef TLSE_H
+#define TLSE_H
+
+// #define DEBUG
+
+// define TLS_LEGACY_SUPPORT to support TLS 1.1/1.0 (legacy)
+// legacy support it will use an additional 272 bytes / context
+#ifndef NO_TLS_LEGACY_SUPPORT
+#define TLS_LEGACY_SUPPORT
+#endif
+// SSL_* style blocking APIs
+#ifndef NO_SSL_COMPATIBLE_INTERFACE
+#define SSL_COMPATIBLE_INTERFACE
+#endif
+// support ChaCha20/Poly1305
+#if !defined(__BIG_ENDIAN__) && ((!defined(__BYTE_ORDER)) || (__BYTE_ORDER == __LITTLE_ENDIAN))
+    // not working on big endian machines
+    #ifndef NO_TLS_WITH_CHACHA20_POLY1305
+    #define TLS_WITH_CHACHA20_POLY1305
+    #endif
+#endif
+// support forward secrecy (Diffie-Hellman ephemeral)
+#ifndef NO_TLS_FORWARD_SECRECY
+#define TLS_FORWARD_SECRECY
+#endif
+// support client-side ECDHE
+#ifndef NO_TLS_CLIENT_ECDHE
+#define TLS_CLIENT_ECDHE
+#endif
+// suport ecdsa
+#ifndef NO_TLS_ECDSA_SUPPORTED
+#define TLS_ECDSA_SUPPORTED
+#endif
+// suport ecdsa client-side
+// #define TLS_CLIENT_ECDSA
+// TLS renegotiation is disabled by default (secured or not)
+// do not uncomment next line!
+// #define TLS_ACCEPT_SECURE_RENEGOTIATION
+// basic superficial X509v1 certificate support
+#ifndef NO_TLS_X509_V1_SUPPORT
+#define TLS_X509_V1_SUPPORT
+#endif
+
+// disable TLS_RSA_WITH_* ciphers
+#ifndef NO_TLS_ROBOT_MITIGATION
+#define TLS_ROBOT_MITIGATION
+#endif
+
+#define SSL_V30                 0x0300
+#define TLS_V10                 0x0301
+#define TLS_V11                 0x0302
+#define TLS_V12                 0x0303
+#define DTLS_V10                0xFEFF
+#define DTLS_V12                0xFEFD
+
+#define TLS_NEED_MORE_DATA       0
+#define TLS_GENERIC_ERROR       -1
+#define TLS_BROKEN_PACKET       -2
+#define TLS_NOT_UNDERSTOOD      -3
+#define TLS_NOT_SAFE            -4
+#define TLS_NO_COMMON_CIPHER    -5
+#define TLS_UNEXPECTED_MESSAGE  -6
+#define TLS_CLOSE_CONNECTION    -7
+#define TLS_COMPRESSION_NOT_SUPPORTED -8
+#define TLS_NO_MEMORY           -9
+#define TLS_NOT_VERIFIED        -10
+#define TLS_INTEGRITY_FAILED    -11
+#define TLS_ERROR_ALERT         -12
+#define TLS_BROKEN_CONNECTION   -13
+#define TLS_BAD_CERTIFICATE     -14
+#define TLS_UNSUPPORTED_CERTIFICATE -15
+#define TLS_NO_RENEGOTIATION    -16
+#define TLS_FEATURE_NOT_SUPPORTED   -17
+
+#define TLS_RSA_WITH_AES_128_CBC_SHA          0x002F
+#define TLS_RSA_WITH_AES_256_CBC_SHA          0x0035
+#define TLS_RSA_WITH_AES_128_CBC_SHA256       0x003C
+#define TLS_RSA_WITH_AES_256_CBC_SHA256       0x003D
+#define TLS_RSA_WITH_AES_128_GCM_SHA256       0x009C
+#define TLS_RSA_WITH_AES_256_GCM_SHA384       0x009D
+
+// forward secrecy
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA      0x0033
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA      0x0039
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256   0x0067
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256   0x006B
+#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256   0x009E
+#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384   0x009F
+
+#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA    0xC013
+#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA    0xC014
+#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
+#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
+#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
+
+#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA    0xC009
+#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA    0xC00A
+#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
+#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
+#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
+#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
+
+#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256     0xCCA8
+#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256   0xCCA9
+#define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256       0xCCAA
+
+#define TLS_FALLBACK_SCSV                     0x5600
+
+#define TLS_UNSUPPORTED_ALGORITHM   0x00
+#define TLS_RSA_SIGN_RSA            0x01
+#define TLS_RSA_SIGN_MD5            0x04
+#define TLS_RSA_SIGN_SHA1           0x05
+#define TLS_RSA_SIGN_SHA256         0x0B
+#define TLS_RSA_SIGN_SHA384         0x0C
+#define TLS_RSA_SIGN_SHA512         0x0D
+
+#define TLS_EC_PUBLIC_KEY           0x11
+#define TLS_EC_prime192v1           0x12
+#define TLS_EC_prime192v2           0x13
+#define TLS_EC_prime192v3           0x14
+#define TLS_EC_prime239v1           0x15
+#define TLS_EC_prime239v2           0x16
+#define TLS_EC_prime239v3           0x17
+#define TLS_EC_prime256v1           0x18
+#define TLS_EC_secp224r1            21
+#define TLS_EC_secp256r1            23
+#define TLS_EC_secp384r1            24
+#define TLS_EC_secp521r1            25
+
+#define TLS_ALERT_WARNING           0x01
+#define TLS_ALERT_CRITICAL          0x02
+
+#ifdef TLS_ROBOT_MITIGATION
+    #define TLS_CIPHERS_SIZE(n, mitigated)         n * 2
+#else
+    #define TLS_CIPHERS_SIZE(n, mitigated)         (n + mitigated) * 2
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    close_notify = 0,
+    unexpected_message = 10,
+    bad_record_mac = 20,
+    decryption_failed_RESERVED = 21,
+    record_overflow = 22,
+    decompression_failure = 30,
+    handshake_failure = 40,
+    no_certificate_RESERVED = 41,
+    bad_certificate = 42,
+    unsupported_certificate = 43,
+    certificate_revoked = 44,
+    certificate_expired = 45,
+    certificate_unknown = 46,
+    illegal_parameter = 47,
+    unknown_ca = 48,
+    access_denied = 49,
+    decode_error = 50,
+    decrypt_error = 51,
+    export_restriction_RESERVED = 60,
+    protocol_version = 70,
+    insufficient_security = 71,
+    internal_error = 80,
+    inappropriate_fallback = 86,
+    user_canceled = 90,
+    no_renegotiation = 100,
+    unsupported_extension = 110,
+    no_error = 255
+} TLSAlertDescription;
+
+// forward declarations
+struct TLSPacket;
+struct TLSCertificate;
+struct TLSContext;
+struct ECCCurveParameters;
+typedef struct TLSContext TLS;
+typedef struct TLSCertificate Certificate;
+
+typedef int (*tls_validation_function)(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
+
+/*
+  Global initialization. Optional, as it will be called automatically;
+  however, the initialization is not thread-safe, so if you intend to use TLSe
+  from multiple threads, you'll need to call tls_init() once, from a single thread,
+  before using the library.
+ */
+void tls_init();
+unsigned char *tls_pem_decode(const unsigned char *data_in, unsigned int input_length, int cert_index, unsigned int *output_len);
+struct TLSCertificate *tls_create_certificate();
+int tls_certificate_valid_subject(struct TLSCertificate *cert, const char *subject);
+int tls_certificate_valid_subject_name(const unsigned char *cert_subject, const char *subject);
+int tls_certificate_is_valid(struct TLSCertificate *cert);
+void tls_certificate_set_copy(unsigned char **member, const unsigned char *val, int len);
+void tls_certificate_set_copy_date(unsigned char **member, const unsigned char *val, int len);
+void tls_certificate_set_key(struct TLSCertificate *cert, const unsigned char *val, int len);
+void tls_certificate_set_priv(struct TLSCertificate *cert, const unsigned char *val, int len);
+void tls_certificate_set_sign_key(struct TLSCertificate *cert, const unsigned char *val, int len);
+char *tls_certificate_to_string(struct TLSCertificate *cert, char *buffer, int len);
+void tls_certificate_set_exponent(struct TLSCertificate *cert, const unsigned char *val, int len);
+void tls_certificate_set_serial(struct TLSCertificate *cert, const unsigned char *val, int len);
+void tls_certificate_set_algorithm(unsigned int *algorithm, const unsigned char *val, int len);
+void tls_destroy_certificate(struct TLSCertificate *cert);
+struct TLSPacket *tls_create_packet(struct TLSContext *context, unsigned char type, unsigned short version, int payload_size_hint);
+void tls_destroy_packet(struct TLSPacket *packet);
+void tls_packet_update(struct TLSPacket *packet);
+int tls_packet_append(struct TLSPacket *packet, const unsigned char *buf, unsigned int len);
+int tls_packet_uint8(struct TLSPacket *packet, unsigned char i);
+int tls_packet_uint16(struct TLSPacket *packet, unsigned short i);
+int tls_packet_uint32(struct TLSPacket *packet, unsigned int i);
+int tls_packet_uint24(struct TLSPacket *packet, unsigned int i);
+int tls_random(unsigned char *key, int len);
+
+/*
+  Get encrypted data to write, if any. Once you've sent all of it, call
+  tls_buffer_clear().
+ */
+const unsigned char *tls_get_write_buffer(struct TLSContext *context, unsigned int *outlen);
+
+void tls_buffer_clear(struct TLSContext *context);
+
+/* Returns 1 for established, 0 for not established yet, and -1 for a critical error. */
+int tls_established(struct TLSContext *context);
+
+/* Discards any unread decrypted data not consumed by tls_read(). */
+void tls_read_clear(struct TLSContext *context);
+
+/*
+  Reads any unread decrypted data (see tls_consume_stream). If you don't read all of it,
+  the remainder will be left in the internal buffers for next tls_read(). Returns -1 for
+  fatal error, 0 for no more data, or otherwise the number of bytes copied into the buffer
+  (up to a maximum of the given size).
+ */
+int tls_read(struct TLSContext *context, unsigned char *buf, unsigned int size);
+
+struct TLSContext *tls_create_context(unsigned char is_server, unsigned short version);
+const struct ECCCurveParameters *tls_set_curve(struct TLSContext *context, const struct ECCCurveParameters *curve);
+
+/* Create a context for a given client, from a server context. Returns NULL on error. */
+struct TLSContext *tls_accept(struct TLSContext *context);
+
+int tls_set_default_dhe_pg(struct TLSContext *context, const char *p_hex_str, const char *g_hex_str);
+void tls_destroy_context(struct TLSContext *context);
+int tls_cipher_supported(struct TLSContext *context, unsigned short cipher);
+int tls_cipher_is_fs(struct TLSContext *context, unsigned short cipher);
+int tls_choose_cipher(struct TLSContext *context, const unsigned char *buf, int buf_len, int *scsv_set);
+int tls_cipher_is_ephemeral(struct TLSContext *context);
+const char *tls_cipher_name(struct TLSContext *context);
+int tls_is_ecdsa(struct TLSContext *context);
+struct TLSPacket *tls_build_client_key_exchange(struct TLSContext *context);
+struct TLSPacket *tls_build_server_key_exchange(struct TLSContext *context, int method);
+struct TLSPacket *tls_build_hello(struct TLSContext *context);
+struct TLSPacket *tls_certificate_request(struct TLSContext *context);
+struct TLSPacket *tls_build_verify_request(struct TLSContext *context);
+int tls_parse_hello(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets, unsigned int *dtls_verified);
+int tls_parse_certificate(struct TLSContext *context, const unsigned char *buf, int buf_len, int is_client);
+int tls_parse_server_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
+int tls_parse_client_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
+int tls_parse_server_hello_done(struct TLSContext *context, const unsigned char *buf, int buf_len);
+int tls_parse_finished(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets);
+int tls_parse_verify(struct TLSContext *context, const unsigned char *buf, int buf_len);
+int tls_parse_payload(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
+int tls_parse_message(struct TLSContext *context, unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
+int tls_certificate_verify_signature(struct TLSCertificate *cert, struct TLSCertificate *parent);
+int tls_certificate_chain_is_valid(struct TLSCertificate **certificates, int len);
+int tls_certificate_chain_is_valid_root(struct TLSContext *context, struct TLSCertificate **certificates, int len);
+
+/*
+  Add a certificate or a certificate chain to the given context, in PEM form.
+  Returns a negative value (TLS_GENERIC_ERROR etc.) on error, 0 if there were no
+  certificates in the buffer, or the number of loaded certificates on success.
+ */
+int tls_load_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
+
+/*
+  Add a private key to the given context, in PEM form. Returns a negative value
+  (TLS_GENERIC_ERROR etc.) on error, 0 if there was no private key in the
+  buffer, or 1 on success.
+ */
+int tls_load_private_key(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
+struct TLSPacket *tls_build_certificate(struct TLSContext *context);
+struct TLSPacket *tls_build_finished(struct TLSContext *context);
+struct TLSPacket *tls_build_change_cipher_spec(struct TLSContext *context);
+struct TLSPacket *tls_build_done(struct TLSContext *context);
+struct TLSPacket *tls_build_message(struct TLSContext *context, const unsigned char *data, unsigned int len);
+int tls_client_connect(struct TLSContext *context);
+int tls_write(struct TLSContext *context, const unsigned char *data, unsigned int len);
+struct TLSPacket *tls_build_alert(struct TLSContext *context, char critical, unsigned char code);
+
+/*
+  Process a given number of input bytes from a socket. If the other side just
+  presented a certificate and certificate_verify is not NULL, it will be called.
+
+  Returns 0 if there's no data ready yet, a negative value (see
+  TLS_GENERIC_ERROR etc.) for an error, or a positive value (the number of bytes
+  used from buf) if one or more complete TLS messages were received. The data
+  is copied into an internal buffer even if not all of it was consumed,
+  so you should not re-send it the next time.
+
+  Decrypted data, if any, should be read back with tls_read(). Can change the
+  status of tls_established(). If the library has anything to send back on the
+  socket (e.g. as part of the handshake), tls_get_write_buffer() will return
+  non-NULL.
+ */
+int tls_consume_stream(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
+void tls_close_notify(struct TLSContext *context);
+void tls_alert(struct TLSContext *context, unsigned char critical, int code);
+
+/* Whether tls_consume_stream() has data in its buffer that is not processed yet. */
+int tls_pending(struct TLSContext *context);
+
+/*
+  Set the context as serializable or not. Must be called before negotiation.
+  Exportable contexts use a bit more memory, to be able to hold the keys.
+
+  Note that imported keys are not reexportable unless TLS_REEXPORTABLE is set.
+ */
+void tls_make_exportable(struct TLSContext *context, unsigned char exportable_flag);
+
+int tls_export_context(struct TLSContext *context, unsigned char *buffer, unsigned int buf_len, unsigned char small_version);
+struct TLSContext *tls_import_context(const unsigned char *buffer, unsigned int buf_len);
+int tls_is_broken(struct TLSContext *context);
+int tls_request_client_certificate(struct TLSContext *context);
+int tls_client_verified(struct TLSContext *context);
+const char *tls_sni(struct TLSContext *context);
+int tls_sni_set(struct TLSContext *context, const char *sni);
+int tls_load_root_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
+int tls_default_verify(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
+void tls_print_certificate(const char *fname);
+int tls_add_alpn(struct TLSContext *context, const char *alpn);
+int tls_alpn_contains(struct TLSContext *context, const char *alpn, unsigned char alpn_size);
+const char *tls_alpn(struct TLSContext *context);
+// useful when renewing certificates for servers, without the need to restart the server
+int tls_clear_certificates(struct TLSContext *context);
+int tls_make_ktls(struct TLSContext *context, int socket);
+int tls_unmake_ktls(struct TLSContext *context, int socket);
+
+#ifdef SSL_COMPATIBLE_INTERFACE
+    #define SSL_SERVER_RSA_CERT 1
+    #define SSL_SERVER_RSA_KEY  2
+    typedef struct TLSContext SSL_CTX;
+    typedef struct TLSContext SSL;
+
+    #define SSL_FILETYPE_PEM    1
+    #define SSL_VERIFY_NONE     0
+    #define SSL_VERIFY_PEER     1
+    #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 2
+    #define SSL_VERIFY_CLIENT_ONCE  3
+
+    typedef struct {
+        int fd;
+        tls_validation_function certificate_verify;
+        void *recv;
+        void *send;
+        void *user_data;
+    } SSLUserData;
+
+    int  SSL_library_init();
+    void SSL_load_error_strings();
+    void OpenSSL_add_all_algorithms();
+    void OpenSSL_add_all_ciphers();
+    void OpenSSL_add_all_digests();
+    void EVP_cleanup();
+
+    int SSLv3_server_method();
+    int SSLv3_client_method();
+    struct TLSContext *SSL_new(struct TLSContext *context);
+    int SSL_CTX_use_certificate_file(struct TLSContext *context, const char *filename, int dummy);
+    int SSL_CTX_use_PrivateKey_file(struct TLSContext *context, const char *filename, int dummy);
+    int SSL_CTX_check_private_key(struct TLSContext *context);
+    struct TLSContext *SSL_CTX_new(int method);
+    void SSL_free(struct TLSContext *context);
+    void SSL_CTX_free(struct TLSContext *context);
+    int SSL_get_error(struct TLSContext *context, int ret);
+    int SSL_set_fd(struct TLSContext *context, int socket);
+    void *SSL_set_userdata(struct TLSContext *context, void *data);
+    void *SSL_userdata(struct TLSContext *context);
+    int SSL_CTX_root_ca(struct TLSContext *context, const char *pem_filename);
+    void SSL_CTX_set_verify(struct TLSContext *context, int mode, tls_validation_function verify_callback);
+    int SSL_accept(struct TLSContext *context);
+    int SSL_connect(struct TLSContext *context);
+    int SSL_shutdown(struct TLSContext *context);
+    int SSL_write(struct TLSContext *context, const void *buf, unsigned int len);
+    int SSL_read(struct TLSContext *context, void *buf, unsigned int len);
+    int SSL_pending(struct TLSContext *context);
+    int SSL_set_io(struct TLSContext *context, void *recv, void *send);
+#endif
+
+#ifdef TLS_SRTP
+    struct SRTPContext;
+    #define SRTP_NULL           0
+    #define SRTP_AES_CM         1
+    #define SRTP_AUTH_NULL      0
+    #define SRTP_AUTH_HMAC_SHA1 1
+
+    struct SRTPContext *srtp_init(unsigned char mode, unsigned char auth_mode);
+    int srtp_key(struct SRTPContext *context, const void *key, int keylen, const void *salt, int saltlen, int tag_bits);
+    int srtp_inline(struct SRTPContext *context, const char *b64, int tag_bits);
+    int srtp_encrypt(struct SRTPContext *context, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
+    int srtp_decrypt(struct SRTPContext *context, const unsigned char *pt_header, int pt_len, const unsigned char *payload, unsigned int payload_len, unsigned char *out, int *out_buffer_len);
+    void srtp_destroy(struct SRTPContext *context);
+#endif
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif