Promised this some time ago. This diff switches relayd from libssl to
libtls. I decided to only do the refactoring so no new features have been
added. I have tested the various modes of relayd and they still behave the
same as before. This is a huge diff and needs some major testing (at least
the regress test is passing so that is a good start).

Any feedback towards the diff welcome. I will ignore feature requests
since those are out of scope for now. Once this is in I will start adding
support for OCSP and later on SNI.
-- 
:wq Claudio

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/Makefile,v
retrieving revision 1.30
diff -u -p -r1.30 Makefile
--- Makefile    28 Sep 2016 15:03:03 -0000      1.30
+++ Makefile    15 May 2017 19:51:17 -0000
@@ -3,13 +3,13 @@
 PROG=          relayd
 SRCS=          parse.y
 SRCS+=         agentx.c ca.c carp.c check_icmp.c check_script.c \
-               check_tcp.c config.c control.c hce.c log.c name2id.c \
-               pfe.c pfe_filter.c pfe_route.c proc.c \
+               check_tcp.c check_tls.c config.c control.c hce.c log.c \
+               name2id.c pfe.c pfe_filter.c pfe_route.c proc.c \
                relay.c relay_http.c relay_udp.c relayd.c \
                shuffle.c snmp.c ssl.c util.c
 MAN=           relayd.8 relayd.conf.5
 
-LDADD=         -levent -lssl -lcrypto -lutil
+LDADD=         -levent -ltls -lssl -lcrypto -lutil
 DPADD=         ${LIBEVENT} ${LIBSSL} ${LIBCRYPTO} ${LIBUTIL}
 CFLAGS+=       -Wall -I${.CURDIR} -I${.CURDIR}/../snmpd
 CFLAGS+=       -Wstrict-prototypes -Wmissing-prototypes
Index: boguskeys.h
===================================================================
RCS file: boguskeys.h
diff -N boguskeys.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ boguskeys.h 26 Mar 2017 19:25:38 -0000
@@ -0,0 +1,200 @@
+/*     $OpenBSD$       */
+
+/*
+ * Placed in the public domain by Claudio Jeker <clau...@openbsd.org>
+ * on March 26, 2017.
+ */
+
+/* Bogus private key since the private key is privseped away */
+const char bogus_1024[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    "MIICXQIBAAKBgQDXEA8QOA7tgvV0UN50pAf34b0vKD95svTuFNuCn7esdTUly/hF\n"
+    "wDckkEznfbGj6o1otpMVaPNwRhhwikF7x9IWPjXw7sfbgvQoa2gkMUMkUr/X49KA\n"
+    "7Uu0xqOaKn/IM4yA/ZaTuL99zdn8EBCRyrDVF8iDnVTPMrsLTyg2bE1qhwIDAQAB\n"
+    "AoGAHvv/T5TkAbAWcPWdtyxSwZHSUdL4oi34P7zdi0o7iiswxwtF77aruybXDZr8\n"
+    "VuNaEDYNps4CFLDkoIIqwQye5bWktBLL9Bv0ZDmR8u1PkQPjwRblg7jPtk46aiWQ\n"
+    "9NEVkr2V1GUrzAPDcC23R5PKx//PveTiwrfmo6j+sWkxTxECQQD+9LevrDATY1nt\n"
+    "Ce9R1KnduwueeDRRByS+8or8dyGXUR1wZjm2M4pBpigTfPQiSA9O6nixV3xpwNUN\n"
+    "G9XpWGO1AkEA1/GE9ZPBWHOut+WYSerq76gZeIaH3tF3FnnLBLzw8+ePf0qm0h4q\n"
+    "i2dl/EQV9LH7q0Rf7k2yXgHeo5dK4OkyywJBAM49+kWSvcVBTmJw8fa5WLw0bf7A\n"
+    "cFnHtJL+sy3t1O+KP41INJFOeh4HIk45e2gr8K4/AGk9QzhtNCuJg+5igS0CQQDM\n"
+    "AyW2TW2w/znmC0ehLgvfd1T5BUCARizYUyB2zXpnNDHh9Mk+YbmYEovLlReZIj2+\n"
+    "RM7M+SK2pdWNgHYBns+ZAkAT7fZsAeOxNjM7h2kA0AriUvc2IuDqVGiFKAFCVacF\n"
+    "mSQSIplSJU117YTqbVGf++SEj/WFYOTS8G+jjBuMr1d9\n"
+    "-----END RSA PRIVATE KEY-----\n";
+const char bogus_2048[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    "MIIEpAIBAAKCAQEA2qsShCATc5n25suEmB+1zaxbrVbSqaEWZ+qizKTLlybJ0TOD\n"
+    "Nl/6lo9hIZ+gTqf0GwJRTUwtkjlovrn5p8IWtZUceG0S+ijh7DybzGCVlOFN0JRx\n"
+    "z+zTr9eNPkvrJLwYavSzV4BpjelBKManE8sHA6pqXCDi5PfJ0iKfWtHQk2S5ukWA\n"
+    "WE33ANLQVW0ATPvtNpHSacNIzWEW7h/66sPJu+iNcekx/Q+1kI+0Msf7m1HFN464\n"
+    "eRrm3kqncPsJ6o3Kbu2aoJFk7oO6+HfSyXmxLywuUgyPnqW6zN8pj7jaq33fmHzo\n"
+    "3s95Nbk/cYOtYHPzaT5eQWXy120aZ/scuY1laQIDAQABAoIBAClEP6pPo1wdokrL\n"
+    "/an30geOj36W9AqvK9tQnIiiUQmleFDSt+B7HH9tb5c42Lf/WkH+nflIdxExZGMa\n"
+    "FdNi/YYnLchMTViIfppmlcBsOc5u9pB2c0QaHZkBxNYM3cOA+9qzc2UABuuRKYrY\n"
+    "co95sUkv0AKy8h7j5GKTxh8NmZ82+YRkkkMkk7bvXhGppR+jiqeQ4KsZbYWFPAG9\n"
+    "WJA+sFVn8WS0oMePfqmeIPY+BiddU0ITn02Hafn9jBhhXI5LKbiiwC8sFDICxPSm\n"
+    "moDpmexe1s7jNuSxueEM5XPQP7v2QmnH9KDxDcPEC5Lz8qFa6wkiLBpQ9CRmPlDV\n"
+    "pEfF8kECgYEA/5jiItxbt+kEDMm6GuAGy02Zq/9Eb3u1J7szjvvGrL6L0S5FcDic\n"
+    "S8M5A5hTvbxQfohr6AEzqog5IQ2EiyxghIfYOs5E+rYVnN4py1ErzR3LoC45bIiO\n"
+    "tRbgYGMqFzD+uGaePpCwz/Ptn9KqCoH4hhfCJPMgOSNUvh8EAJfh7HcCgYEA2wNK\n"
+    "Y53qfMjsd1qGYMM3J6QtTJWrteejSspouyKAlCD1RHKKzhmOxa5GPkG4NSYi1hij\n"
+    "nRywxGvFOm0eoYYMUhPdjdC4Txp646l3HNdEZMWv+NN47+vaHX+KvTyq1xis46JB\n"
+    "Y5SK+57RmS7sEQqUVwuqJiuPR1YoM2daBqiUFR8CgYEAymyLE67PGLz7TyFoOaaY\n"
+    "2uQPQ098JIqlstyofaHa+65Azx7FMZYz+jCXc8hs8cQ1P7DNPMXO5EzUad/py8sO\n"
+    "eYeYcSIxMRmJzl2IXhRgCyeAv9A7/D++PZ7rfoqqqAlOgj4LL2OqFFeMJtpRftbm\n"
+    "O1SPlnHSYE4h7BxmMA4ZiAsCgYAeG0Cxmvat+qzO52nLiWpej6oOehClq9b9o/9r\n"
+    "oh2Mv08X/qroFAlVUVSkoEIjRD/LsI1lPplqFuqA0plAWP3+lm6BXSzI6vnzq8sM\n"
+    "8uaa97Xt/ZwFVyWfonW+98UAVosFq7tTZgsI9dcYOKQI36xuntLf9mL2yngyQMXW\n"
+    "XnwkvwKBgQCCoZxoF0o6QWbEowJf/BrozjYa2D0tVokxRr7kfVXt9TTQez5LQ1u4\n"
+    "/w6oCEKldPe/6tzO12i9BITmAmoZzswO/ms7J3cRnvoLWM1tPHh3zrGZgIaMdTyv\n"
+    "n0QebhOEKeXrhwZVmyhBFgI/4bTZJWByAnr6p3jLywK2NdxJIXZ5cg==\n"
+    "-----END RSA PRIVATE KEY-----\n";
+const char bogus_4096[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    "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\n"
+    "-----END RSA PRIVATE KEY-----\n";
+const char bogus_8192[] = "-----BEGIN RSA PRIVATE KEY-----\n"
+    "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\n"
+    "-----END RSA PRIVATE KEY-----\n";
Index: ca.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ca.c,v
retrieving revision 1.24
diff -u -p -r1.24 ca.c
--- ca.c        6 Apr 2017 12:20:48 -0000       1.24
+++ ca.c        17 Apr 2017 12:48:59 -0000
@@ -82,17 +82,57 @@ ca_init(struct privsep *ps, struct privs
        env->sc_id = getpid() & 0xffff;
 }
 
+static void
+hash_string(char *d, size_t dlen, char *hash, size_t hashlen)
+{
+       static const char       hex[] = "0123456789abcdef";
+       size_t                  off, i;
+
+       if (hashlen < 2 * dlen + sizeof("SHA256:"))
+               fatalx("%s hash buffer to small", __func__);
+
+       off = strlcpy(hash, "SHA256:", hashlen);
+
+       for (i = 0; i < dlen; i++) {
+               hash[off++] = hex[(d[i] >> 4) & 0x0f];
+               hash[off++] = hex[d[i] & 0x0f];
+       }
+       hash[off] = 0;
+}
+
 void
 ca_launch(void)
 {
+       char             d[EVP_MAX_MD_SIZE], hash[TLS_CERT_HASH_SIZE];
        BIO             *in = NULL;
        EVP_PKEY        *pkey = NULL;
        struct relay    *rlay;
+       X509            *cert = NULL;
+       int              dlen;
 
        TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
                if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
                        continue;
 
+               if (rlay->rl_conf.tls_cert_len) {
+                       if ((in = BIO_new_mem_buf(rlay->rl_tls_cert,
+                           rlay->rl_conf.tls_cert_len)) == NULL)
+                               fatalx("ca_launch: cert");
+
+                       if ((cert = PEM_read_bio_X509(in, NULL,
+                           NULL, NULL)) == NULL)
+                               fatalx("ca_launch: cert");
+
+                       if (X509_digest(cert, EVP_sha256(), d, &dlen) != 1)
+                               fatalx("ca_launch: cert");
+
+                       hash_string(d, dlen, hash, sizeof(hash));
+
+                       BIO_free(in);
+                       X509_free(cert);
+                       purge_key(&rlay->rl_tls_cert,
+                           rlay->rl_conf.tls_cert_len);
+               }
                if (rlay->rl_conf.tls_key_len) {
                        if ((in = BIO_new_mem_buf(rlay->rl_tls_key,
                            rlay->rl_conf.tls_key_len)) == NULL)
@@ -105,16 +145,31 @@ ca_launch(void)
 
                        rlay->rl_tls_pkey = pkey;
 
-                       if (pkey_add(env, pkey,
-                           rlay->rl_conf.tls_keyid) == NULL)
+                       if (pkey_add(env, pkey, hash) == NULL)
                                fatalx("tls pkey");
 
                        purge_key(&rlay->rl_tls_key,
                            rlay->rl_conf.tls_key_len);
                }
-               if (rlay->rl_conf.tls_cert_len) {
-                       purge_key(&rlay->rl_tls_cert,
-                           rlay->rl_conf.tls_cert_len);
+
+               if (rlay->rl_conf.tls_cacert_len) {
+                       if ((in = BIO_new_mem_buf(rlay->rl_tls_cacert,
+                           rlay->rl_conf.tls_cacert_len)) == NULL)
+                               fatalx("ca_launch: cacert");
+
+                       if ((cert = PEM_read_bio_X509(in, NULL,
+                           NULL, NULL)) == NULL)
+                               fatalx("ca_launch: cacert");
+
+                       if (X509_digest(cert, EVP_sha256(), d, &dlen) != 1)
+                               fatalx("ca_launch: cacert");
+
+                       hash_string(d, dlen, hash, sizeof(hash));
+
+                       BIO_free(in);
+                       X509_free(cert);
+                       purge_key(&rlay->rl_tls_cacert,
+                           rlay->rl_conf.tls_cacert_len);
                }
                if (rlay->rl_conf.tls_cakey_len) {
                        if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
@@ -128,17 +183,12 @@ ca_launch(void)
 
                        rlay->rl_tls_capkey = pkey;
 
-                       if (pkey_add(env, pkey,
-                           rlay->rl_conf.tls_cakeyid) == NULL)
+                       if (pkey_add(env, pkey, hash) == NULL)
                                fatalx("ca pkey");
 
                        purge_key(&rlay->rl_tls_cakey,
                            rlay->rl_conf.tls_cakey_len);
                }
-               if (rlay->rl_conf.tls_cacert_len) {
-                       purge_key(&rlay->rl_tls_cacert,
-                           rlay->rl_conf.tls_cacert_len);
-               }
        }
 }
 
@@ -186,12 +236,13 @@ ca_dispatch_relay(int fd, struct privsep
                if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
                        fatalx("ca_dispatch_relay: "
                            "invalid key operation");
-               if ((pkey = pkey_find(env, cko.cko_id)) == NULL ||
+               if ((pkey = pkey_find(env, cko.cko_hash)) == NULL ||
                    (rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
                        fatalx("ca_dispatch_relay: "
                            "invalid relay key or id");
 
-               DPRINTF("%s:%d: key id %d", __func__, __LINE__, cko.cko_id);
+               DPRINTF("%s:%d: key hash %s proc %d",
+                   __func__, __LINE__, cko.cko_hash, cko.cko_proc);
 
                from = (u_char *)imsg->data + sizeof(cko);
                if ((to = calloc(1, cko.cko_tlen)) == NULL)
@@ -259,7 +310,7 @@ rsae_send_imsg(int flen, const u_char *f
        struct pollfd    pfd[1];
        struct ctl_keyop cko;
        int              ret = 0;
-       objid_t         *id;
+       char            *hash;
        struct iovec     iov[2];
        struct imsgbuf  *ibuf;
        struct imsgev   *iev;
@@ -267,7 +318,7 @@ rsae_send_imsg(int flen, const u_char *f
        int              n, done = 0, cnt = 0;
        u_char          *toptr;
 
-       if ((id = RSA_get_ex_data(rsa, 0)) == NULL)
+       if ((hash = RSA_get_ex_data(rsa, 0)) == NULL)
                return (0);
 
        iev = proc_iev(ps, PROC_CA, ps->ps_instance);
@@ -277,7 +328,7 @@ rsae_send_imsg(int flen, const u_char *f
         * XXX this could be nicer...
         */
 
-       cko.cko_id = *id;
+       (void)strlcpy(cko.cko_hash, hash, sizeof(cko.cko_hash));
        cko.cko_proc = ps->ps_instance;
        cko.cko_flen = flen;
        cko.cko_tlen = RSA_size(rsa);
@@ -490,6 +541,5 @@ ca_engine_init(struct relayd *x_env)
        return;
 
  fail:
-       ssl_error(__func__, errstr);
-       fatalx("%s", errstr);
+       fatalx("%s: %s", __func__, errstr);
 }
Index: check_tcp.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/check_tcp.c,v
retrieving revision 1.52
diff -u -p -r1.52 check_tcp.c
--- check_tcp.c 9 Feb 2017 11:16:22 -0000       1.52
+++ check_tcp.c 26 Mar 2017 05:44:08 -0000
@@ -170,7 +170,7 @@ tcp_host_up(struct ctl_tcp_event *cte)
        }
 
        if (cte->table->conf.flags & F_TLS) {
-               ssl_transaction(cte);
+               check_tls(cte);
                return;
        }
 
Index: check_tls.c
===================================================================
RCS file: check_tls.c
diff -N check_tls.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ check_tls.c 15 May 2017 19:50:33 -0000
@@ -0,0 +1,226 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2017 Claudio Jeker <clau...@openbsd.org>
+ * Copyright (c) 2007 - 2014 Reyk Floeter <r...@openbsd.org>
+ * Copyright (c) 2006 Pierre-Yves Ritschard <p...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <limits.h>
+#include <event.h>
+#include <unistd.h>
+#include <string.h>
+#include <imsg.h>
+
+#include "relayd.h"
+
+void   check_tls_read(int, short, void *);
+void   check_tls_write(int, short, void *);
+void   check_tls_handshake(int, short, void *);
+void   check_tls_cleanup(struct ctl_tcp_event *);
+void   check_tls_error(struct ctl_tcp_event *, const char *, const char *);
+
+void
+check_tls_read(int s, short event, void *arg)
+{
+       char                     rbuf[SMALL_READ_BUF_SIZE];
+       struct ctl_tcp_event    *cte = arg;
+       int                      retry_flag = EV_READ;
+       int                      ret;
+
+       if (event == EV_TIMEOUT) {
+               cte->host->up = HOST_DOWN;
+               check_tls_cleanup(cte);
+               hce_notify_done(cte->host, HCE_TLS_READ_TIMEOUT);
+               return;
+       }
+
+       bzero(rbuf, sizeof(rbuf));
+
+       ret = tls_read(cte->tls, rbuf, sizeof(rbuf));
+       if (ret > 0) {
+               if (ibuf_add(cte->buf, rbuf, ret) == -1)
+                       fatal("check_tls_read: buf_add error");
+               if (cte->validate_read != NULL &&
+                   cte->validate_read(cte) == 0) {
+                       check_tls_cleanup(cte);
+                       hce_notify_done(cte->host, cte->host->he);
+                       return;
+               }
+       } else if (ret == 0) {
+               cte->host->up = HOST_DOWN;
+               (void)cte->validate_close(cte);
+               check_tls_cleanup(cte);
+               hce_notify_done(cte->host, cte->host->he);
+               return;
+       } else if (ret == TLS_WANT_POLLIN) {
+               retry_flag = EV_READ;
+       } else if (ret == TLS_WANT_POLLOUT) {
+               retry_flag = EV_WRITE;
+       } else {
+               cte->host->up = HOST_DOWN;
+               check_tls_error(cte, cte->host->conf.name, "cannot read");
+               check_tls_cleanup(cte);
+               hce_notify_done(cte->host, HCE_TLS_READ_ERROR);
+               return;
+       }
+
+       event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, check_tls_read,
+           &cte->tv_start, &cte->table->conf.timeout, cte);
+       return;
+}
+
+void
+check_tls_write(int s, short event, void *arg)
+{
+       struct ctl_tcp_event    *cte = arg;
+       int                      retry_flag = EV_WRITE;
+       int                      len;
+       int                      ret;
+
+       if (event == EV_TIMEOUT) {
+               cte->host->up = HOST_DOWN;
+               check_tls_cleanup(cte);
+               hce_notify_done(cte->host, HCE_TLS_WRITE_TIMEOUT);
+               return;
+       }
+
+       len = strlen(cte->table->sendbuf);
+
+       ret = tls_write(cte->tls, cte->table->sendbuf, len);
+       if (ret > 0) {
+               if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) ==
+                   NULL)
+                       fatalx("ssl_write: cannot create dynamic buffer");
+
+               event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, check_tls_read,
+                   &cte->tv_start, &cte->table->conf.timeout, cte);
+               return;
+       } else if (ret == TLS_WANT_POLLIN) {
+               retry_flag = EV_READ;
+       } else if (ret == TLS_WANT_POLLOUT) {
+               retry_flag = EV_WRITE;
+       } else {
+               cte->host->up = HOST_DOWN;
+               check_tls_error(cte, cte->host->conf.name, "cannot write");
+               check_tls_cleanup(cte);
+               hce_notify_done(cte->host, HCE_TLS_WRITE_ERROR);
+               return;
+       }
+
+       event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, check_tls_write,
+           &cte->tv_start, &cte->table->conf.timeout, cte);
+}
+
+void
+check_tls_handshake(int fd, short event, void *arg)
+{
+       struct ctl_tcp_event    *cte = arg;
+       int                      retry_flag = 0;
+       int                      ret;
+
+       if (event == EV_TIMEOUT) {
+               cte->host->up = HOST_DOWN;
+               hce_notify_done(cte->host, HCE_TLS_CONNECT_TIMEOUT);
+               check_tls_cleanup(cte);
+               return;
+       }
+
+       ret = tls_handshake(cte->tls);
+       if (ret == 0) {
+               if (cte->table->conf.check == CHECK_TCP) {
+                       cte->host->up = HOST_UP;
+                       hce_notify_done(cte->host, HCE_TLS_CONNECT_OK);
+                       check_tls_cleanup(cte);
+                       return;
+               }
+               if (cte->table->sendbuf != NULL) {
+                       event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE,
+                           check_tls_write, &cte->tv_start,
+                           &cte->table->conf.timeout, cte);
+                       return;
+               }
+               if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) ==
+                   NULL)
+                       fatalx("ssl_connect: cannot create dynamic buffer");
+               event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ,
+                   check_tls_read, &cte->tv_start, &cte->table->conf.timeout,
+                   cte);
+               return;
+       } else if (ret == TLS_WANT_POLLIN) {
+               retry_flag = EV_READ;
+       } else if (ret == TLS_WANT_POLLOUT) {
+               retry_flag = EV_WRITE;
+       } else {
+               cte->host->up = HOST_DOWN;
+               check_tls_error(cte, cte->host->conf.name,
+                  "cannot connect");
+               hce_notify_done(cte->host, HCE_TLS_CONNECT_FAIL);
+               check_tls_cleanup(cte);
+               return;
+       }
+
+       event_again(&cte->ev, cte->s, EV_TIMEOUT|retry_flag,
+           check_tls_handshake,
+           &cte->tv_start, &cte->table->conf.timeout, cte);
+}
+
+void
+check_tls_cleanup(struct ctl_tcp_event *cte)
+{
+       tls_close(cte->tls);
+       tls_reset(cte->tls);
+       close(cte->s);
+       ibuf_free(cte->buf);
+       cte->buf = NULL;
+}
+
+void
+check_tls_error(struct ctl_tcp_event *cte, const char *where, const char *what)
+{
+       if (log_getverbose() < 2)
+               return;
+       log_debug("TLS error: %s: %s: %s", where, what, tls_error(cte->tls));
+}
+
+void
+check_tls(struct ctl_tcp_event *cte)
+{
+       if (cte->tls == NULL) {
+               cte->tls = tls_client();
+               if (cte->tls == NULL)
+                       fatal("cannot create TLS connection");
+       }
+       /* need to re-configure because of tls_reset */
+       if (tls_configure(cte->tls, cte->table->tls_cfg) == -1)
+               fatal("cannot configure TLS connection");
+
+       if (tls_connect_socket(cte->tls, cte->s, NULL) == -1) {
+               check_tls_error(cte, cte->host->conf.name,
+                   "cannot connect");
+               tls_close(cte->tls);
+               tls_reset(cte->tls);
+               cte->host->up = HOST_UNKNOWN;
+               hce_notify_done(cte->host, HCE_TLS_CONNECT_ERROR);
+               return;
+       }
+
+       event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, check_tls_handshake,
+           &cte->tv_start, &cte->table->conf.timeout, cte);
+}
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
retrieving revision 1.31
diff -u -p -r1.31 config.c
--- config.c    24 Nov 2016 21:01:18 -0000      1.31
+++ config.c    15 May 2017 19:53:35 -0000
@@ -100,8 +100,12 @@ config_init(struct relayd *env)
                (void)strlcpy(env->sc_proto_default.tlsciphers,
                    TLSCIPHERS_DEFAULT,
                    sizeof(env->sc_proto_default.tlsciphers));
-               env->sc_proto_default.tlsecdhcurve = TLSECDHCURVE_DEFAULT;
-               env->sc_proto_default.tlsdhparams = TLSDHPARAMS_DEFAULT;
+               (void)strlcpy(env->sc_proto_default.tlsecdhcurve,
+                   TLSECDHCURVE_DEFAULT,
+                   sizeof(env->sc_proto_default.tlsecdhcurve));
+               (void)strlcpy(env->sc_proto_default.tlsdhparams,
+                   TLSDHPARAM_DEFAULT,
+                   sizeof(env->sc_proto_default.tlsdhparams));
                env->sc_proto_default.type = RELAY_PROTO_TCP;
                (void)strlcpy(env->sc_proto_default.name, "default",
                    sizeof(env->sc_proto_default.name));
@@ -269,6 +273,8 @@ config_getcfg(struct relayd *env, struct
                ssl_init(env);
                if (what & CONFIG_CA_ENGINE)
                        ca_engine_init(env);
+               if (tls_init() == -1)
+                       fatalx("unable to initialize TLS");
        }
 
        if (privsep_process != PROC_PARENT)
Index: hce.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/hce.c,v
retrieving revision 1.75
diff -u -p -r1.75 hce.c
--- hce.c       3 Sep 2016 14:09:04 -0000       1.75
+++ hce.c       26 Mar 2017 15:53:08 -0000
@@ -90,9 +90,11 @@ hce_setup_events(void)
        if (env->sc_conf.flags & F_TLS) {
                TAILQ_FOREACH(table, env->sc_tables, entry) {
                        if (!(table->conf.flags & F_TLS) ||
-                           table->ssl_ctx != NULL)
+                           table->tls_cfg != NULL)
                                continue;
-                       table->ssl_ctx = ssl_ctx_create(env);
+                       table->tls_cfg = tls_config_new();
+                       tls_config_insecure_noverifycert(table->tls_cfg);
+                       tls_config_insecure_noverifyname(table->tls_cfg);
                }
        }
 }
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.214
diff -u -p -r1.214 parse.y
--- parse.y     5 Jan 2017 13:53:09 -0000       1.214
+++ parse.y     15 May 2017 19:56:10 -0000
@@ -181,7 +181,6 @@ typedef struct {
 %type  <v.number>      opttls opttlsclient
 %type  <v.number>      redirect_proto relay_proto match
 %type  <v.number>      action ruleaf key_option
-%type  <v.number>      tlsdhparams tlsecdhcurve
 %type  <v.port>        port
 %type  <v.host>        host
 %type  <v.addr>        address
@@ -1000,8 +999,10 @@ proto             : relay_proto PROTO STRING      {
                        TAILQ_INIT(&p->rules);
                        (void)strlcpy(p->tlsciphers, TLSCIPHERS_DEFAULT,
                            sizeof(p->tlsciphers));
-                       p->tlsdhparams = TLSDHPARAMS_DEFAULT;
-                       p->tlsecdhcurve = TLSECDHCURVE_DEFAULT;
+                       (void)strlcpy(p->tlsecdhcurve, TLSECDHCURVE_DEFAULT,
+                           sizeof(p->tlsecdhcurve));
+                       (void)strlcpy(p->tlsdhparams, TLSDHPARAM_DEFAULT,
+                           sizeof(p->tlsdhparams));
                        if (last_proto_id == INT_MAX) {
                                yyerror("too many protocols defined");
                                free(p);
@@ -1088,8 +1089,8 @@ tlsflags_l        : tlsflags comma tlsflags_l
                | tlsflags
                ;
 
-tlsflags       : SESSION TICKETS { proto->tickets = 0; }
-               | NO SESSION TICKETS { proto->tickets = -1; }
+tlsflags       : SESSION TICKETS { proto->tickets = 1; }
+               | NO SESSION TICKETS { proto->tickets = 0; }
                | CIPHERS STRING                {
                        if (strlcpy(proto->tlsciphers, $2,
                            sizeof(proto->tlsciphers)) >=
@@ -1101,16 +1102,68 @@ tlsflags        : SESSION TICKETS { proto->tick
                        free($2);
                }
                | NO EDH                        {
-                       proto->tlsdhparams = TLSDHPARAMS_NONE;
+                       (void)strlcpy(proto->tlsdhparams, "none",
+                           sizeof(proto->tlsdhparams));
                }
-               | EDH tlsdhparams               {
-                       proto->tlsdhparams = $2;
+               | EDH                   {
+                       (void)strlcpy(proto->tlsdhparams, "auto",
+                           sizeof(proto->tlsdhparams));
+               }
+               | EDH PARAMS STRING             {
+                       struct tls_config       *tls_cfg;
+                       if ((tls_cfg = tls_config_new()) == NULL) {
+                               yyerror("tls_config_new failed");
+                               free($3);
+                               YYERROR;
+                       }
+                       if (tls_config_set_dheparams(tls_cfg, $3) != 0) {
+                               yyerror("tls edh params %s: %s", $3,
+                                   tls_config_error(tls_cfg));
+                               tls_config_free(tls_cfg);
+                               free($3);
+                               YYERROR;
+                       }
+                       tls_config_free(tls_cfg);
+                       if (strlcpy(proto->tlsdhparams, $3,
+                           sizeof(proto->tlsdhparams)) >=
+                           sizeof(proto->tlsdhparams)) {
+                               yyerror("tls edh truncated");
+                               free($3);
+                               YYERROR;
+                       }
+                       free($3);
                }
                | NO ECDH                       {
-                       proto->tlsecdhcurve = 0;
+                       (void)strlcpy(proto->tlsecdhcurve, "none",
+                           sizeof(proto->tlsecdhcurve));
                }
-               | ECDH tlsecdhcurve             {
-                       proto->tlsecdhcurve = $2;
+               | ECDH                  {
+                       (void)strlcpy(proto->tlsecdhcurve, "auto",
+                           sizeof(proto->tlsecdhcurve));
+               }
+               | ECDH CURVE STRING                     {
+                       struct tls_config       *tls_cfg;
+                       if ((tls_cfg = tls_config_new()) == NULL) {
+                               yyerror("tls_config_new failed");
+                               free($3);
+                               YYERROR;
+                       }
+                       if (tls_config_set_ecdhecurve(tls_cfg, $3) != 0) {
+                               yyerror("tls ecdh curve %s: %s", $3,
+                                   tls_config_error(tls_cfg));
+                               tls_config_free(tls_cfg);
+                               free($3);
+                               YYERROR;
+                       }
+                       tls_config_free(tls_cfg);
+                       if (strlcpy(proto->tlsecdhcurve, $3,
+                           sizeof(proto->tlsecdhcurve)) >=
+                           sizeof(proto->tlsecdhcurve)) {
+                               yyerror("tls ecdh truncated");
+                               free($3);
+                               YYERROR;
+                       }
+                       free($3);
                }
                | CA FILENAME STRING            {
                        if (strlcpy(proto->tlsca, $3,
@@ -1547,29 +1600,6 @@ key_option       : /* empty */           { $$ = KEY_OPT
                | REMOVE                { $$ = KEY_OPTION_REMOVE; }
                | HASH                  { $$ = KEY_OPTION_HASH; }
                | LOG                   { $$ = KEY_OPTION_LOG; }
-               ;
-
-tlsdhparams    : /* empty */           { $$ = TLSDHPARAMS_MIN; }
-               | PARAMS NUMBER         {
-                       if ($2 < TLSDHPARAMS_MIN) {
-                               yyerror("EDH params not supported: %d", $2);
-                               YYERROR;
-                       }
-                       $$ = $2;
-               }
-               ;
-
-tlsecdhcurve   : /* empty */           { $$ = TLSECDHCURVE_DEFAULT; }
-               | CURVE STRING          {
-                       if (strcmp("none", $2) == 0)
-                               $$ = 0;
-                       else if ((proto->tlsecdhcurve = OBJ_sn2nid($2)) == 0) {
-                               yyerror("ECDH curve not supported");
-                               free($2);
-                               YYERROR;
-                       }
-                       free($2);
-               }
                ;
 
 relay          : RELAY STRING  {
Index: relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.219
diff -u -p -r1.219 relay.c
--- relay.c     2 Feb 2017 08:24:16 -0000       1.219
+++ relay.c     10 May 2017 11:18:15 -0000
@@ -39,8 +39,7 @@
 #include <siphash.h>
 #include <imsg.h>
 
-#include <openssl/dh.h>
-#include <openssl/ssl.h>
+#include <tls.h>
 
 #include "relayd.h"
 
@@ -73,22 +72,15 @@ void                 relay_input(struct rsession *);
 
 void            relay_hash_addr(SIPHASH_CTX *, struct sockaddr_storage *, int);
 
-DH *            relay_tls_get_dhparams(int);
-DH             *relay_tls_callback_dh(SSL *, int, int);
-SSL_CTX                *relay_tls_ctx_create(struct relay *);
+int             relay_tls_ctx_create(struct relay *);
 void            relay_tls_transaction(struct rsession *,
                    struct ctl_relay_event *);
-void            relay_tls_accept(int, short, void *);
+void            relay_tls_handshake(int, short, void *);
 void            relay_connect_retry(int, short, void *);
-void            relay_tls_connect(int, short, void *);
 void            relay_tls_connected(struct ctl_relay_event *);
 void            relay_tls_readcb(int, short, void *);
 void            relay_tls_writecb(int, short, void *);
 
-struct tls_ticket      *relay_get_ticket_key(unsigned char *);
-int                     relay_tls_session_ticket(SSL *, unsigned char *,
-                           unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int);
-
 char           *relay_load_file(const char *, off_t *);
 extern void     bufferevent_read_pressure_cb(struct evbuffer *, size_t,
                    size_t, void *);
@@ -262,7 +254,7 @@ relay_protodebug(struct relay *rlay)
                fprintf(stderr, "\ttls flags: %s\n",
                    printb_flags(proto->tlsflags, TLSFLAG_BITS));
        fprintf(stderr, "\ttls session tickets: %s\n",
-           (proto->tickets > -1) ? "enabled" : "disabled");
+           (proto->tickets == 1) ? "enabled" : "disabled");
        fprintf(stderr, "\ttype: ");
        switch (proto->type) {
        case RELAY_PROTO_TCP:
@@ -426,8 +418,8 @@ relay_launch(void)
 
        TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
                if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) &&
-                   (rlay->rl_ssl_ctx = relay_tls_ctx_create(rlay)) == NULL)
-                       fatal("relay_init: failed to create TLS context");
+                   relay_tls_ctx_create(rlay) == -1)
+                       fatalx("relay_launch: failed to create TLS context");
 
                TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
                        /*
@@ -687,7 +679,7 @@ relay_connected(int fd, short sig, void 
                return;
        }
 
-       if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->ssl == NULL)) {
+       if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->tls == NULL)) {
                relay_tls_transaction(con, out);
                return;
        }
@@ -727,7 +719,7 @@ relay_connected(int fd, short sig, void 
        con->se_out.bev = bev;
 
        /* Initialize the TLS wrapper */
-       if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->ssl != NULL))
+       if ((rlay->rl_conf.flags & F_TLSCLIENT) && (out->tls != NULL))
                relay_tls_connected(out);
 
        bufferevent_settimeout(bev,
@@ -778,7 +770,7 @@ relay_input(struct rsession *con)
        }
 
        /* Initialize the TLS wrapper */
-       if ((rlay->rl_conf.flags & F_TLS) && con->se_in.ssl != NULL)
+       if ((rlay->rl_conf.flags & F_TLS) && con->se_in.tls != NULL)
                relay_tls_connected(&con->se_in);
 
        bufferevent_settimeout(con->se_in.bev,
@@ -826,8 +818,8 @@ relay_dump(struct ctl_relay_event *cre, 
         * of non-blocking events etc. This is useful to print an
         * error message before gracefully closing the session.
         */
-       if (cre->ssl != NULL)
-               (void)SSL_write(cre->ssl, buf, len);
+       if (cre->tls != NULL)
+               (void)tls_write(cre->tls, buf, len);
        else
                (void)write(cre->s, buf, len);
 }
@@ -1086,9 +1078,9 @@ relay_accept(int fd, short event, void *
                goto err;
 
        con->se_in.s = s;
-       con->se_in.ssl = NULL;
+       con->se_in.tls = NULL;
        con->se_out.s = -1;
-       con->se_out.ssl = NULL;
+       con->se_out.tls = NULL;
        con->se_in.dst = &con->se_out;
        con->se_out.dst = &con->se_in;
        con->se_in.con = con;
@@ -1401,7 +1393,7 @@ relay_session(struct rsession *con)
                return;
        }
 
-       if ((rlay->rl_conf.flags & F_TLS) && (in->ssl == NULL)) {
+       if ((rlay->rl_conf.flags & F_TLS) && (in->tls == NULL)) {
                relay_tls_transaction(con, in);
                return;
        }
@@ -1570,7 +1562,7 @@ relay_connect(struct rsession *con)
        /* Connection is already established but session not active */
        if ((rlay->rl_conf.flags & F_TLSINSPECT) &&
            con->se_out.state == STATE_PRECONNECT) {
-               if (con->se_out.ssl == NULL) {
+               if (con->se_out.tls == NULL) {
                        log_debug("%s: tls connect failed", __func__);
                        return (-1);
                }
@@ -1706,14 +1698,11 @@ relay_close(struct rsession *con, const 
                bufferevent_free(con->se_in.bev);
        else if (con->se_in.output != NULL)
                evbuffer_free(con->se_in.output);
-       if (con->se_in.ssl != NULL) {
-               /* XXX handle non-blocking shutdown */
-               if (SSL_shutdown(con->se_in.ssl) == 0)
-                       SSL_shutdown(con->se_in.ssl);
-               SSL_free(con->se_in.ssl);
-       }
-       if (con->se_in.tlscert != NULL)
-               X509_free(con->se_in.tlscert);
+       if (con->se_in.tls != NULL)
+               tls_close(con->se_in.tls);
+       tls_free(con->se_in.tls);
+       tls_config_free(con->se_in.tls_cfg);
+       free(con->se_in.tlscert);
        if (con->se_in.s != -1) {
                close(con->se_in.s);
                if (con->se_out.s == -1) {
@@ -1726,20 +1715,16 @@ relay_close(struct rsession *con, const 
                            __func__, relay_inflight);
                }
        }
-       free(con->se_in.buf);
 
        if (con->se_out.bev != NULL)
                bufferevent_free(con->se_out.bev);
        else if (con->se_out.output != NULL)
                evbuffer_free(con->se_out.output);
-       if (con->se_out.ssl != NULL) {
-               /* XXX handle non-blocking shutdown */
-               if (SSL_shutdown(con->se_out.ssl) == 0)
-                       SSL_shutdown(con->se_out.ssl);
-               SSL_free(con->se_out.ssl);
-       }
-       if (con->se_out.tlscert != NULL)
-               X509_free(con->se_out.tlscert);
+       if (con->se_out.tls != NULL)
+               tls_close(con->se_out.tls);
+       tls_free(con->se_out.tls);
+       tls_config_free(con->se_out.tls_cfg);
+       free(con->se_out.tlscert);
        if (con->se_out.s != -1) {
                close(con->se_out.s);
 
@@ -1751,8 +1736,6 @@ relay_close(struct rsession *con, const 
        }
        con->se_out.state = STATE_INIT;
 
-       free(con->se_out.buf);
-
        if (con->se_log != NULL)
                evbuffer_free(con->se_log);
 
@@ -1896,6 +1879,8 @@ relay_dispatch_ca(int fd, struct privsep
 int
 relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
 {
+       struct relay_ticket_key  ticket;
+       struct relay            *rlay;
        struct rsession         *con;
        struct timeval           tv;
        objid_t                  id;
@@ -1945,13 +1930,15 @@ relay_dispatch_parent(int fd, struct pri
                config_getreset(env, imsg);
                break;
        case IMSG_TLSTICKET_REKEY:
-               IMSG_SIZE_CHECK(imsg, (&env->sc_tls_ticket));
-               /* rotate keys */
-               memcpy(&env->sc_tls_ticket_bak, &env->sc_tls_ticket,
-                   sizeof(env->sc_tls_ticket));
-               env->sc_tls_ticket_bak.tt_backup = 1;
-               memcpy(&env->sc_tls_ticket, imsg->data,
-                   sizeof(env->sc_tls_ticket));
+               IMSG_SIZE_CHECK(imsg, (&ticket));
+               memcpy(&env->sc_ticket, imsg->data, sizeof(env->sc_ticket));
+               TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
+                       if (rlay->rl_conf.flags & F_TLS)
+                               tls_config_add_ticket_key(rlay->rl_tls_cfg,
+                                   env->sc_ticket.tt_keyrev,
+                                   env->sc_ticket.tt_key,
+                                   sizeof(env->sc_ticket.tt_key));
+               }
                break;
        default:
                return (-1);
@@ -1960,69 +1947,6 @@ relay_dispatch_parent(int fd, struct pri
        return (0);
 }
 
-DH *
-relay_tls_get_dhparams(int keylen)
-{
-       DH              *dh;
-       BIGNUM          *(*prime)(BIGNUM *);
-       const char      *gen;
-
-       gen = "2";
-       if (keylen >= 8192)
-               prime = get_rfc3526_prime_8192;
-       else if (keylen >= 4096)
-               prime = get_rfc3526_prime_4096;
-       else if (keylen >= 3072)
-               prime = get_rfc3526_prime_3072;
-       else if (keylen >= 2048)
-               prime = get_rfc3526_prime_2048;
-       else if (keylen >= 1536)
-               prime = get_rfc3526_prime_1536;
-       else
-               prime = get_rfc2409_prime_1024;
-
-       if ((dh = DH_new()) == NULL)
-               return (NULL);
-
-       dh->p = (*prime)(NULL);
-       BN_dec2bn(&dh->g, gen);
-
-       if (dh->p == NULL || dh->g == NULL) {
-               DH_free(dh);
-               return (NULL);
-       }
-
-       return (dh);
-}
-
-DH *
-relay_tls_callback_dh(SSL *ssl, int export, int keylen)
-{
-       struct ctl_relay_event  *cre;
-       EVP_PKEY                *pkey;
-       int                      keytype, maxlen;
-       DH                      *dh = NULL;
-
-       /* Get maximum key length from config */
-       if ((cre = (struct ctl_relay_event *)SSL_get_app_data(ssl)) == NULL)
-               return (NULL);
-       maxlen = cre->con->se_relay->rl_proto->tlsdhparams;
-
-       /* Get the private key length from the cert */
-       if ((pkey = SSL_get_privatekey(ssl))) {
-               keytype = EVP_PKEY_type(pkey->type);
-               if (keytype == EVP_PKEY_RSA || keytype == EVP_PKEY_DSA)
-                       keylen = EVP_PKEY_bits(pkey);
-               else
-                       return (NULL);
-       }
-
-       /* get built-in params based on the shorter key length */
-       dh = relay_tls_get_dhparams(MINIMUM(keylen, maxlen));
-
-       return (dh);
-}
-
 int
 relay_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
 {
@@ -2034,316 +1958,357 @@ relay_dispatch_hce(int fd, struct privse
        return (-1);
 }
 
-SSL_CTX *
-relay_tls_ctx_create(struct relay *rlay)
+static int
+relay_tls_ctx_create_proto(struct protocol *proto, struct tls_config *tls_cfg)
 {
-       struct protocol *proto = rlay->rl_proto;
-       SSL_CTX         *ctx;
-       EC_KEY          *ecdhkey;
+       uint32_t                 protocols = 0;
 
-       ctx = SSL_CTX_new(SSLv23_method());
-       if (ctx == NULL)
-               goto err;
+       /* Set the allowed SSL protocols */
+       if (proto->tlsflags & TLSFLAG_TLSV1_0)
+               protocols |= TLS_PROTOCOL_TLSv1_0;
+       if (proto->tlsflags & TLSFLAG_TLSV1_1)
+               protocols |= TLS_PROTOCOL_TLSv1_1;
+       if (proto->tlsflags & TLSFLAG_TLSV1_2)
+               protocols |= TLS_PROTOCOL_TLSv1_2;
+       if (tls_config_set_protocols(tls_cfg, protocols) == -1) {
+               log_warnx("could not set the TLS protocol: %s",
+                   tls_config_error(tls_cfg));
+               return (-1);
+       }
+
+       if (tls_config_set_ciphers(tls_cfg, proto->tlsciphers)) {
+               log_warnx("could not set the TLS cypers: %s",
+                   tls_config_error(tls_cfg));
+               return (-1);
+       }
+
+       if ((proto->tlsflags & TLSFLAG_CIPHER_SERVER_PREF) == 0)
+               tls_config_prefer_ciphers_client(tls_cfg);
 
        /*
-        * Disable the session cache by default.
-        * Everything modern uses tickets
+        * Set session ID context to a random value. It needs to be the
+        * same accross all relay processes or session caching will fail.
         */
-       SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+       if (tls_config_set_session_id(tls_cfg, env->sc_conf.tls_sid,
+           sizeof(env->sc_conf.tls_sid)) == -1) {
+               log_warnx("could not set the TLS session ID: %s",
+                   tls_config_error(tls_cfg));
+               return (-1);
+       }
 
        /* Set callback for TLS session tickets if enabled */
-       if (proto->tickets == -1)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
-       else {
-               if (!SSL_CTX_set_tlsext_ticket_key_cb(ctx,
-                   relay_tls_session_ticket))
-                       log_warnx("could not set the TLS ticket callback");
+       if (proto->tickets == 1) {
                /* set timeout to the ticket rekey time */
-               SSL_CTX_set_timeout(ctx, TLS_TICKET_REKEY_TIME);
+               tls_config_set_session_lifetime(tls_cfg, TLS_SESSION_LIFETIME);
+
+               tls_config_add_ticket_key(tls_cfg,
+                   env->sc_ticket.tt_keyrev, env->sc_ticket.tt_key,
+                   sizeof(env->sc_ticket.tt_key));
        }
 
-       /* Enable all workarounds and set SSL options */
-       SSL_CTX_set_options(ctx, SSL_OP_ALL);
-       SSL_CTX_set_options(ctx,
-           SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
-       if (proto->tlsflags & TLSFLAG_CIPHER_SERVER_PREF)
-               SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
-       if ((proto->tlsflags & TLSFLAG_CLIENT_RENEG) == 0)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_CLIENT_RENEGOTIATION);
+       if (tls_config_set_ecdhecurve(tls_cfg, proto->tlsecdhcurve) != 0) {
+               log_warnx("failed to set ecdh curve %s: %s",
+                   proto->tlsecdhcurve, tls_config_error(tls_cfg));
+               return (-1);
+       }
 
-       /* Set the allowed SSL protocols */
-       SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
-       SSL_CTX_clear_options(ctx, SSL_OP_NO_SSLv3);
-       if ((proto->tlsflags & TLSFLAG_SSLV3) == 0)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
-       SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1);
-       if ((proto->tlsflags & TLSFLAG_TLSV1_0) == 0)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
-       SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_1);
-       if ((proto->tlsflags & TLSFLAG_TLSV1_1) == 0)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1);
-       SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_2);
-       if ((proto->tlsflags & TLSFLAG_TLSV1_2) == 0)
-               SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_2);
-
-       if (proto->tlsecdhcurve > 0) {
-               /* Enable ECDHE support for TLS perfect forward secrecy */
-               if ((ecdhkey =
-                   EC_KEY_new_by_curve_name(proto->tlsecdhcurve)) == NULL)
-                       goto err;
-               SSL_CTX_set_tmp_ecdh(ctx, ecdhkey);
-               SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
-               EC_KEY_free(ecdhkey);
+       if (tls_config_set_dheparams(tls_cfg, proto->tlsdhparams) != 0) {
+               log_warnx("failed to set dh params %s: %s",
+                   proto->tlsdhparams, tls_config_error(tls_cfg));
+               return (-1);
        }
 
-       if (proto->tlsdhparams > 0) {
-               /* Enable EDH params (forward secrecy for older clients) */
-               SSL_CTX_set_tmp_dh_callback(ctx, relay_tls_callback_dh);
+       return (0);
+}
+
+/*
+ * This function is not publicy exported because it is a hack until libtls
+ * has a proper privsep setup 
+ */
+void tls_config_skip_private_key_check(struct tls_config *config);
+
+int
+relay_tls_ctx_create(struct relay *rlay)
+{
+       struct tls_config       *tls_cfg, *tls_client_cfg;
+       struct tls              *tls = NULL;
+       const char              *fake_key;
+       int                      fake_keylen;
+
+       if ((tls_cfg = tls_config_new()) == NULL) {
+               log_warnx("unable to allocate TLS config");
+               return (-1);
+       }
+       if ((tls_client_cfg = tls_config_new()) == NULL) {
+               log_warnx("unable to allocate TLS config");
+               return (-1);
        }
 
-       if (!SSL_CTX_set_cipher_list(ctx, proto->tlsciphers))
+       if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_cfg) == -1)
+               goto err;
+       if (relay_tls_ctx_create_proto(rlay->rl_proto, tls_client_cfg) == -1)
                goto err;
 
        /* Verify the server certificate if we have a CA chain */
-       if ((rlay->rl_conf.flags & F_TLSCLIENT) &&
-           (rlay->rl_tls_ca != NULL)) {
-               if (!SSL_CTX_load_verify_mem(ctx,
-                   rlay->rl_tls_ca, rlay->rl_conf.tls_ca_len))
-                       goto err;
-               SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+       if (rlay->rl_conf.flags & F_TLSCLIENT) {
+               /*
+                * Currently relayd can't verify the name of certs and changing
+                * this is non trivial. For now just disable name verification.
+                */
+               tls_config_insecure_noverifyname(tls_client_cfg);
+
+               if (rlay->rl_tls_ca != NULL) {
+                       if (tls_config_set_ca_mem(tls_client_cfg,
+                           rlay->rl_tls_ca, rlay->rl_conf.tls_ca_len) != 0) {
+                               log_warnx("failed to set root certificates: %s",
+                                   tls_config_error(tls_client_cfg));
+                               goto err;
+                       }
+               } else {
+                       /* No root cert available so disable the checking */
+                       tls_config_insecure_noverifycert(tls_client_cfg);
+               }
+
+               rlay->rl_tls_client_cfg = tls_client_cfg;
        }
 
-       if ((rlay->rl_conf.flags & F_TLS) == 0)
-               return (ctx);
+       if (rlay->rl_conf.flags & F_TLS) {
+               log_debug("%s: loading certificate", __func__);
+               /*
+                * Use the public key as the "private" key - the secret key
+                * parameters are hidden in an extra process that will be
+                * contacted by the RSA engine.  The SSL/TLS library needs at
+                * least the public key parameters in the current process.
+                * For this we need to skip the private key check done by
+                * libtls.
+                */
+               tls_config_skip_private_key_check(tls_cfg);
 
-       log_debug("%s: loading certificate", __func__);
-       if (!SSL_CTX_use_certificate_chain_mem(ctx,
-           rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len))
-               goto err;
+               if ((fake_keylen = ssl_ctx_fake_private_key(rlay->rl_tls_cert,
+                   rlay->rl_conf.tls_cert_len, &fake_key)) == -1) {
+                       /* error already printed */
+                       goto err;
+               }
 
-       log_debug("%s: loading private key", __func__);
-       if (!ssl_ctx_fake_private_key(ctx,
-           &rlay->rl_conf.tls_keyid, sizeof(rlay->rl_conf.tls_keyid),
-           rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len,
-           &rlay->rl_tls_x509, &rlay->rl_tls_pkey))
-               goto err;
+               if (tls_config_set_keypair_ocsp_mem(tls_cfg,
+                   rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len,
+                   fake_key, fake_keylen, NULL, 0) != 0) {
+                       log_warnx("failed to set tls certificate: %s",
+                           tls_config_error(tls_cfg));
+                       goto err;
+               }
 
-       if (!SSL_CTX_check_private_key(ctx))
-               goto err;
+               if (rlay->rl_conf.tls_cacert_len) {
+                       log_debug("%s: loading CA certificate", __func__);
+                       if (!ssl_load_pkey(&rlay->rl_conf.tls_cakeyid,
+                           rlay->rl_tls_cacert, rlay->rl_conf.tls_cacert_len,
+                           &rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
+                               goto err;
+                       /* loading certificate public key */
+                       if (!ssl_load_pkey(NULL,
+                           rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len,
+                           NULL, &rlay->rl_tls_pkey))
+                               goto err;
+               }
 
-       if (rlay->rl_conf.tls_cacert_len) {
-               log_debug("%s: loading CA private key", __func__);
-               if (!ssl_load_pkey(&rlay->rl_conf.tls_cakeyid,
-                   sizeof(rlay->rl_conf.tls_cakeyid),
-                   rlay->rl_tls_cacert, rlay->rl_conf.tls_cacert_len,
-                   &rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
+               tls = tls_server();
+               if (tls == NULL) {
+                       log_warnx("unable to allocate TLS context");
                        goto err;
+               }
+               if (tls_configure(tls, tls_cfg) == -1) {
+                       log_warnx("could not configure the TLS context: %s",
+                           tls_error(tls));
+                       tls_free(tls);
+                       goto err;
+               }
+               rlay->rl_tls_cfg = tls_cfg;
+               rlay->rl_tls_ctx = tls;
        }
 
-       /*
-        * Set session ID context to a random value. It needs to be the
-        * same accross all relay processes or session caching will fail.
-        */
-       if (!SSL_CTX_set_session_id_context(ctx, env->sc_conf.tls_sid,
-           sizeof(env->sc_conf.tls_sid)))
-               goto err;
-
        /* The text versions of the keys/certs are not needed anymore */
        purge_key(&rlay->rl_tls_cert, rlay->rl_conf.tls_cert_len);
        purge_key(&rlay->rl_tls_cacert, rlay->rl_conf.tls_cacert_len);
 
-       return (ctx);
+       if (rlay->rl_tls_client_cfg == NULL)
+               tls_config_free(tls_client_cfg);
+       if (rlay->rl_tls_cfg == NULL)
+               tls_config_free(tls_cfg);
 
+       return (0);
  err:
-       SSL_CTX_free(ctx);
-       ssl_error(rlay->rl_conf.name, "relay_tls_ctx_create");
-       return (NULL);
+       tls_config_free(tls_client_cfg);
+       tls_config_free(tls_cfg);
+       return (-1);
 }
 
-void
-relay_tls_transaction(struct rsession *con, struct ctl_relay_event *cre)
+static struct tls *
+relay_tls_inspect_create(struct relay *rlay, struct ctl_relay_event *cre)
 {
-       struct relay            *rlay = con->se_relay;
-       SSL                     *ssl;
-       const SSL_METHOD        *method;
-       void                    (*cb)(int, short, void *);
-       u_int                    flag;
-
-       ssl = SSL_new(rlay->rl_ssl_ctx);
-       if (ssl == NULL)
+       struct tls_config       *tls_cfg;
+       struct tls              *tls;
+       const char              *fake_key;
+       int                      fake_keylen;
+
+       /* TLS inspection: use session-specific certificate */
+       if ((tls_cfg = tls_config_new()) == NULL) {
+               log_warnx("unable to allocate TLS config");
+               goto err;
+       }
+       if (relay_tls_ctx_create_proto(rlay->rl_proto,
+           tls_cfg) == -1) {
+               tls_config_free(tls_cfg);
                goto err;
-
-       if (cre->dir == RELAY_DIR_REQUEST) {
-               cb = relay_tls_accept;
-               method = SSLv23_server_method();
-               flag = EV_READ;
-
-               /* Use session-specific certificate for TLS inspection. */
-               if (cre->tlscert != NULL)
-                       SSL_use_certificate(ssl, cre->tlscert);
-       } else {
-               cb = relay_tls_connect;
-               method = SSLv23_client_method();
-               flag = EV_WRITE;
        }
 
-       if (!SSL_set_ssl_method(ssl, method))
+       log_debug("%s: loading intercepted certificate", __func__);
+       if ((fake_keylen = ssl_ctx_fake_private_key(cre->tlscert,
+           cre->tlscert_len, &fake_key)) == -1) {
+               /* error already printed */
                goto err;
-       if (!SSL_set_fd(ssl, cre->s))
+       }
+       if (tls_config_set_keypair_ocsp_mem(tls_cfg,
+           cre->tlscert, cre->tlscert_len, fake_key, fake_keylen,
+           NULL, 0) != 0) {
+               log_warnx("failed to set tls certificate: %s",
+                   tls_config_error(tls_cfg));
                goto err;
+       }
 
-       if (cre->dir == RELAY_DIR_REQUEST)
-               SSL_set_accept_state(ssl);
-       else
-               SSL_set_connect_state(ssl);
-
-       SSL_set_app_data(ssl, cre);
-       cre->ssl = ssl;
-
-       DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
-           (flag == EV_READ) ? "EV_READ" : "EV_WRITE");
-       event_again(&con->se_ev, cre->s, EV_TIMEOUT|flag, cb,
-           &con->se_tv_start, &rlay->rl_conf.timeout, con);
-       return;
+       tls = tls_server();
+       if (tls == NULL) {
+               log_warnx("unable to allocate TLS context");
+               goto err;
+       }
+       if (tls_configure(tls, tls_cfg) == -1) {
+               log_warnx("could not configure the TLS context: %s",
+                   tls_error(tls));
+               tls_free(tls);
+               goto err;
+       }
 
+       cre->tls_cfg = tls_cfg;
+       return (tls);
  err:
-       SSL_free(ssl);
-       ssl_error(rlay->rl_conf.name, "relay_tls_transaction");
-       relay_close(con, "session tls failed");
+       tls_config_free(tls_cfg);
+       return (NULL);
 }
 
 void
-relay_tls_accept(int fd, short event, void *arg)
+relay_tls_transaction(struct rsession *con, struct ctl_relay_event *cre)
 {
-       struct rsession *con = arg;
-       struct relay    *rlay = con->se_relay;
-       int              retry_flag = 0;
-       int              tls_err = 0;
-       int              ret;
-
-       if (event == EV_TIMEOUT) {
-               relay_close(con, "TLS accept timeout");
-               return;
-       }
+       struct relay            *rlay = con->se_relay;
+       struct tls              *tls_server;
+       const char              *errstr;
+       u_int                    flag;
 
-       ret = SSL_accept(con->se_in.ssl);
-       if (ret <= 0) {
-               tls_err = SSL_get_error(con->se_in.ssl, ret);
+       if (cre->dir == RELAY_DIR_REQUEST) {
+               if (cre->tlscert != NULL)
+                       tls_server = relay_tls_inspect_create(rlay, cre);
+               else
+                       tls_server = rlay->rl_tls_ctx;
 
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       retry_flag = EV_READ;
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       retry_flag = EV_WRITE;
-                       goto retry;
-               case SSL_ERROR_ZERO_RETURN:
-               case SSL_ERROR_SYSCALL:
-                       if (ret == 0) {
-                               relay_close(con, "closed");
-                               return;
-                       }
-                       /* FALLTHROUGH */
-               default:
-                       ssl_error(rlay->rl_conf.name, "relay_tls_accept");
-                       relay_close(con, "TLS accept error");
-                       return;
+               if (tls_accept_socket(tls_server, &cre->tls, cre->s) == -1) {
+                       errstr = "could not accept the TLS connection";
+                       goto err;
+               }
+               if (cre->tlscert != NULL)
+                       tls_free(tls_server);
+               flag = EV_READ;
+       } else {
+               cre->tls = tls_client();
+               if (cre->tls == NULL ||
+                   tls_configure(cre->tls, rlay->rl_tls_client_cfg) == -1) {
+                       errstr = "could not configure the TLS client context";
+                       goto err;
                }
+               if (tls_connect_socket(cre->tls, cre->s, NULL) == -1) {
+                       errstr = "could not connect the TLS connection";
+                       goto err;
+               }
+               flag = EV_WRITE;
        }
 
-
-#ifdef DEBUG
-       log_info(
-#else
-       log_debug(
-#endif
-           "relay %s, session %d established (%d active)",
-           rlay->rl_conf.name, con->se_id, relay_sessions);
-
-       relay_session(con);
+       log_debug("%s: session %d: scheduling on %s", __func__, con->se_id,
+           (flag == EV_READ) ? "EV_READ" : "EV_WRITE");
+       event_again(&con->se_ev, cre->s, EV_TIMEOUT|flag, relay_tls_handshake,
+           &con->se_tv_start, &rlay->rl_conf.timeout, cre);
        return;
 
-retry:
-       DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
-           (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
-       event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_tls_accept,
-           &con->se_tv_start, &rlay->rl_conf.timeout, con);
+ err:
+       relay_close(con, errstr);
 }
 
 void
-relay_tls_connect(int fd, short event, void *arg)
+relay_tls_handshake(int fd, short event, void *arg)
 {
-       struct rsession *con = arg;
-       struct relay    *rlay = con->se_relay;
-       int              retry_flag = 0;
-       int              tls_err = 0;
-       int              ret;
-       X509            *servercert = NULL;
+       struct ctl_relay_event  *cre = arg;
+       struct rsession         *con = cre->con;
+       struct relay            *rlay = con->se_relay;
+       int                      retry_flag = 0;
+       int                      ret;
 
        if (event == EV_TIMEOUT) {
-               relay_close(con, "TLS connect timeout");
+               relay_close(con, "TLS handshake timeout");
                return;
        }
 
-       ret = SSL_connect(con->se_out.ssl);
-       if (ret <= 0) {
-               tls_err = SSL_get_error(con->se_out.ssl, ret);
-
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       retry_flag = EV_READ;
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       retry_flag = EV_WRITE;
-                       goto retry;
-               case SSL_ERROR_ZERO_RETURN:
-               case SSL_ERROR_SYSCALL:
-                       if (ret == 0) {
-                               relay_close(con, "closed");
-                               return;
-                       }
-                       /* FALLTHROUGH */
-               default:
-                       ssl_error(rlay->rl_conf.name, "relay_tls_connect");
-                       relay_close(con, "TLS connect error");
-                       return;
-               }
-       }
-
+       ret = tls_handshake(cre->tls);
+       if (ret == 0) {
 #ifdef DEBUG
-       log_info(
+               log_info(
 #else
-       log_debug(
+               log_debug(
 #endif
-           "relay %s, tls session %d connected (%d active)",
-           rlay->rl_conf.name, con->se_id, relay_sessions);
+                   "relay %s, tls session %d %s (%d active)",
+                   rlay->rl_conf.name, con->se_id,
+                   cre->dir == RELAY_DIR_REQUEST ? "established" : "connected",
+                   relay_sessions);
 
-       if (rlay->rl_conf.flags & F_TLSINSPECT) {
-               if ((servercert =
-                   SSL_get_peer_certificate(con->se_out.ssl)) != NULL) {
-                       con->se_in.tlscert =
-                           ssl_update_certificate(servercert,
-                           rlay->rl_tls_pkey, rlay->rl_tls_capkey,
-                           rlay->rl_tls_cacertx509);
-               } else
-                       con->se_in.tlscert = NULL;
-               if (servercert != NULL)
-                       X509_free(servercert);
-               if (con->se_in.tlscert == NULL)
-                       relay_close(con, "could not create certificate");
-               else
+               if (cre->dir == RELAY_DIR_REQUEST) {
                        relay_session(con);
+                       return;
+               }
+
+               if (rlay->rl_conf.flags & F_TLSINSPECT) {
+                       const uint8_t   *servercert;
+                       size_t           len;
+
+                       servercert = tls_peer_cert_chain_pem(con->se_out.tls,
+                           &len);
+                       if (servercert != NULL) {
+                               con->se_in.tlscert = ssl_update_certificate(
+                                   servercert, len,
+                                   rlay->rl_tls_pkey, rlay->rl_tls_capkey,
+                                   rlay->rl_tls_cacertx509,
+                                   &con->se_in.tlscert_len);
+                       } else
+                               con->se_in.tlscert = NULL;
+                       if (con->se_in.tlscert == NULL)
+                               relay_close(con,
+                                   "could not create certificate");
+                       else
+                               relay_session(con);
+                       return;
+               }
+               relay_connected(fd, EV_WRITE, con);
+               return;
+       } else if (ret == TLS_WANT_POLLIN) {
+               retry_flag = EV_READ;
+       } else if (ret == TLS_WANT_POLLOUT) {
+               retry_flag = EV_WRITE;
+       } else {
+               log_debug("TLS handshake failed: %s: %s: %s",
+                   rlay->rl_conf.name, __func__,
+                   tls_error(cre->tls));
+               relay_close(con, "TLS handshake error");
                return;
        }
 
-       relay_connected(fd, EV_WRITE, con);
-       return;
-
-retry:
        DPRINTF("%s: session %d: scheduling on %s", __func__, con->se_id,
            (retry_flag == EV_READ) ? "EV_READ" : "EV_WRITE");
-       event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_tls_connect,
-           &con->se_tv_start, &rlay->rl_conf.timeout, con);
+       event_again(&con->se_ev, fd, EV_TIMEOUT|retry_flag, relay_tls_handshake,
+           &con->se_tv_start, &rlay->rl_conf.timeout, cre);
 }
 
 void
@@ -2365,11 +2330,9 @@ relay_tls_readcb(int fd, short event, vo
        char                     rbuf[IBUF_READ_SIZE];
        struct bufferevent      *bufev = arg;
        struct ctl_relay_event  *cre = bufev->cbarg;
-       struct rsession         *con = cre->con;
-       struct relay            *rlay = con->se_relay;
-       int                      ret = 0, tls_err = 0;
        short                    what = EVBUFFER_READ;
        int                      howmuch = IBUF_READ_SIZE;
+       ssize_t                  ret;
        size_t                   len;
 
        if (event == EV_TIMEOUT) {
@@ -2380,29 +2343,18 @@ relay_tls_readcb(int fd, short event, vo
        if (bufev->wm_read.high != 0)
                howmuch = MINIMUM(sizeof(rbuf), bufev->wm_read.high);
 
-       ret = SSL_read(cre->ssl, rbuf, howmuch);
-       if (ret <= 0) {
-               tls_err = SSL_get_error(cre->ssl, ret);
-
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       DPRINTF("%s: session %d: want read",
-                           __func__, con->se_id);
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       DPRINTF("%s: session %d: want write",
-                           __func__, con->se_id);
-                       goto retry;
-               default:
-                       if (ret == 0)
-                               what |= EVBUFFER_EOF;
-                       else {
-                               ssl_error(rlay->rl_conf.name,
-                                   "relay_tls_readcb");
-                               what |= EVBUFFER_ERROR;
-                       }
-                       goto err;
-               }
+       ret = tls_read(cre->tls, rbuf, howmuch);
+       if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
+               goto retry;
+       } else if (ret < 0) {
+               what |= EVBUFFER_ERROR;
+               goto err;
+       }
+       len = ret;
+
+       if (len == 0) {
+               what |= EVBUFFER_EOF;
+               goto err;
        }
 
        if (evbuffer_add(bufev->input, rbuf, ret) == -1) {
@@ -2439,9 +2391,8 @@ relay_tls_writecb(int fd, short event, v
 {
        struct bufferevent      *bufev = arg;
        struct ctl_relay_event  *cre = bufev->cbarg;
-       struct rsession         *con = cre->con;
-       struct relay            *rlay = con->se_relay;
-       int                      ret = 0, tls_err;
+       ssize_t                  ret;
+       size_t                   len;
        short                    what = EVBUFFER_WRITE;
 
        if (event == EV_TIMEOUT) {
@@ -2450,46 +2401,16 @@ relay_tls_writecb(int fd, short event, v
        }
 
        if (EVBUFFER_LENGTH(bufev->output)) {
-               if (cre->buf == NULL) {
-                       cre->buflen = EVBUFFER_LENGTH(bufev->output);
-                       if ((cre->buf = malloc(cre->buflen)) == NULL) {
-                               what |= EVBUFFER_ERROR;
-                               goto err;
-                       }
-                       bcopy(EVBUFFER_DATA(bufev->output),
-                           cre->buf, cre->buflen);
-               }
-
-               ret = SSL_write(cre->ssl, cre->buf, cre->buflen);
-               if (ret <= 0) {
-                       tls_err = SSL_get_error(cre->ssl, ret);
-
-                       switch (tls_err) {
-                       case SSL_ERROR_WANT_READ:
-                               DPRINTF("%s: session %d: want read",
-                                   __func__, con->se_id);
-                               goto retry;
-                       case SSL_ERROR_WANT_WRITE:
-                               DPRINTF("%s: session %d: want write",
-                                   __func__, con->se_id);
-                               goto retry;
-                       default:
-                               if (ret == 0)
-                                       what |= EVBUFFER_EOF;
-                               else {
-                                       ssl_error(rlay->rl_conf.name,
-                                           "relay_tls_writecb");
-                                       what |= EVBUFFER_ERROR;
-                               }
-                               goto err;
-                       }
+               ret = tls_write(cre->tls, EVBUFFER_DATA(bufev->output),
+                   EVBUFFER_LENGTH(bufev->output));
+               if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) {
+                       goto retry;
+               } else if (ret < 0) {
+                       what |= EVBUFFER_ERROR;
+                       goto err;
                }
-               evbuffer_drain(bufev->output, ret);
-       }
-       if (cre->buf != NULL) {
-               free(cre->buf);
-               cre->buf = NULL;
-               cre->buflen = 0;
+               len = ret;
+               evbuffer_drain(bufev->output, len);
        }
 
        if (EVBUFFER_LENGTH(bufev->output) != 0)
@@ -2501,69 +2422,11 @@ relay_tls_writecb(int fd, short event, v
        return;
 
  retry:
-       if (cre->buflen != 0)
-               relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+       relay_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
        return;
 
  err:
-       if (cre->buf != NULL) {
-               free(cre->buf);
-               cre->buf = NULL;
-               cre->buflen = 0;
-       }
        (*bufev->errorcb)(bufev, what, bufev->cbarg);
-}
-
-struct tls_ticket *
-relay_get_ticket_key(unsigned char *keyname)
-{
-       if (keyname) {
-               if (timingsafe_memcmp(keyname,
-                   env->sc_tls_ticket_bak.tt_key_name,
-                   sizeof(env->sc_tls_ticket_bak.tt_key_name)) == 0)
-                       return &env->sc_tls_ticket_bak;
-               if (timingsafe_memcmp(keyname,
-                   env->sc_tls_ticket.tt_key_name,
-                   sizeof(env->sc_tls_ticket.tt_key_name)) == 0)
-                       return &env->sc_tls_ticket;
-               return NULL;
-       }
-       return &env->sc_tls_ticket;
-}
-
-int
-relay_tls_session_ticket(SSL *ssl, unsigned char *keyname, unsigned char *iv,
-    EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int mode)
-{
-       struct tls_ticket       *key;
-
-       if (mode == 1) {
-               /* create new session */
-               key = relay_get_ticket_key(NULL);
-               memcpy(keyname, key->tt_key_name, sizeof(key->tt_key_name));
-               arc4random_buf(iv, EVP_MAX_IV_LENGTH);
-               EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL,
-                   key->tt_aes_key, iv);
-               HMAC_Init_ex(hctx, key->tt_hmac_key, sizeof(key->tt_hmac_key),
-                   EVP_sha256(), NULL);
-               return 0;
-       } else {
-               /* get key by name */
-               key = relay_get_ticket_key(keyname);
-               if  (!key)
-                       return 0;
-
-               EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL,
-                   key->tt_aes_key, iv);
-               HMAC_Init_ex(hctx, key->tt_hmac_key, sizeof(key->tt_hmac_key),
-                   EVP_sha256(), NULL);
-
-               /* time to renew the ticket? */
-               if (key->tt_backup) {
-                       return 2;
-               }
-               return 1;
-       }
 }
 
 int
Index: relay_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
retrieving revision 1.64
diff -u -p -r1.64 relay_http.c
--- relay_http.c        10 Mar 2017 21:04:35 -0000      1.64
+++ relay_http.c        13 Mar 2017 09:37:31 -0000
@@ -715,11 +715,6 @@ relay_reset_http(struct ctl_relay_event 
        struct http_descriptor  *desc = cre->desc;
 
        relay_httpdesc_free(desc);
-       if (cre->buf != NULL) {
-               free(cre->buf);
-               cre->buf = NULL;
-               cre->buflen = 0;
-       }
        desc->http_method = 0;
        desc->http_chunked = 0;
        cre->headerlen = 0;
Index: relayd.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v
retrieving revision 1.166
diff -u -p -r1.166 relayd.c
--- relayd.c    6 May 2017 19:44:53 -0000       1.166
+++ relayd.c    9 May 2017 12:03:04 -0000
@@ -43,7 +43,7 @@
 #include <sha1.h>
 #include <md5.h>
 
-#include <openssl/ssl.h>
+#include <tls.h>
 
 #include "relayd.h"
 
@@ -530,12 +530,11 @@ purge_table(struct relayd *env, struct t
                        close(host->cte.s);
                }
                ibuf_free(host->cte.buf);
-               SSL_free(host->cte.ssl);
+               tls_free(host->cte.tls);
                free(host);
        }
        free(table->sendbuf);
-       if (table->conf.flags & F_TLS)
-               SSL_CTX_free(table->ssl_ctx);
+       tls_config_free(table->tls_cfg);
 
        if (head != NULL)
                TAILQ_REMOVE(head, table, entry);
@@ -578,10 +577,6 @@ purge_relay(struct relayd *env, struct r
        purge_key(&rlay->rl_tls_ca, rlay->rl_conf.tls_ca_len);
        purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len);
 
-       if (rlay->rl_tls_x509 != NULL) {
-               X509_free(rlay->rl_tls_x509);
-               rlay->rl_tls_x509 = NULL;
-       }
        if (rlay->rl_tls_pkey != NULL) {
                EVP_PKEY_free(rlay->rl_tls_pkey);
                rlay->rl_tls_pkey = NULL;
@@ -595,7 +590,9 @@ purge_relay(struct relayd *env, struct r
                rlay->rl_tls_capkey = NULL;
        }
 
-       SSL_CTX_free(rlay->rl_ssl_ctx);
+       tls_free(rlay->rl_tls_ctx);
+       tls_config_free(rlay->rl_tls_cfg);
+       tls_config_free(rlay->rl_tls_client_cfg);
 
        while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) {
                TAILQ_REMOVE(&rlay->rl_tables, rlt, rlt_entry);
@@ -1166,18 +1163,18 @@ relay_findbyaddr(struct relayd *env, str
 }
 
 EVP_PKEY *
-pkey_find(struct relayd *env, objid_t id)
+pkey_find(struct relayd *env, char * hash)
 {
        struct ca_pkey  *pkey;
 
        TAILQ_FOREACH(pkey, env->sc_pkeys, pkey_entry)
-               if (pkey->pkey_id == id)
+               if (strcmp(hash, pkey->pkey_hash) == 0)
                        return (pkey->pkey);
        return (NULL);
 }
 
 struct ca_pkey *
-pkey_add(struct relayd *env, EVP_PKEY *pkey, objid_t id)
+pkey_add(struct relayd *env, EVP_PKEY *pkey, char *hash)
 {
        struct ca_pkey  *ca_pkey;
 
@@ -1188,8 +1185,10 @@ pkey_add(struct relayd *env, EVP_PKEY *p
                return (NULL);
 
        ca_pkey->pkey = pkey;
-       ca_pkey->pkey_id = id;
-
+       if (strlcpy(ca_pkey->pkey_hash, hash, sizeof(ca_pkey->pkey_hash)) >=
+           sizeof(ca_pkey->pkey_hash))
+               return (NULL);
+               
        TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry);
 
        return (ca_pkey);
@@ -1638,20 +1637,18 @@ parent_tls_ticket_rekey(int fd, short ev
        static struct event      rekeyev;
        struct relayd           *env = arg;
        struct timeval           tv;
-       struct tls_ticket        key;
+       struct relay_ticket_key  key;
 
        log_debug("relayd_tls_ticket_rekey: rekeying tickets");
 
-       arc4random_buf(key.tt_key_name, sizeof(key.tt_key_name));
-       arc4random_buf(key.tt_hmac_key, sizeof(key.tt_hmac_key));
-       arc4random_buf(key.tt_aes_key, sizeof(key.tt_aes_key));
-       key.tt_backup = 0;
+       key.tt_keyrev = arc4random();
+       arc4random_buf(key.tt_key, sizeof(key.tt_key));
 
        proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TLSTICKET_REKEY,
            -1, -1, &key, sizeof(key));
 
        evtimer_set(&rekeyev, parent_tls_ticket_rekey, env);
        timerclear(&tv);
-       tv.tv_sec = TLS_TICKET_REKEY_TIME;
+       tv.tv_sec = TLS_SESSION_LIFETIME / 4;
        evtimer_add(&rekeyev, &tv);
 }
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.239
diff -u -p -r1.239 relayd.h
--- relayd.h    2 Feb 2017 08:24:16 -0000       1.239
+++ relayd.h    15 May 2017 18:57:48 -0000
@@ -37,6 +37,7 @@
 #include <imsg.h>
 
 #include <openssl/ssl.h>
+#include <tls.h>
 
 #ifndef nitems
 #define        nitems(_a)      (sizeof((_a)) / sizeof((_a)[0]))
@@ -61,6 +62,7 @@
 #define MAX_NAME_SIZE          64
 #define SRV_MAX_VIRTS          16
 #define TLS_NAME_SIZE          512
+#define TLS_CERT_HASH_SIZE     128
 #define RELAY_MAX_PREFETCH     256
 #define RELAY_MIN_PREFETCHED   32
 
@@ -166,7 +168,7 @@ struct ctl_tcp_event {
        int                     (*validate_read)(struct ctl_tcp_event *);
        int                     (*validate_close)(struct ctl_tcp_event *);
 
-       SSL                     *ssl;   /* libssl object */
+       struct tls              *tls;
 };
 
 enum direction {
@@ -192,9 +194,11 @@ struct ctl_relay_event {
        struct ctl_relay_event  *dst;
        struct rsession         *con;
 
-       SSL                     *ssl;   /* libssl object */
+       struct tls              *tls;
+       struct tls_config       *tls_cfg;
 
-       X509                    *tlscert;
+       uint8_t                 *tlscert;
+       size_t                   tlscert_len;
 
        off_t                    splicelen;
        off_t                    toread;
@@ -205,9 +209,6 @@ struct ctl_relay_event {
        enum relay_state         state;
        enum direction           dir;
 
-       u_int8_t                *buf;
-       int                      buflen;
-
        /* protocol-specific descriptor */
        void                    *desc;
 };
@@ -243,7 +244,7 @@ struct ctl_bindany {
 };
 
 struct ctl_keyop {
-       objid_t                  cko_id;
+       char                     cko_hash[TLS_CERT_HASH_SIZE];
        int                      cko_proc;
        int                      cko_flen;
        int                      cko_tlen;
@@ -496,7 +497,7 @@ struct table {
        int                      up;
        int                      skipped;
        struct hostlist          hosts;
-       SSL_CTX                 *ssl_ctx;       /* libssl context */
+       struct tls_config       *tls_cfg;
        char                    *sendbuf;
 };
 TAILQ_HEAD(tablelist, table);
@@ -680,20 +681,14 @@ TAILQ_HEAD(relay_rules, relay_rule);
        "\06cipher-server-preference\07client-renegotiation"
 
 #define TLSCIPHERS_DEFAULT     "HIGH:!aNULL"
-#define TLSECDHCURVE_DEFAULT   NID_X9_62_prime256v1
+#define TLSECDHCURVE_DEFAULT   "auto"
+#define TLSDHPARAM_DEFAULT     "none"
 
-#define TLSDHPARAMS_NONE       0
-#define TLSDHPARAMS_DEFAULT    0
-#define TLSDHPARAMS_MIN                1024
-
-struct tls_ticket {
-       /* The key, aes key and hmac key must be 16 bytes / 128bits */
-       unsigned char   tt_key_name[16];
-       unsigned char   tt_aes_key[16];
-       unsigned char   tt_hmac_key[16];
-       int             tt_backup;
+struct relay_ticket_key {
+       uint32_t        tt_keyrev;
+       unsigned char   tt_key[TLS_TICKET_KEY_SIZE];
 };
-#define        TLS_TICKET_REKEY_TIME   (2 * 3600)
+#define        TLS_SESSION_LIFETIME    (2 * 3600)
 
 struct protocol {
        objid_t                  id;
@@ -705,8 +700,8 @@ struct protocol {
        u_int8_t                 tcpipminttl;
        u_int8_t                 tlsflags;
        char                     tlsciphers[768];
-       int                      tlsdhparams;
-       int                      tlsecdhcurve;
+       char                     tlsdhparams[128];
+       char                     tlsecdhcurve[128];
        char                     tlsca[PATH_MAX];
        char                     tlscacert[PATH_MAX];
        char                     tlscakey[PATH_MAX];
@@ -742,7 +737,7 @@ struct relay_table {
 TAILQ_HEAD(relaytables, relay_table);
 
 struct ca_pkey {
-       objid_t                  pkey_id;
+       char                     pkey_hash[TLS_CERT_HASH_SIZE];
        EVP_PKEY                *pkey;
        TAILQ_ENTRY(ca_pkey)     pkey_entry;
 };
@@ -788,10 +783,11 @@ struct relay {
        struct event             rl_ev;
        struct event             rl_evt;
 
-       SSL_CTX                 *rl_ssl_ctx;    /* libssl context */
+       struct tls_config       *rl_tls_cfg;
+       struct tls_config       *rl_tls_client_cfg;
+       struct tls              *rl_tls_ctx;
 
        char                    *rl_tls_cert;
-       X509                    *rl_tls_x509;
        char                    *rl_tls_key;
        EVP_PKEY                *rl_tls_pkey;
        char                    *rl_tls_ca;
@@ -1092,11 +1088,10 @@ struct relayd {
        struct ctl_icmp_event    sc_icmp6_send;
        struct ctl_icmp_event    sc_icmp6_recv;
 
+       struct relay_ticket_key  sc_ticket;
+
        struct privsep          *sc_ps;
        int                      sc_reload;
-
-       struct tls_ticket        sc_tls_ticket;
-       struct tls_ticket        sc_tls_ticket_bak;
 };
 
 #define RELAYD_OPT_VERBOSE             0x01
@@ -1237,6 +1232,9 @@ void       check_icmp(struct relayd *, struct
 /* check_tcp.c */
 void    check_tcp(struct ctl_tcp_event *);
 
+/* check_tls.c */
+void    check_tls(struct ctl_tcp_event *);
+
 /* check_script.c */
 void    check_script(struct relayd *, struct host *);
 void    script_done(struct relayd *, struct ctl_script *);
@@ -1244,15 +1242,11 @@ int      script_exec(struct relayd *, struct
 
 /* ssl.c */
 void    ssl_init(struct relayd *);
-void    ssl_transaction(struct ctl_tcp_event *);
-SSL_CTX        *ssl_ctx_create(struct relayd *);
-void    ssl_error(const char *, const char *);
 char   *ssl_load_key(struct relayd *, const char *, off_t *, char *);
-X509   *ssl_update_certificate(X509 *, EVP_PKEY *, EVP_PKEY *, X509 *);
-int     ssl_load_pkey(const void *, size_t, char *, off_t,
-           X509 **, EVP_PKEY **);
-int     ssl_ctx_fake_private_key(SSL_CTX *, const void *, size_t,
-           char *, off_t, X509 **, EVP_PKEY **);
+uint8_t *ssl_update_certificate(const uint8_t *, size_t, EVP_PKEY *,
+           EVP_PKEY *, X509 *, size_t *);
+int     ssl_load_pkey(void *, char *, off_t, X509 **, EVP_PKEY **);
+int     ssl_ctx_fake_private_key(char *, off_t, const char **);
 
 /* ca.c */
 void    ca(struct privsep *, struct privsep_proc *);
@@ -1276,8 +1270,8 @@ struct protocol   *proto_find(struct relay
 struct rsession        *session_find(struct relayd *, objid_t);
 struct relay   *relay_findbyname(struct relayd *, const char *);
 struct relay   *relay_findbyaddr(struct relayd *, struct relay_config *);
-EVP_PKEY       *pkey_find(struct relayd *, objid_t);
-struct ca_pkey *pkey_add(struct relayd *, EVP_PKEY *, objid_t);
+EVP_PKEY       *pkey_find(struct relayd *, char *hash);
+struct ca_pkey *pkey_add(struct relayd *, EVP_PKEY *, char *hash);
 int             expand_string(char *, size_t, const char *, const char *);
 void            translate_string(char *);
 void            purge_key(char **, off_t);
Index: ssl.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ssl.c,v
retrieving revision 1.31
diff -u -p -r1.31 ssl.c
--- ssl.c       9 Jan 2017 14:49:21 -0000       1.31
+++ ssl.c       27 Mar 2017 00:39:43 -0000
@@ -18,12 +18,9 @@
  */
 
 #include <sys/types.h>
-#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
 
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <event.h>
 #include <unistd.h>
 #include <string.h>
 #include <imsg.h>
@@ -33,208 +30,11 @@
 #include <openssl/engine.h>
 
 #include "relayd.h"
+#include "boguskeys.h"
 
-void   ssl_read(int, short, void *);
-void   ssl_write(int, short, void *);
-void   ssl_connect(int, short, void *);
-void   ssl_cleanup(struct ctl_tcp_event *);
 int    ssl_password_cb(char *, int, int, void *);
 
 void
-ssl_read(int s, short event, void *arg)
-{
-       char                     rbuf[SMALL_READ_BUF_SIZE];
-       struct ctl_tcp_event    *cte = arg;
-       int                      retry_flag = EV_READ;
-       int                      tls_err = 0;
-       int                      ret;
-
-       if (event == EV_TIMEOUT) {
-               cte->host->up = HOST_DOWN;
-               ssl_cleanup(cte);
-               hce_notify_done(cte->host, HCE_TLS_READ_TIMEOUT);
-               return;
-       }
-
-       bzero(rbuf, sizeof(rbuf));
-
-       ret = SSL_read(cte->ssl, rbuf, sizeof(rbuf));
-       if (ret <= 0) {
-               tls_err = SSL_get_error(cte->ssl, ret);
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       retry_flag = EV_READ;
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       retry_flag = EV_WRITE;
-                       goto retry;
-               case SSL_ERROR_ZERO_RETURN: /* FALLTHROUGH */
-               case SSL_ERROR_SYSCALL:
-                       if (ret == 0) {
-                               cte->host->up = HOST_DOWN;
-                               (void)cte->validate_close(cte);
-                               ssl_cleanup(cte);
-                               hce_notify_done(cte->host, cte->host->he);
-                               return;
-                       }
-                       /* FALLTHROUGH */
-               default:
-                       cte->host->up = HOST_DOWN;
-                       ssl_error(cte->host->conf.name, "cannot read");
-                       ssl_cleanup(cte);
-                       hce_notify_done(cte->host, HCE_TLS_READ_ERROR);
-                       break;
-               }
-               return;
-       }
-       if (ibuf_add(cte->buf, rbuf, ret) == -1)
-               fatal("ssl_read: buf_add error");
-       if (cte->validate_read != NULL) {
-               if (cte->validate_read(cte) != 0)
-                       goto retry;
-
-               ssl_cleanup(cte);
-               hce_notify_done(cte->host, cte->host->he);
-               return;
-       }
-
-retry:
-       event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_read,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-       return;
-}
-
-void
-ssl_write(int s, short event, void *arg)
-{
-       struct ctl_tcp_event    *cte = arg;
-       int                      retry_flag = EV_WRITE;
-       int                      tls_err = 0;
-       int                      len;
-       int                      ret;
-
-       if (event == EV_TIMEOUT) {
-               cte->host->up = HOST_DOWN;
-               ssl_cleanup(cte);
-               hce_notify_done(cte->host, HCE_TLS_WRITE_TIMEOUT);
-               return;
-       }
-
-       len = strlen(cte->table->sendbuf);
-
-       ret = SSL_write(cte->ssl, cte->table->sendbuf, len);
-       if (ret <= 0) {
-               tls_err = SSL_get_error(cte->ssl, ret);
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       retry_flag = EV_READ;
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       retry_flag = EV_WRITE;
-                       goto retry;
-               default:
-                       cte->host->up = HOST_DOWN;
-                       ssl_error(cte->host->conf.name, "cannot write");
-                       ssl_cleanup(cte);
-                       hce_notify_done(cte->host, HCE_TLS_WRITE_ERROR);
-                       return;
-               }
-       }
-       if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
-               fatalx("ssl_write: cannot create dynamic buffer");
-
-       event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, ssl_read,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-       return;
-retry:
-       event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_write,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-}
-
-void
-ssl_connect(int s, short event, void *arg)
-{
-       struct ctl_tcp_event    *cte = arg;
-       int                      retry_flag = 0;
-       int                      tls_err = 0;
-       int                      ret;
-
-       if (event == EV_TIMEOUT) {
-               cte->host->up = HOST_DOWN;
-               hce_notify_done(cte->host, HCE_TLS_CONNECT_TIMEOUT);
-               ssl_cleanup(cte);
-               return;
-       }
-
-       ret = SSL_connect(cte->ssl);
-       if (ret <= 0) {
-               tls_err = SSL_get_error(cte->ssl, ret);
-               switch (tls_err) {
-               case SSL_ERROR_WANT_READ:
-                       retry_flag = EV_READ;
-                       goto retry;
-               case SSL_ERROR_WANT_WRITE:
-                       retry_flag = EV_WRITE;
-                       goto retry;
-               default:
-                       cte->host->up = HOST_DOWN;
-                       ssl_error(cte->host->conf.name, "cannot connect");
-                       hce_notify_done(cte->host, HCE_TLS_CONNECT_FAIL);
-                       ssl_cleanup(cte);
-                       return;
-               }
-       }
-
-       if (cte->table->conf.check == CHECK_TCP) {
-               cte->host->up = HOST_UP;
-               hce_notify_done(cte->host, HCE_TLS_CONNECT_OK);
-               ssl_cleanup(cte);
-               return;
-       }
-       if (cte->table->sendbuf != NULL) {
-               event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_write,
-                   &cte->tv_start, &cte->table->conf.timeout, cte);
-               return;
-       }
-
-       if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
-               fatalx("ssl_connect: cannot create dynamic buffer");
-       event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, ssl_read,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-       return;
-
-retry:
-       event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_connect,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-}
-
-void
-ssl_cleanup(struct ctl_tcp_event *cte)
-{
-       close(cte->s);
-       if (cte->ssl != NULL) {
-               SSL_shutdown(cte->ssl);
-               SSL_clear(cte->ssl);
-       }
-       ibuf_free(cte->buf);
-       cte->buf = NULL;
-}
-
-void
-ssl_error(const char *where, const char *what)
-{
-       char             errbuf[128];
-       unsigned long    code;
-
-       if (log_getverbose() < 2)
-               return;
-       for (; (code = ERR_get_error()) != 0 ;) {
-               ERR_error_string_n(code, errbuf, sizeof(errbuf));
-               log_debug("SSL library error: %s: %s: %s", where, what, errbuf);
-       }
-}
-
-void
 ssl_init(struct relayd *env)
 {
        static int       initialized = 0;
@@ -252,43 +52,6 @@ ssl_init(struct relayd *env)
        initialized = 1;
 }
 
-void
-ssl_transaction(struct ctl_tcp_event *cte)
-{
-       if (cte->ssl == NULL) {
-               cte->ssl = SSL_new(cte->table->ssl_ctx);
-               if (cte->ssl == NULL) {
-                       ssl_error(cte->host->conf.name, "cannot create object");
-                       fatal("cannot create SSL object");
-               }
-       }
-
-       if (SSL_set_fd(cte->ssl, cte->s) == 0) {
-               cte->host->up = HOST_UNKNOWN;
-               ssl_error(cte->host->conf.name, "cannot set fd");
-               ssl_cleanup(cte);
-               hce_notify_done(cte->host, HCE_TLS_CONNECT_ERROR);
-               return;
-       }
-       SSL_set_connect_state(cte->ssl);
-
-       event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_connect,
-           &cte->tv_start, &cte->table->conf.timeout, cte);
-}
-
-SSL_CTX *
-ssl_ctx_create(struct relayd *env)
-{
-       SSL_CTX *ctx;
-
-       ctx = SSL_CTX_new(SSLv23_client_method());
-       if (ctx == NULL) {
-               ssl_error("ssl_ctx_create", "cannot create context");
-               fatal("could not create SSL context");
-       }
-       return (ctx);
-}
-
 int
 ssl_password_cb(char *buf, int size, int rwflag, void *u)
 {
@@ -345,8 +108,6 @@ ssl_load_key(struct relayd *env, const c
        return (buf);
 
  fail:
-       ssl_error(__func__, name);
-
        free(buf);
        if (bio != NULL)
                BIO_free_all(bio);
@@ -355,21 +116,45 @@ ssl_load_key(struct relayd *env, const c
        return (NULL);
 }
 
-X509 *
-ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey, EVP_PKEY *capkey,
-    X509 *cacert)
+uint8_t *
+ssl_update_certificate(const uint8_t *oldcert, size_t oldlen, EVP_PKEY *pkey,
+    EVP_PKEY *capkey, X509 *cacert, size_t *newlen)
 {
        char             name[2][TLS_NAME_SIZE];
+       BIO             *in, *out = NULL;
+       BUF_MEM         *bptr = NULL;
        X509            *cert = NULL;
+       uint8_t         *newcert = NULL, *foo = NULL;
+
+       /* XXX BIO_new_mem_buf is not using const so work around this */
+       if ((foo = malloc(oldlen)) == NULL) {   
+               log_warn("%s: malloc", __func__);
+               return (NULL);
+       }
+       memcpy(foo, oldcert, oldlen);
+
+       if ((in = BIO_new_mem_buf(foo, oldlen)) == NULL) {
+               log_warnx("%s: BIO_new_mem_buf failed", __func__);
+               goto done;
+       }
+
+       if ((cert = PEM_read_bio_X509(in, NULL,
+           ssl_password_cb, NULL)) == NULL) {
+               log_warnx("%s: PEM_read_bio_X509 failed", __func__);
+               goto done;
+       }
+
+       BIO_free(in);
+       in = NULL;
 
        name[0][0] = name[1][0] = '\0';
-       if (!X509_NAME_oneline(X509_get_subject_name(oldcert),
+       if (!X509_NAME_oneline(X509_get_subject_name(cert),
            name[0], sizeof(name[0])) ||
-           !X509_NAME_oneline(X509_get_issuer_name(oldcert),
+           !X509_NAME_oneline(X509_get_issuer_name(cert),
            name[1], sizeof(name[1])))
                goto done;
 
-       if ((cert = X509_dup(oldcert)) == NULL)
+       if ((cert = X509_dup(cert)) == NULL)
                goto done;
 
        /* Update certificate key and use our CA as the issuer */
@@ -377,9 +162,9 @@ ssl_update_certificate(X509 *oldcert, EV
        X509_set_issuer_name(cert, X509_get_subject_name(cacert));
 
        /* Sign with our CA */
-       if (!X509_sign(cert, capkey, EVP_sha1())) {
-               X509_free(cert);
-               cert = NULL;
+       if (!X509_sign(cert, capkey, EVP_sha256())) {
+               log_warnx("%s: X509_sign failed", __func__);
+               goto done;
        }
 
 #if DEBUG_CERT
@@ -390,15 +175,37 @@ ssl_update_certificate(X509 *oldcert, EV
 #endif
 #endif
 
- done:
-       if (cert == NULL)
-               ssl_error(__func__, name[0]);
+       /* write cert as PEM file */
+       out = BIO_new(BIO_s_mem());
+       if (out == NULL) {
+               log_warnx("%s: BIO_new failed", __func__);
+               goto done;
+       }
+       if (!PEM_write_bio_X509(out, cert)) {
+               log_warnx("%s: PEM_write_bio_X509 failed", __func__);
+               goto done;
+       }
+       BIO_get_mem_ptr(out, &bptr);
+       if ((newcert = malloc(bptr->length)) == NULL) {
+               log_warn("%s: malloc", __func__);
+               goto done;
+       }
+       memcpy(newcert, bptr->data, bptr->length);
+       *newlen = bptr->length;
 
-       return (cert);
+done:
+       free(foo);
+       if (in)
+               BIO_free(in);
+       if (out)
+               BIO_free(out);
+       if (cert)
+               X509_free(cert);
+       return (newcert);
 }
 
 int
-ssl_load_pkey(const void *data, size_t datalen, char *buf, off_t len,
+ssl_load_pkey(void *data, char *buf, off_t len,
     X509 **x509ptr, EVP_PKEY **pkeyptr)
 {
        BIO             *in;
@@ -408,36 +215,38 @@ ssl_load_pkey(const void *data, size_t d
        void            *exdata = NULL;
 
        if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
-               SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_BUF_LIB);
+               log_warnx("%s: BIO_new_mem_buf failed", __func__);
                return (0);
        }
 
        if ((x509 = PEM_read_bio_X509(in, NULL,
            ssl_password_cb, NULL)) == NULL) {
-               SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PEM_LIB);
+               log_warnx("%s: PEM_read_bio_X509 failed", __func__);
                goto fail;
        }
 
        if ((pkey = X509_get_pubkey(x509)) == NULL) {
-               SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_X509_LIB);
+               log_warnx("%s: X509_get_pubkey failed", __func__);
                goto fail;
        }
 
        BIO_free(in);
 
-       if (data != NULL && datalen) {
-               if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL ||
-                   (exdata = malloc(datalen)) == NULL) {
-                       SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_EVP_LIB);
+       if (data != NULL) {
+               if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
+                       log_warnx("%s: failed to extract RSA", __func__);
                        goto fail;
                }
 
-               memcpy(exdata, data, datalen);
-               RSA_set_ex_data(rsa, 0, exdata);
+               RSA_set_ex_data(rsa, 0, data);
                RSA_free(rsa); /* dereference, will be cleaned up with pkey */
        }
 
-       *x509ptr = x509;
+       if (x509ptr != NULL)
+               *x509ptr = x509;
+       else
+               X509_free(x509);
+
        *pkeyptr = pkey;
 
        return (1);
@@ -456,37 +265,63 @@ ssl_load_pkey(const void *data, size_t d
        return (0);
 }
 
+/*
+ * This function is a horrible hack but for RSA privsep to work a private key
+ * with correct size needs to be loaded into the tls config.
+ */
 int
-ssl_ctx_fake_private_key(SSL_CTX *ctx, const void *data, size_t datalen,
-    char *buf, off_t len, X509 **x509ptr, EVP_PKEY **pkeyptr)
+ssl_ctx_fake_private_key(char *buf, off_t len, const char **fake_key)
 {
-       int              ret = 0;
+       BIO             *in;
        EVP_PKEY        *pkey = NULL;
        X509            *x509 = NULL;
+       int              ret = -1, keylen;
 
-       if (!ssl_load_pkey(data, datalen, buf, len, &x509, &pkey))
+       if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
+               log_warnx("%s: BIO_new_mem_buf failed", __func__);
                return (0);
+       }
 
-       /*
-        * Use the public key as the "private" key - the secret key
-        * parameters are hidden in an extra process that will be
-        * contacted by the RSA engine.  The SSL/TLS library needs at
-        * least the public key parameters in the current process.
-        */
-       ret = SSL_CTX_use_PrivateKey(ctx, pkey);
-       if (!ret)
-               SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_SSL_LIB);
-
-       if (pkeyptr != NULL)
-               *pkeyptr = pkey;
-       else if (pkey != NULL)
-               EVP_PKEY_free(pkey);
+       if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) {
+               log_warnx("%s: PEM_read_bio_X509 failed", __func__);
+               goto fail;
+       }
 
-       if (x509ptr != NULL)
-               *x509ptr = x509;
-       else if (x509 != NULL)
-               X509_free(x509);
+       if ((pkey = X509_get_pubkey(x509)) == NULL) {
+               log_warnx("%s: X509_get_pubkey failed", __func__);
+               goto fail;
+       }
+
+       keylen = EVP_PKEY_size(pkey) * 8;
+       switch(keylen) {
+       case 1024:
+               *fake_key = bogus_1024;
+               ret = sizeof(bogus_1024);
+               break;
+       case 2048:
+               *fake_key = bogus_2048;
+               ret = sizeof(bogus_2048);
+               break;
+       case 4096:
+               *fake_key = bogus_4096;
+               ret = sizeof(bogus_4096);
+               break;
+       case 8192:
+               *fake_key = bogus_8192;
+               ret = sizeof(bogus_8192);
+               break;
+       default:
+               log_warnx("%s: key size %d not support", __func__, keylen);
+               ret = -1;
+               break;
+       }
+fail:
+       BIO_free(in);
 
+       if (pkey != NULL)
+               EVP_PKEY_free(pkey);
+       if (x509 != NULL)
+               X509_free(x509);
+       
        return (ret);
 }
-

Reply via email to