diff options
author | 2017-03-25 17:25:34 +0000 | |
---|---|---|
committer | 2017-03-25 17:25:34 +0000 | |
commit | fe006a116d1775efa666fe8afddc5dc84efc24f2 (patch) | |
tree | 2b6dfe5c61eeeefa0636e444b71eedbb97ad997b | |
parent | OpenSSL documented the public function BIO_printf(3) (and friends) (diff) | |
download | wireguard-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.c | 6 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.c | 44 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.conf.5 | 11 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.h | 20 | ||||
-rw-r--r-- | usr.sbin/httpd/parse.y | 29 | ||||
-rw-r--r-- | usr.sbin/httpd/server.c | 65 |
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); } |