maybe session cache disable should disable tickets too. some little things below, otherwise ok
Claudio Jeker([email protected]) on 2016.07.19 15:32:13 +0200: > 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 */ indent? > + 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; whitespace > + 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 */ do we mention that fact elsewhere? ;) > + 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]); space at the end > + } > + 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)); > +} > --
