summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2017-03-25 17:25:34 +0000
committerclaudio <claudio@openbsd.org>2017-03-25 17:25:34 +0000
commitfe006a116d1775efa666fe8afddc5dc84efc24f2 (patch)
tree2b6dfe5c61eeeefa0636e444b71eedbb97ad997b
parentOpenSSL documented the public function BIO_printf(3) (and friends) (diff)
downloadwireguard-openbsd-fe006a116d1775efa666fe8afddc5dc84efc24f2.tar.xz
wireguard-openbsd-fe006a116d1775efa666fe8afddc5dc84efc24f2.zip
Implement TLS ticket support in httpd. Off by default. Use
tls ticket lifetime default to turn it on with a 2h ticket lifetime. Rekeying happens after a quarter of that time. OK reky@ and bob@
-rw-r--r--usr.sbin/httpd/config.c6
-rw-r--r--usr.sbin/httpd/httpd.c44
-rw-r--r--usr.sbin/httpd/httpd.conf.511
-rw-r--r--usr.sbin/httpd/httpd.h20
-rw-r--r--usr.sbin/httpd/parse.y29
-rw-r--r--usr.sbin/httpd/server.c65
6 files changed, 163 insertions, 12 deletions
diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c
index f337a72d8e4..b8eee8c3505 100644
--- a/usr.sbin/httpd/config.c
+++ b/usr.sbin/httpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.50 2016/11/06 10:49:38 beck Exp $ */
+/* $OpenBSD: config.c,v 1.51 2017/03/25 17:25:34 claudio Exp $ */
/*
* Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -146,6 +146,7 @@ config_getcfg(struct httpd *env, struct imsg *imsg)
memcpy(&cf, imsg->data, sizeof(cf));
env->sc_opts = cf.cf_opts;
env->sc_flags = cf.cf_flags;
+ memcpy(env->sc_tls_sid, cf.cf_tls_sid, sizeof(env->sc_tls_sid));
what = ps->ps_what[privsep_process];
@@ -239,6 +240,9 @@ config_setserver(struct httpd *env, struct server *srv)
srv->srv_s = -1;
}
+ explicit_bzero(&srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+
return (0);
}
diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c
index 6daccdf52ad..879845a6650 100644
--- a/usr.sbin/httpd/httpd.c
+++ b/usr.sbin/httpd/httpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.c,v 1.64 2017/01/23 04:25:05 deraadt Exp $ */
+/* $OpenBSD: httpd.c,v 1.65 2017/03/25 17:25:34 claudio Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
@@ -57,6 +57,8 @@ int parent_dispatch_server(int, struct privsep_proc *,
struct imsg *);
int parent_dispatch_logger(int, struct privsep_proc *,
struct imsg *);
+void parent_tls_ticket_rekey_start(struct server *);
+void parent_tls_ticket_rekey(int, short, void *);
struct httpd *httpd_env;
@@ -252,6 +254,9 @@ main(int argc, char *argv[])
exit(0);
}
+ /* initialize the TLS session id to a random key for all procs */
+ arc4random_buf(env->sc_tls_sid, sizeof(env->sc_tls_sid));
+
if (parent_configure(env) == -1)
fatalx("configuration failed");
@@ -287,6 +292,10 @@ parent_configure(struct httpd *env)
TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
if (srv->srv_conf.flags & SRVFLAG_LOCATION)
continue;
+ /* start the rekey of the tls ticket keys */
+ if (srv->srv_conf.flags & SRVFLAG_TLS &&
+ srv->srv_conf.tls_ticket_lifetime)
+ parent_tls_ticket_rekey_start(srv);
if (config_setserver(env, srv) == -1)
fatal("send server");
}
@@ -306,6 +315,7 @@ parent_configure(struct httpd *env)
continue;
cf.cf_opts = env->sc_opts;
cf.cf_flags = env->sc_flags;
+ memcpy(cf.cf_tls_sid, env->sc_tls_sid, sizeof(cf.cf_tls_sid));
proc_compose(env->sc_ps, id, IMSG_CFG_DONE, &cf, sizeof(cf));
}
@@ -451,6 +461,38 @@ parent_dispatch_logger(int fd, struct privsep_proc *p, struct imsg *imsg)
return (0);
}
+void
+parent_tls_ticket_rekey_start(struct server *srv)
+{
+ struct timeval tv;
+
+ server_generate_ticket_key(&srv->srv_conf);
+
+ evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv);
+ timerclear(&tv);
+ tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4;
+ evtimer_add(&srv->srv_evt, &tv);
+}
+
+void
+parent_tls_ticket_rekey(int fd, short events, void *arg)
+{
+ struct server *srv = arg;
+ struct timeval tv;
+
+ server_generate_ticket_key(&srv->srv_conf);
+ proc_compose_imsg(httpd_env->sc_ps, PROC_SERVER, -1,
+ IMSG_TLSTICKET_REKEY, -1, -1, &srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+ explicit_bzero(&srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+
+ evtimer_set(&srv->srv_evt, parent_tls_ticket_rekey, srv);
+ timerclear(&tv);
+ tv.tv_sec = srv->srv_conf.tls_ticket_lifetime / 4;
+ evtimer_add(&srv->srv_evt, &tv);
+}
+
/*
* Utility functions
*/
diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5
index 05735332386..548bc7ed027 100644
--- a/usr.sbin/httpd/httpd.conf.5
+++ b/usr.sbin/httpd/httpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: httpd.conf.5,v 1.80 2017/03/16 10:18:11 florian Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.81 2017/03/25 17:25:34 claudio Exp $
.\"
.\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,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: March 16 2017 $
+.Dd $Mdocdate: March 25 2017 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
@@ -564,6 +564,13 @@ will be used (secure protocols; TLSv1.2-only).
Refer to the
.Xr tls_config_parse_protocols 3
function for other valid protocol string values.
+.It Ic ticket Ic lifetime Ar seconds
+Enable TLS session tickets with a
+.Ar seconds
+session lifetime.
+It is possible to set
+.Ar seconds
+to default to use the httpd default timeout of 2 hours.
.El
.El
.Sh TYPES
diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
index 7e527c105c3..6cf2412bf44 100644
--- a/usr.sbin/httpd/httpd.h
+++ b/usr.sbin/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.130 2017/02/07 12:27:42 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.131 2017/03/25 17:25:34 claudio Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -76,6 +76,9 @@
#define SERVER_MIN_PREFETCHED 32
#define SERVER_HSTS_DEFAULT_AGE 31536000
#define SERVER_MAX_RANGES 4
+#define SERVER_DEF_TLS_LIFETIME (2 * 3600)
+#define SERVER_MIN_TLS_LIFETIME (60)
+#define SERVER_MAX_TLS_LIFETIME (24 * 3600)
#define MEDIATYPE_NAMEMAX 128 /* file name extension */
#define MEDIATYPE_TYPEMAX 64 /* length of type/subtype */
@@ -109,6 +112,7 @@ enum httpchunk {
struct ctl_flags {
uint8_t cf_opts;
uint32_t cf_flags;
+ uint8_t cf_tls_sid[TLS_MAX_SESSION_ID_LENGTH];
};
enum key_type {
@@ -219,7 +223,8 @@ enum imsg_type {
IMSG_CFG_DONE,
IMSG_LOG_ACCESS,
IMSG_LOG_ERROR,
- IMSG_LOG_OPEN
+ IMSG_LOG_OPEN,
+ IMSG_TLSTICKET_REKEY
};
enum privsep_procid {
@@ -444,6 +449,12 @@ struct auth {
};
TAILQ_HEAD(serverauth, auth);
+struct server_tls_ticket {
+ uint32_t tt_id;
+ uint32_t tt_keyrev;
+ unsigned char tt_key[TLS_TICKET_KEY_SIZE];
+};
+
struct server_config {
uint32_t id;
uint32_t parent_id;
@@ -477,6 +488,8 @@ struct server_config {
uint8_t *tls_ocsp_staple;
size_t tls_ocsp_staple_len;
char *tls_ocsp_staple_file;
+ struct server_tls_ticket tls_ticket_key;
+ int tls_ticket_lifetime;
uint32_t flags;
int strip;
@@ -540,6 +553,8 @@ struct httpd {
char *sc_chroot;
char *sc_logdir;
+ uint8_t sc_tls_sid[TLS_MAX_SESSION_ID_LENGTH];
+
struct serverlist *sc_servers;
struct mediatypes *sc_mediatypes;
struct media_type sc_default_type;
@@ -573,6 +588,7 @@ void server(struct privsep *, struct privsep_proc *);
int server_tls_cmp(struct server *, struct server *, int);
int server_tls_load_keypair(struct server *);
int server_tls_load_ocsp(struct server *);
+void server_generate_ticket_key(struct server_config *);
int server_privinit(struct server *);
void server_purge(struct server *);
void serverconfig_free(struct server_config *);
diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y
index f53cfff67bf..41964765f0f 100644
--- a/usr.sbin/httpd/parse.y
+++ b/usr.sbin/httpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.89 2017/02/07 12:27:42 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.90 2017/03/25 17:25:34 claudio Exp $ */
/*
* Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -130,10 +130,10 @@ typedef struct {
%}
%token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON
-%token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LISTEN
-%token LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK
-%token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT
-%token TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
+%token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LIFETIME
+%token LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK
+%token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET
+%token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
%token <v.string> STRING
%token <v.number> NUMBER
@@ -766,6 +766,23 @@ tlsopts : CERTIFICATE STRING {
}
free($2);
}
+ | TICKET LIFETIME DEFAULT {
+ srv_conf->tls_ticket_lifetime = SERVER_DEF_TLS_LIFETIME;
+ }
+ | TICKET LIFETIME NUMBER {
+ if ($3 != 0 && $3 < SERVER_MIN_TLS_LIFETIME) {
+ yyerror("ticket lifetime too small");
+ YYERROR;
+ }
+ if ($3 > SERVER_MAX_TLS_LIFETIME) {
+ yyerror("ticket lifetime too large");
+ YYERROR;
+ }
+ srv_conf->tls_ticket_lifetime = $3;
+ }
+ | NO TICKET {
+ srv_conf->tls_ticket_lifetime = 0;
+ }
;
root : ROOT rootflags
@@ -1218,6 +1235,7 @@ lookup(char *s)
{ "index", INDEX },
{ "ip", IP },
{ "key", KEY },
+ { "lifetime", LIFETIME },
{ "listen", LISTEN },
{ "location", LOCATION },
{ "log", LOG },
@@ -1246,6 +1264,7 @@ lookup(char *s)
{ "subdomains", SUBDOMAINS },
{ "syslog", SYSLOG },
{ "tcp", TCP },
+ { "ticket", TICKET },
{ "timeout", TIMEOUT },
{ "tls", TLS },
{ "type", TYPE },
diff --git a/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c
index a00378bf9de..9ff532d7746 100644
--- a/usr.sbin/httpd/server.c
+++ b/usr.sbin/httpd/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.107 2017/02/07 12:27:42 reyk Exp $ */
+/* $OpenBSD: server.c,v 1.108 2017/03/25 17:25:34 claudio Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -58,6 +58,7 @@ int server_socket(struct sockaddr_storage *, in_port_t,
struct server_config *, int, int);
int server_socket_listen(struct sockaddr_storage *, in_port_t,
struct server_config *);
+struct server *server_byid(uint32_t);
int server_tls_init(struct server *);
void server_tls_readcb(int, short, void *);
@@ -135,6 +136,8 @@ server_tls_cmp(struct server *s1, struct server *s2, int match_keypair)
if (sc1->tls_protocols != sc2->tls_protocols)
return (-1);
+ if (sc1->tls_ticket_lifetime != sc2->tls_ticket_lifetime)
+ return (-1);
if (strcmp(sc1->tls_ciphers, sc2->tls_ciphers) != 0)
return (-1);
if (strcmp(sc1->tls_dhe_params, sc2->tls_dhe_params) != 0)
@@ -266,6 +269,31 @@ server_tls_init(struct server *srv)
}
}
+ /* set common session ID among all processes */
+ if (tls_config_set_session_id(srv->srv_tls_config,
+ httpd_env->sc_tls_sid, sizeof(httpd_env->sc_tls_sid)) == -1) {
+ log_warnx("%s: could not set the TLS session ID: %s",
+ __func__, tls_config_error(srv->srv_tls_config));
+ return (-1);
+ }
+
+ /* ticket support */
+ if (srv->srv_conf.tls_ticket_lifetime) {
+ if (tls_config_set_session_lifetime(srv->srv_tls_config,
+ srv->srv_conf.tls_ticket_lifetime) == -1) {
+ log_warnx("%s: could not set the TLS session lifetime: "
+ "%s", __func__,
+ tls_config_error(srv->srv_tls_config));
+ return (-1);
+ }
+ tls_config_add_ticket_key(srv->srv_tls_config,
+ srv->srv_conf.tls_ticket_key.tt_keyrev,
+ srv->srv_conf.tls_ticket_key.tt_key,
+ sizeof(srv->srv_conf.tls_ticket_key.tt_key));
+ explicit_bzero(&srv->srv_conf.tls_ticket_key,
+ sizeof(srv->srv_conf.tls_ticket_key));
+ }
+
if (tls_configure(srv->srv_tls_ctx, srv->srv_tls_config) != 0) {
log_warnx("%s: failed to configure tls - %s", __func__,
tls_error(srv->srv_tls_ctx));
@@ -287,6 +315,16 @@ server_tls_init(struct server *srv)
}
void
+server_generate_ticket_key(struct server_config *srv_conf)
+{
+ struct server_tls_ticket *key = &srv_conf->tls_ticket_key;
+
+ key->tt_id = srv_conf->id;
+ key->tt_keyrev = arc4random();
+ arc4random_buf(key->tt_key, sizeof(key->tt_key));
+}
+
+void
server_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
server_http();
@@ -438,6 +476,18 @@ serverconfig_byid(uint32_t id)
return (NULL);
}
+struct server *
+server_byid(uint32_t id)
+{
+ struct server *srv;
+
+ TAILQ_FOREACH(srv, httpd_env->sc_servers, srv_entry) {
+ if (srv->srv_conf.id == id)
+ return (srv);
+ }
+ return (NULL);
+}
+
int
server_foreach(int (*srv_cb)(struct server *,
struct server_config *, void *), void *arg)
@@ -1226,6 +1276,9 @@ server_close(struct client *clt, const char *msg)
int
server_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
+ struct server *srv;
+ struct server_tls_ticket key;
+
switch (imsg->hdr.type) {
case IMSG_CFG_MEDIA:
config_getmedia(httpd_env, imsg);
@@ -1248,6 +1301,16 @@ server_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
case IMSG_CTL_RESET:
config_getreset(httpd_env, imsg);
break;
+ case IMSG_TLSTICKET_REKEY:
+ IMSG_SIZE_CHECK(imsg, (&key));
+ memcpy(&key, imsg->data, sizeof(key));
+ /* apply to the right server */
+ srv = server_byid(key.tt_id);
+ if (srv) {
+ tls_config_add_ticket_key(srv->srv_tls_config,
+ key.tt_keyrev, key.tt_key, sizeof(key.tt_key));
+ }
+ break;
default:
return (-1);
}