At the moment relayd's TLS session caching is a bit busted because
the multiple relay processes do not share state.
The following diff adds SSL session caching and sharing of the TLS ticket
secrets. Which this openssl s_client -connect W.X.Y.Z:443 -reconnect
reuses the connection after the first one.
This should help TLS preformance since no exchange with the ca process is
needed if there is a cache hit.

The shared SSL session cache is in a new process (tlsc) but we still use
the internal cache as well (which is populated on cache miss).

The TLS token secret are generated on startup and a key rollover happens
every 4h with a rekey window of 10min. I see no need to add tunables for
this and also the shared SSL cache will just use the tls session cache
settings (because OpenSSL will do the garbage collection of the external
cache via the internal one).

This is the first version which seems to work for me when hammering relayd
with openssl s_client.
-- 
:wq Claudio


Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/Makefile,v
retrieving revision 1.29
diff -u -p -r1.29 Makefile
--- Makefile    21 Nov 2015 12:37:42 -0000      1.29
+++ Makefile    19 Jul 2016 08:33:26 -0000
@@ -6,7 +6,7 @@ SRCS+=          agentx.c ca.c carp.c check_icmp.
                check_tcp.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
+               shuffle.c snmp.c ssl.c tlsc.c util.c
 MAN=           relayd.8 relayd.conf.5
 
 LDADD=         -levent -lssl -lcrypto -lutil
Index: ca.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ca.c,v
retrieving revision 1.16
diff -u -p -r1.16 ca.c
--- ca.c        5 Dec 2015 13:13:11 -0000       1.16
+++ ca.c        19 Jul 2016 13:18:33 -0000
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <poll.h>
 #include <imsg.h>
 
 #include <openssl/bio.h>
@@ -256,6 +257,7 @@ static int
 rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa,
     int padding, u_int cmd)
 {
+       struct pollfd    pfd[1];
        struct ctl_keyop cko;
        int              ret = 0;
        objid_t         *id;
@@ -292,9 +294,21 @@ rsae_send_imsg(int flen, const u_char *f
         * operation in OpenSSL's engine layer.
         */
        imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt);
-       imsg_flush(ibuf);
+       if (imsg_flush(ibuf) == -1)
+               log_warn("rsae_send_imsg: imsg_flush");
 
+       pfd[0].fd = ibuf->fd;
+       pfd[0].events = POLLIN;
        while (!done) {
+               switch (poll(pfd, 1, 5 * 1000)) {
+               case -1:
+                       fatal("rsae_send_imsg: poll");
+               case 0:
+                       log_warnx("rsae_send_imsg: poll timeout");
+                       break;
+               default:
+                       break;
+               }
                if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
                        fatalx("imsg_read");
                if (n == 0)
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
retrieving revision 1.27
diff -u -p -r1.27 config.c
--- config.c    7 Dec 2015 04:03:27 -0000       1.27
+++ config.c    18 Jul 2016 13:01:35 -0000
@@ -51,6 +51,7 @@ config_init(struct relayd *env)
                ps->ps_what[PROC_CA] = CONFIG_RELAYS;
                ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|
                    CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE;
+               ps->ps_what[PROC_TLSC] = 0;
        }
 
        /* Other configuration */
Index: relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.206
diff -u -p -r1.206 relay.c
--- relay.c     30 Dec 2015 16:00:57 -0000      1.206
+++ relay.c     19 Jul 2016 13:17:57 -0000
@@ -28,6 +28,7 @@
 #include <arpa/inet.h>
 
 #include <limits.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -54,6 +55,8 @@ int            relay_dispatch_ca(int, struct priv
                    struct imsg *);
 int             relay_dispatch_hce(int, struct privsep_proc *,
                    struct imsg *);
+int             relay_dispatch_tlsc(int, struct privsep_proc *,
+                   struct imsg *);
 void            relay_shutdown(void);
 
 void            relay_protodebug(struct relay *);
@@ -84,6 +87,13 @@ void          relay_tls_connect(int, short, voi
 void            relay_tls_connected(struct ctl_relay_event *);
 void            relay_tls_readcb(int, short, void *);
 void            relay_tls_writecb(int, short, void *);
+int             relay_tls_new_session(SSL *, SSL_SESSION *);
+SSL_SESSION    *relay_tls_get_session(SSL *, unsigned char *, int, int *);
+void            relay_tls_del_session(SSL_CTX *, SSL_SESSION *);
+
+struct tls_ticket_ctx  *relay_get_ticket_key(unsigned char [16]);
+int                     relay_tls_session_ticket(SSL *, unsigned char [16],
+                           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,
@@ -92,6 +102,8 @@ extern void   bufferevent_read_pressure_c
 volatile int relay_sessions;
 volatile int relay_inflight = 0;
 objid_t relay_conid;
+static u_int8_t                         sid[SSL_MAX_SID_CTX_LENGTH];
+static struct tls_ticket_ctx    tls_ticket, tls_ticket_bak;
 
 static struct relayd           *env = NULL;
 int                             proc_id;
@@ -101,12 +113,18 @@ static struct privsep_proc procs[] = {
        { "pfe",        PROC_PFE,       relay_dispatch_pfe },
        { "ca",         PROC_CA,        relay_dispatch_ca },
        { "hce",        PROC_HCE,       relay_dispatch_hce },
+       { "tlsc",       PROC_TLSC,      relay_dispatch_tlsc },
 };
 
 pid_t
 relay(struct privsep *ps, struct privsep_proc *p)
 {
        pid_t    pid;
+
+       /* initialize the session id to a random key for all relay procs */
+       arc4random_buf(sid, sizeof(sid));
+       tlsc_create_ticket(&tls_ticket);
+
        env = ps->ps_env;
        pid = proc_run(ps, p, procs, nitems(procs), relay_init, NULL);
        relay_http(env);
@@ -1931,6 +1949,23 @@ relay_dispatch_parent(int fd, struct pri
        return (0);
 }
 
+int
+relay_dispatch_tlsc(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+       switch (imsg->hdr.type) {
+       case IMSG_TLSC_REKEY:
+               IMSG_SIZE_CHECK(imsg, (&tls_ticket));
+               /* rotate keys */
+               memcpy(&tls_ticket_bak, &tls_ticket, sizeof(tls_ticket));
+               memcpy(&tls_ticket, imsg->data, sizeof(tls_ticket));
+               break;
+       default:
+               return (-1);
+       }
+
+       return (0);
+}
+
 void
 relay_tls_callback_info(const SSL *ssl, int where, int rc)
 {
@@ -2045,7 +2080,6 @@ relay_tls_ctx_create(struct relay *rlay)
        struct protocol *proto = rlay->rl_proto;
        SSL_CTX         *ctx;
        EC_KEY          *ecdhkey;
-       u_int8_t         sid[SSL_MAX_SID_CTX_LENGTH];
 
        ctx = SSL_CTX_new(SSLv23_method());
        if (ctx == NULL)
@@ -2058,10 +2092,18 @@ relay_tls_ctx_create(struct relay *rlay)
                SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
        } else if (proto->cache >= -1) {
                SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
-               if (proto->cache >= 0)
+               if (proto->cache >= 0) {
                        SSL_CTX_sess_set_cache_size(ctx, proto->cache);
+               }
+               SSL_CTX_sess_set_new_cb(ctx, relay_tls_new_session);
+               SSL_CTX_sess_set_get_cb(ctx, relay_tls_get_session);
+               SSL_CTX_sess_set_remove_cb(ctx, relay_tls_del_session);
        }
 
+       /* Callback for TLS session tickets */
+       if (!SSL_CTX_set_tlsext_ticket_key_cb(ctx, relay_tls_session_ticket))
+               log_warnx("could not set the TLS ticket callback");
+
        /* Enable all workarounds and set SSL options */
        SSL_CTX_set_options(ctx, SSL_OP_ALL);
        SSL_CTX_set_options(ctx,
@@ -2142,11 +2184,9 @@ relay_tls_ctx_create(struct relay *rlay)
        }
 
        /*
-        * Set session ID context to a random value.  We don't support
-        * persistent caching of sessions so it is OK to set a temporary
-        * session ID context that is valid during run time.
+        * Set session ID context to a random value. It needs to be the
+        * same accross all relay processes or session caching will fail.
         */
-       arc4random_buf(sid, sizeof(sid));
        if (!SSL_CTX_set_session_id_context(ctx, sid, sizeof(sid)))
                goto err;
 
@@ -2534,6 +2574,156 @@ relay_tls_writecb(int fd, short event, v
                cre->buflen = 0;
        }
        (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+int
+relay_tls_new_session(SSL *ssl, SSL_SESSION *session)
+{
+       const unsigned char *id;
+       unsigned char *buf, *s;
+       unsigned int idlen;
+       long timeout;
+       int slen;
+
+       timeout = SSL_SESSION_get_timeout(session);
+
+       id = SSL_SESSION_get_id(session, &idlen);
+
+       /* Serialise the session. */
+       slen = i2d_SSL_SESSION(session, NULL);
+       if ((buf = s = malloc(slen)) == NULL)
+               fatal("relay_tls_new_session");
+       if (slen != i2d_SSL_SESSION(session, &buf))
+               fatalx("SSL SESSION unexpectly grew beyond buffer");
+
+       tlsc_modify(env, IMSG_TLSC_ADD, id, idlen, s, slen, timeout);
+
+       free(s);
+       return 0;       /* tell SSL to remove the reference on the session */
+}
+
+SSL_SESSION *
+relay_tls_get_session(SSL *ssl, unsigned char *id, int idlen, int *do_copy)
+{
+       struct pollfd            pfd[1];
+       struct iovec             iov[3];
+       SSL_SESSION             *session = NULL;
+       struct imsgbuf          *ibuf;
+       const unsigned char     *data;
+       struct imsg              imsg;
+       int                      proc;
+       int                      n, done = 0, cnt = 0;
+
+       ibuf = proc_ibuf(env->sc_ps, PROC_TLSC, -1);
+       proc = proc_id;
+
+       iov[cnt].iov_base = &proc;
+       iov[cnt++].iov_len = sizeof(proc);
+       iov[cnt].iov_base = (void *)id;
+       iov[cnt++].iov_len = idlen;
+
+       imsg_composev(ibuf, IMSG_TLSC_GET, 0, 0, -1, iov, cnt);
+       if (imsg_flush(ibuf) == -1)
+               log_warn("tlsc_lookup: imsg_flush");
+
+       pfd[0].fd = ibuf->fd;
+       pfd[0].events = POLLIN;
+       while (!done) {
+               switch (poll(pfd, 1, 5 * 1000)) {
+               case -1:
+                       fatal("rsae_send_imsg: poll");
+               case 0:
+                       log_warnx("tlsc_lookup: poll timeout");
+                       break;
+               default:
+                       break;
+               }
+               if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+                       fatalx("imsg_read");
+               if (n == 0)
+                       fatalx("pipe closed");
+
+               while (!done) {
+                       if ((n = imsg_get(ibuf, &imsg)) == -1)
+                               fatalx("imsg_get error");
+                       if (n == 0)
+                               break;
+                       if (imsg.hdr.type != IMSG_TLSC_GET)
+                               fatalx("invalid response");
+
+                       if (IMSG_DATA_SIZE(&imsg) != 0) {
+                               data = imsg.data;
+                               session = d2i_SSL_SESSION(NULL, &data,
+                                   IMSG_DATA_SIZE(&imsg));
+                       }
+                       done = 1;
+                       imsg_free(&imsg);
+               }
+       }
+
+       *do_copy = 0;
+       return (session);
+}
+
+void
+relay_tls_del_session(SSL_CTX *ssl, SSL_SESSION *session)
+{
+       unsigned char *id;
+       unsigned int idlen;
+
+       id = (unsigned char *)SSL_SESSION_get_id(session, &idlen);
+       tlsc_modify(env, IMSG_TLSC_DEL, id, idlen, NULL, 0, 0);
+}
+
+struct tls_ticket_ctx *
+relay_get_ticket_key(unsigned char keyname[16])
+{
+       if (keyname) {
+               if (timingsafe_memcmp(keyname,
+                   tls_ticket_bak.key_name, sizeof(keyname)) == 0)
+                       return &tls_ticket_bak;
+               if (timingsafe_memcmp(keyname,
+                   tls_ticket.key_name, sizeof(keyname)) == 0)
+                       return &tls_ticket;
+               return NULL;
+       }
+       return &tls_ticket;
+}
+
+int
+relay_tls_session_ticket(SSL *ssl, unsigned char keyname[16], unsigned char 
*iv,
+    EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int mode)
+{
+       struct tls_ticket_ctx   *key;
+       struct timespec          ts;
+
+       if (mode == 1) {
+               /* create new session */
+               key = relay_get_ticket_key(NULL);
+               memcpy(keyname, key->key_name, 16);
+               arc4random_buf(iv, EVP_MAX_IV_LENGTH);
+               EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL,
+                   key->aes_key, iv);
+               HMAC_Init_ex(hctx, key->hmac_key, 16, EVP_sha256(), NULL);
+               return 0;
+       } else {
+               if (clock_gettime(CLOCK_MONOTONIC, &ts))
+                       fatal("clock_gettime");
+
+               /* get key by name */
+               key = relay_get_ticket_key(keyname);
+               if  (!key || key->expire < ts.tv_sec)
+                       return 0;
+
+               EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL,
+                   key->aes_key, iv);
+               HMAC_Init_ex(hctx, key->hmac_key, 16, EVP_sha256(), NULL);
+
+               /* time to renew the ticket? */
+               if (key->expire - TLS_TICKET_RENEW_TIME < ts.tv_sec)
+                       return 2;
+               return 1;
+       }
 }
 
 int
Index: relayd.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v
retrieving revision 1.153
diff -u -p -r1.153 relayd.c
--- relayd.c    2 Feb 2016 17:51:11 -0000       1.153
+++ relayd.c    19 Jul 2016 10:00:03 -0000
@@ -70,7 +70,8 @@ static struct privsep_proc procs[] = {
        { "pfe",        PROC_PFE, parent_dispatch_pfe, pfe },
        { "hce",        PROC_HCE, parent_dispatch_hce, hce },
        { "relay",      PROC_RELAY, parent_dispatch_relay, relay },
-       { "ca",         PROC_CA, parent_dispatch_ca, ca }
+       { "ca",         PROC_CA, parent_dispatch_ca, ca },
+       { "tlsc",       PROC_TLSC, NULL, tlsc }
 };
 
 void
@@ -635,6 +636,8 @@ purge_relay(struct relayd *env, struct r
                rlay->rl_tls_capkey = NULL;
        }
 
+       if (rlay->rl_ssl_ctx)
+               SSL_CTX_sess_set_remove_cb(rlay->rl_ssl_ctx, NULL);
        SSL_CTX_free(rlay->rl_ssl_ctx);
 
        while ((rlt = TAILQ_FIRST(&rlay->rl_tables))) {
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.222
diff -u -p -r1.222 relayd.h
--- relayd.h    11 Jan 2016 21:31:42 -0000      1.222
+++ relayd.h    19 Jul 2016 13:07:36 -0000
@@ -961,7 +961,11 @@ enum imsg_type {
        IMSG_CA_PRIVENC,
        IMSG_CA_PRIVDEC,
        IMSG_SESS_PUBLISH,      /* from relay to hce */
-       IMSG_SESS_UNPUBLISH
+       IMSG_SESS_UNPUBLISH,
+       IMSG_TLSC_ADD,
+       IMSG_TLSC_GET,
+       IMSG_TLSC_DEL,
+       IMSG_TLSC_REKEY
 };
 
 enum privsep_procid {
@@ -971,6 +975,7 @@ enum privsep_procid {
        PROC_RELAY,
        PROC_PFE,
        PROC_CA,
+       PROC_TLSC,
        PROC_MAX
 } privsep_process;
 
@@ -1076,6 +1081,15 @@ struct relayd {
        int                      sc_reload;
 };
 
+struct tls_ticket_ctx {
+       time_t          expire;
+       unsigned char   key_name[16];
+       unsigned char   aes_key[16];
+       unsigned char   hmac_key[16];
+};
+#define        TLS_TICKET_LIFE_TIME    (4 * 3600)
+#define        TLS_TICKET_RENEW_TIME   600
+
 #define        FSNMP_TRAPONLY                  0x01
 
 #define RELAYD_OPT_VERBOSE             0x01
@@ -1237,6 +1251,13 @@ int       ssl_ctx_fake_private_key(SSL_CTX *,
 /* ca.c */
 pid_t   ca(struct privsep *, struct privsep_proc *);
 void    ca_engine_init(struct relayd *);
+
+/* tlsc.c */
+pid_t   tlsc(struct privsep *, struct privsep_proc *);
+void    tlsc_engine_init(struct relayd *);
+void    tlsc_modify(struct relayd *, u_int, const void *, size_t,
+           void *, size_t, long);
+void    tlsc_create_ticket(struct tls_ticket_ctx *);
 
 /* relayd.c */
 struct host    *host_find(struct relayd *, objid_t);
Index: tlsc.c
===================================================================
RCS file: tlsc.c
diff -N tlsc.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ tlsc.c      19 Jul 2016 13:30:01 -0000
@@ -0,0 +1,336 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2016 Claudio Jeker <[email protected]>
+ *
+ * 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/tree.h>
+#include <sys/uio.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <poll.h>
+#include <imsg.h>
+
+#include "relayd.h"
+
+struct tlsc_hdr {
+       size_t idlen;
+       size_t slen;
+       long   timeout;
+};
+
+struct tlsc_get {
+       size_t  idlen;
+       int     proc;
+};
+
+struct tlsc {
+       RB_ENTRY(tlsc)          entry;
+       size_t                  idlen;
+       size_t                  slen;
+       time_t                  expire;
+       const unsigned char     *id;
+       const unsigned char     *session;
+};
+
+void   tlsc_init(struct privsep *, struct privsep_proc *p, void *);
+void   tlsc_launch(void);
+void   tlsc_rekey(int, short, void *);
+int    tlsc_dispatch_parent(int, struct privsep_proc *, struct imsg *);
+int    tlsc_dispatch_relay(int, struct privsep_proc *, struct imsg *);
+
+int             tlsc_compare(struct tlsc *, struct tlsc *);
+struct tlsc    *tlsc_get(const void *, size_t);
+void            tlsc_add(const void *, size_t, const void *, size_t, long);
+void            tlsc_del(const void *, size_t);
+void            tlsc_flush(void);
+
+void tlsc_dump(const char *pre, const void *id, size_t idlen);
+
+RB_HEAD(tlsc_tree, tlsc) tls_cache = RB_INITIALIZER(&tls_cache);
+RB_PROTOTYPE(tlsc_tree, tlsc, entry, tlsc_compare)
+RB_GENERATE(tlsc_tree, tlsc, entry, tlsc_compare)
+
+static struct relayd *env = NULL;
+extern int              proc_id;
+
+static struct event    rekeyev;
+
+static struct privsep_proc procs[] = {
+       { "parent",     PROC_PARENT,    tlsc_dispatch_parent },
+       { "relay",      PROC_RELAY,     tlsc_dispatch_relay },
+};
+
+pid_t
+tlsc(struct privsep *ps, struct privsep_proc *p)
+{
+       env = ps->ps_env;
+
+       return (proc_run(ps, p, procs, nitems(procs), tlsc_init, NULL));
+}
+
+void
+tlsc_init(struct privsep *ps, struct privsep_proc *p, void *arg)
+{
+       if (pledge("stdio", NULL) == -1)
+               fatal("pledge");
+
+       if (config_init(ps->ps_env) == -1)
+               fatal("failed to initialize configuration");
+}
+
+void
+tlsc_launch(void)
+{
+       struct timeval   tv;
+
+       /* flush the cache after reconfigure, the same happens in the relays */
+       tlsc_flush();
+
+        /* Schedule statistics timer */
+       evtimer_set(&rekeyev, tlsc_rekey, NULL);
+       bzero(&tv, sizeof(tv));
+       tv.tv_sec = TLS_TICKET_LIFE_TIME;
+       evtimer_add(&rekeyev, &tv);
+}
+
+void
+tlsc_rekey(int fd, short events, void *arg)
+{
+       struct timeval          tv;
+       struct tls_ticket_ctx   ticket;
+       
+       log_debug("tlsc_rekey: rekeying tickets");
+
+       tlsc_create_ticket(&ticket);
+       proc_compose_imsg(env->sc_ps, PROC_RELAY, -1, IMSG_TLSC_REKEY, -1, -1,
+           &ticket, sizeof(ticket));
+
+       evtimer_set(&rekeyev, tlsc_rekey, NULL);
+       bzero(&tv, sizeof(tv));
+       tv.tv_sec = TLS_TICKET_LIFE_TIME;
+       evtimer_add(&rekeyev, &tv);
+}
+
+int
+tlsc_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+       switch (imsg->hdr.type) {
+       case IMSG_CTL_START:
+               tlsc_launch();
+               break;
+       case IMSG_CFG_DONE:
+               /* nothing to do here */
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+int
+tlsc_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+       struct tlsc_hdr  th;
+       int              proc;
+       unsigned char   *id, *s;
+       struct tlsc     *t;
+
+       switch (imsg->hdr.type) {
+       case IMSG_TLSC_ADD:
+       case IMSG_TLSC_DEL:
+               IMSG_SIZE_CHECK(imsg, (&th));
+               memcpy(&th, imsg->data, sizeof(th));
+               if (IMSG_DATA_SIZE(imsg) != (sizeof(th) + th.idlen + th.slen))
+                       fatalx("tlsc_dispatch_relay: bad TLS cache imsg");
+               id = (unsigned char *)imsg->data + sizeof(th);
+               s = id + th.idlen;
+
+               switch (imsg->hdr.type) {
+               case IMSG_TLSC_ADD:
+                       tlsc_add(id, th.idlen, s, th.slen, th.timeout);
+                       break;
+               case IMSG_TLSC_DEL:
+                       tlsc_del(id, th.idlen);
+                       break;
+               }
+               break;
+       case IMSG_TLSC_GET:
+               IMSG_SIZE_CHECK(imsg, (&proc));
+               memcpy(&proc, imsg->data, sizeof(proc));
+
+               t = tlsc_get((unsigned char *)imsg->data + sizeof(proc),
+                   IMSG_DATA_SIZE(imsg) - sizeof(proc));
+               if (t == NULL)
+                       proc_compose_imsg(env->sc_ps, PROC_RELAY, proc,
+                           imsg->hdr.type, -1, -1, NULL, 0);
+               else
+                       proc_compose_imsg(env->sc_ps, PROC_RELAY, proc,
+                           imsg->hdr.type, -1, -1,
+                           (void *)t->session, t->slen);
+               break;
+       default:
+               return (-1);
+       }
+
+       return (0);
+}
+
+void
+tlsc_modify(struct relayd *e, u_int cmd, const void *id, size_t idlen,
+    void *s, size_t slen, long timeout)
+{
+       struct iovec     iov[3];
+       struct imsgbuf  *ibuf;
+       struct tlsc_hdr  th;
+       int              cnt = 0;
+
+
+       ibuf = proc_ibuf(e->sc_ps, PROC_TLSC, -1);
+
+       /* build up imsg */
+       th.timeout = timeout;
+       th.idlen = idlen;
+       if (s)
+               th.slen = slen;
+       else
+               th.slen = 0;
+
+       iov[cnt].iov_base = &th;
+       iov[cnt++].iov_len = sizeof(th);
+       iov[cnt].iov_base = (void *)id;
+       iov[cnt++].iov_len = idlen;
+       if (s) {
+               iov[cnt].iov_base = (void *)s;
+               iov[cnt++].iov_len = slen;
+       }
+
+       /* Fire and forget, imsg are reliable */
+       imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt);
+       if (imsg_flush(ibuf) == -1)
+               log_warn("tlsc_modify: imsg_flush");
+}
+
+int
+tlsc_compare(struct tlsc *a, struct tlsc *b)
+{
+       if (a->idlen < b->idlen)
+               return -1;
+       if (a->idlen > b->idlen)
+               return 1;
+       return memcmp(a->id, b->id, a->idlen);
+}
+
+struct tlsc *
+tlsc_get(const void *id, size_t idlen)
+{ 
+       struct tlsc     tt;
+
+       tlsc_dump("tlsc_get", id, idlen);
+       memset(&tt, 0, sizeof(tt));
+       tt.id = id;
+       tt.idlen = idlen;
+
+       return RB_FIND(tlsc_tree, &tls_cache, &tt);
+}
+
+void
+tlsc_add(const void *id, size_t idlen, const void *s, size_t slen, long 
timeout)
+{
+       struct timespec  ts;
+       struct tlsc     *t;
+       unsigned char   *b;
+       size_t           l;
+
+       tlsc_dump("tlsc_add", id, idlen);
+       l = sizeof(*t) + idlen + slen;
+       if ((t = malloc(l)) == NULL)
+               fatal("tlsc_add");
+       memset(t, 0, sizeof(*t));
+       b = (unsigned char *)(t + 1);
+       memcpy(b, id, idlen);
+       t->id = b;
+       t->idlen = idlen;
+       b += idlen;
+       memcpy(b, s, slen);
+       t->session = b;
+       t->slen = slen;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ts))
+               fatal("clock_gettime");
+       t->expire = ts.tv_sec + timeout;
+
+       if (RB_INSERT(tlsc_tree, &tls_cache, t)) {
+               log_warnx("tlsc_add: session already in cache");
+               free(t);
+       }
+}
+
+void
+tlsc_del(const void *id, size_t idlen)
+{ 
+       struct tlsc     *t;
+
+       tlsc_dump("tlsc_del", id, idlen);
+       if ((t = tlsc_get(id, idlen)) == NULL) {
+               log_warnx("tlsc_del: session not in cache");
+               return;
+       }
+
+       RB_REMOVE(tlsc_tree, &tls_cache, t);
+       free(t);
+}
+
+void
+tlsc_flush(void)
+{
+       struct tlsc     *t;
+
+       while ((t = RB_MIN(tlsc_tree, &tls_cache)) != NULL) {
+               RB_REMOVE(tlsc_tree, &tls_cache, t);
+               free(t);
+       }
+}
+
+void
+tlsc_dump(const char *pre, const void *id, size_t idlen)
+{
+       char buf[80];
+       const unsigned char *s = id;
+       size_t i;
+
+       for (i = 0; i < idlen; i++) {
+               snprintf(buf + 2 * i, sizeof(buf) - 2 * i, "%02x", s[i]); 
+       }
+       log_debug("%s id: %s", pre, buf);
+}
+
+void
+tlsc_create_ticket(struct tls_ticket_ctx *key)
+{
+       struct timespec ts;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ts))
+               fatal("clock_gettime");
+       key->expire = ts.tv_sec + TLS_TICKET_LIFE_TIME;
+
+       arc4random_buf(key->key_name, sizeof(key->key_name));
+       arc4random_buf(key->hmac_key, sizeof(key->hmac_key));
+       arc4random_buf(key->aes_key, sizeof(key->aes_key));
+}

Reply via email to