summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2016-09-01 10:49:48 +0000
committerclaudio <claudio@openbsd.org>2016-09-01 10:49:48 +0000
commit9c9085255d0c0d3ffec78411e89820462c2e45f7 (patch)
treed058d4d966f0778302f10e7069be9b253dc07f12
parentIn 32 bits sqrt(val) + 1 can overflow, so some big primes still (diff)
downloadwireguard-openbsd-9c9085255d0c0d3ffec78411e89820462c2e45f7.tar.xz
wireguard-openbsd-9c9085255d0c0d3ffec78411e89820462c2e45f7.zip
Switch from the not really working session cache (because of the multiprocess
nature of relayd) to tls session tickets to do TLS session resumption. TLS session tickets do not need to store SSL session data in the server but instead send an encrypted ticket to the clients that allows to resume the session. This is mostly stateless (apart from the encryption keys). relayd now ensures that all relay processes use the same key to encrypt the tickets. Keys are rotated every 2h and there is a primary and backup key. The tls session timeout is set to 2h to hint to the clients how long the session tickets is supposed to be alive. Input and OK benno@, reyk@
-rw-r--r--usr.sbin/relayd/config.c3
-rw-r--r--usr.sbin/relayd/parse.y21
-rw-r--r--usr.sbin/relayd/relay.c104
-rw-r--r--usr.sbin/relayd/relayd.c31
-rw-r--r--usr.sbin/relayd/relayd.conf.520
-rw-r--r--usr.sbin/relayd/relayd.h20
6 files changed, 150 insertions, 49 deletions
diff --git a/usr.sbin/relayd/config.c b/usr.sbin/relayd/config.c
index a6afdc666f1..a72e32f983a 100644
--- a/usr.sbin/relayd/config.c
+++ b/usr.sbin/relayd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.27 2015/12/07 04:03:27 mmcc Exp $ */
+/* $OpenBSD: config.c,v 1.28 2016/09/01 10:49:48 claudio Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -94,7 +94,6 @@ config_init(struct relayd *env)
bzero(&env->sc_proto_default, sizeof(env->sc_proto_default));
env->sc_proto_default.id = EMPTY_ID;
env->sc_proto_default.flags = F_USED;
- env->sc_proto_default.cache = RELAY_CACHESIZE;
env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT;
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index 7e9afb8d6ad..a69ef4fb1a0 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.207 2016/06/21 21:35:25 benno Exp $ */
+/* $OpenBSD: parse.y,v 1.208 2016/09/01 10:49:48 claudio Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -172,13 +172,13 @@ typedef struct {
%token SOCKET SPLICE SSL STICKYADDR STYLE TABLE TAG TAGGED TCP TIMEOUT TLS TO
%token ROUTER RTLABEL TRANSPARENT TRAP UPDATES URL VIRTUAL WITH TTL RTABLE
%token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDH
-%token EDH CURVE
+%token EDH CURVE TICKETS
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> hostname interface table value optstring
%type <v.number> http_type loglevel quick trap
%type <v.number> dstmode flag forwardmode retry
-%type <v.number> opttls opttlsclient tlscache
+%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
@@ -996,7 +996,6 @@ proto : relay_proto PROTO STRING {
free($3);
p->id = ++last_proto_id;
p->type = $1;
- p->cache = RELAY_CACHESIZE;
p->tcpflags = TCPFLAG_DEFAULT;
p->tlsflags = TLSFLAG_DEFAULT;
p->tcpbacklog = RELAY_BACKLOG;
@@ -1091,7 +1090,8 @@ tlsflags_l : tlsflags comma tlsflags_l
| tlsflags
;
-tlsflags : SESSION CACHE tlscache { proto->cache = $3; }
+tlsflags : SESSION TICKETS { proto->tickets = 0; }
+ | NO SESSION TICKETS { proto->tickets = -1; }
| CIPHERS STRING {
if (strlcpy(proto->tlsciphers, $2,
sizeof(proto->tlsciphers)) >=
@@ -1180,16 +1180,6 @@ flag : STRING {
}
;
-tlscache : NUMBER {
- if ($1 < 0) {
- yyerror("invalid tlscache value: %d", $1);
- YYERROR;
- }
- $$ = $1;
- }
- | DISABLE { $$ = -2; }
- ;
-
filterrule : action dir quick ruleaf rulesrc ruledst {
if ((rule = calloc(1, sizeof(*rule))) == NULL)
fatal("out of memory");
@@ -2257,6 +2247,7 @@ lookup(char *s)
{ "tag", TAG },
{ "tagged", TAGGED },
{ "tcp", TCP },
+ { "tickets", TICKETS },
{ "timeout", TIMEOUT },
{ "tls", TLS },
{ "to", TO },
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index b721b7d192b..33a49782f50 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.206 2015/12/30 16:00:57 benno Exp $ */
+/* $OpenBSD: relay.c,v 1.207 2016/09/01 10:49:48 claudio Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -28,6 +28,7 @@
#include <arpa/inet.h>
#include <limits.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
@@ -85,6 +86,10 @@ 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 [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,
size_t, void *);
@@ -107,6 +112,7 @@ pid_t
relay(struct privsep *ps, struct privsep_proc *p)
{
pid_t pid;
+
env = ps->ps_env;
pid = proc_run(ps, p, procs, nitems(procs), relay_init, NULL);
relay_http(env);
@@ -260,8 +266,8 @@ relay_protodebug(struct relay *rlay)
if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) && proto->tlsflags)
fprintf(stderr, "\ttls flags: %s\n",
printb_flags(proto->tlsflags, TLSFLAG_BITS));
- if (proto->cache != -1)
- fprintf(stderr, "\ttls session cache: %d\n", proto->cache);
+ fprintf(stderr, "\ttls session tickets: %s\n",
+ (proto->tickets > -1) ? "enabled" : "disabled");
fprintf(stderr, "\ttype: ");
switch (proto->type) {
case RELAY_PROTO_TCP:
@@ -1924,6 +1930,15 @@ relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
case IMSG_CTL_RESET:
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));
+ break;
default:
return (-1);
}
@@ -2045,21 +2060,27 @@ 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)
goto err;
- /* Modify session timeout and cache size*/
- SSL_CTX_set_timeout(ctx,
- (long)MINIMUM(rlay->rl_conf.timeout.tv_sec, LONG_MAX));
- if (proto->cache < -1) {
- 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)
- SSL_CTX_sess_set_cache_size(ctx, proto->cache);
+ /*
+ * Disable the session cache by default.
+ * Everything modern uses tickets
+ */
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+
+
+ /* 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");
+ /* set timeout to the ticket rekey time */
+ SSL_CTX_set_timeout(ctx, TLS_TICKET_REKEY_TIME);
}
/* Enable all workarounds and set SSL options */
@@ -2142,12 +2163,11 @@ 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)))
+ if (!SSL_CTX_set_session_id_context(ctx, env->sc_tls_sid,
+ sizeof(env->sc_tls_sid)))
goto err;
/* The text versions of the keys/certs are not needed anymore */
@@ -2536,6 +2556,54 @@ relay_tls_writecb(int fd, short event, void *arg)
(*bufev->errorcb)(bufev, what, bufev->cbarg);
}
+struct tls_ticket *
+relay_get_ticket_key(unsigned char keyname[16])
+{
+ if (keyname) {
+ if (timingsafe_memcmp(keyname,
+ env->sc_tls_ticket_bak.tt_key_name, sizeof(keyname)) == 0)
+ return &env->sc_tls_ticket_bak;
+ if (timingsafe_memcmp(keyname,
+ env->sc_tls_ticket.tt_key_name, sizeof(keyname)) == 0)
+ return &env->sc_tls_ticket;
+ return NULL;
+ }
+ return &env->sc_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 *key;
+
+ if (mode == 1) {
+ /* create new session */
+ key = relay_get_ticket_key(NULL);
+ memcpy(keyname, key->tt_key_name, 16);
+ 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, 16, 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, 16, EVP_sha256(), NULL);
+
+ /* time to renew the ticket? */
+ if (key->tt_backup) {
+ return 2;
+ }
+ return 1;
+ }
+}
+
int
relay_bufferevent_add(struct event *ev, int timeout)
{
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index a41851da462..abb226d74af 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.155 2016/07/29 10:09:26 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.156 2016/09/01 10:49:48 claudio Exp $ */
/*
* Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -63,6 +63,7 @@ int parent_dispatch_relay(int, struct privsep_proc *,
int parent_dispatch_ca(int, struct privsep_proc *,
struct imsg *);
int bindany(struct ctl_bindany *);
+void parent_tls_ticket_rekey(int, short, void *);
struct relayd *relayd_env;
@@ -212,6 +213,8 @@ main(int argc, char *argv[])
TAILQ_INIT(&env->sc_hosts);
TAILQ_INIT(&env->sc_sessions);
env->sc_rtable = getrtable();
+ /* initialize the TLS session id to a random key for all relay procs */
+ arc4random_buf(env->sc_tls_sid, sizeof(env->sc_tls_sid));
if (parse_config(env->sc_conffile, env) == -1)
exit(1);
@@ -278,6 +281,8 @@ main(int argc, char *argv[])
if (env->sc_flags & (F_TLS|F_TLSCLIENT))
ssl_init(env);
+ /* rekey the TLS tickets before pushing the config */
+ parent_tls_ticket_rekey(0, 0, env);
if (parent_configure(env) == -1)
fatalx("configuration failed");
@@ -1671,3 +1676,27 @@ accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
}
return (ret);
}
+
+void
+parent_tls_ticket_rekey(int fd, short events, void *arg)
+{
+ static struct event rekeyev;
+ struct relayd *env = arg;
+ struct timeval tv;
+ struct tls_ticket 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;
+
+ 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;
+ evtimer_add(&rekeyev, &tv);
+}
diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5
index 3f1aa7c3a22..99a02b519cb 100644
--- a/usr.sbin/relayd/relayd.conf.5
+++ b/usr.sbin/relayd/relayd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: relayd.conf.5,v 1.171 2016/08/18 14:12:51 jmc Exp $
+.\" $OpenBSD: relayd.conf.5,v 1.172 2016/09/01 10:49:48 claudio Exp $
.\"
.\" Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 18 2016 $
+.Dd $Mdocdate: September 1 2016 $
.Dt RELAYD.CONF 5
.Os
.Sh NAME
@@ -965,14 +965,14 @@ TLS clients.
.It Ic no edh
Disable EDH support.
This is the default.
-.It Ic session cache Ar value
-Set the maximum size of the TLS session cache.
-If the
-.Ar value
-is zero, the default size defined by the TLS library will be used.
-A positive number will set the maximum size in bytes and the keyword
-.Ic disable
-will disable the TLS session cache.
+.It Xo
+.Op Ic no
+.Ic session tickets
+.Xc
+Disable TLS session tickets; enabled by default.
+.Xr relayd 8
+supports stateless TLS session tickets (RFC 5077) to implement TLS session
+resumption.
.It Xo
.Op Ic no
.Ic sslv3
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index 1413fdfb12b..31b3211fa5d 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.226 2016/09/01 10:40:38 claudio Exp $ */
+/* $OpenBSD: relayd.h,v 1.227 2016/09/01 10:49:48 claudio Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -694,6 +694,15 @@ TAILQ_HEAD(relay_rules, relay_rule);
#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;
+};
+#define TLS_TICKET_REKEY_TIME (2 * 3600)
+
struct protocol {
objid_t id;
u_int32_t flags;
@@ -711,7 +720,7 @@ struct protocol {
char tlscakey[PATH_MAX];
char *tlscapass;
char name[MAX_NAME_SIZE];
- int cache;
+ int tickets;
enum prototype type;
char *style;
@@ -964,7 +973,8 @@ enum imsg_type {
IMSG_CA_PRIVENC,
IMSG_CA_PRIVDEC,
IMSG_SESS_PUBLISH, /* from relay to hce */
- IMSG_SESS_UNPUBLISH
+ IMSG_SESS_UNPUBLISH,
+ IMSG_TLSTICKET_REKEY
};
enum privsep_procid {
@@ -1077,6 +1087,10 @@ struct relayd {
struct privsep *sc_ps;
int sc_reload;
+
+ char sc_tls_sid[SSL_MAX_SID_CTX_LENGTH];
+ struct tls_ticket sc_tls_ticket;
+ struct tls_ticket sc_tls_ticket_bak;
};
#define FSNMP_TRAPONLY 0x01