> On 24.01.2017, at 12:44, Claudio Jeker <cje...@diehard.n-r-g.com> wrote: > > On Tue, Jan 24, 2017 at 07:52:07AM +0100, Reyk Floeter wrote: >> >>> Am 24.01.2017 um 02:54 schrieb Claudio Jeker <cje...@diehard.n-r-g.com>: >>> >>> Since I just added ticket support to libtls here is a diff to enable it >>> in httpd. >>> >> >> Thanks, comments below. >> > > New version that actually uses a per server tls ticket lifetime. Got a bit > more complex because there is now multiple timers running. >
looks good Reyk > - > :wq Claudio > > Index: config.c > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/config.c,v > retrieving revision 1.50 > diff -u -p -r1.50 config.c > --- config.c 6 Nov 2016 10:49:38 -0000 1.50 > +++ config.c 24 Jan 2017 11:21:35 -0000 > @@ -146,6 +146,7 @@ config_getcfg(struct httpd *env, struct > 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]; > > @@ -238,6 +239,9 @@ config_setserver(struct httpd *env, stru > close(srv->srv_s); > srv->srv_s = -1; > } > + > + explicit_bzero(&srv->srv_conf.tls_ticket_key, > + sizeof(srv->srv_conf.tls_ticket_key)); > > return (0); > } > Index: httpd.c > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/httpd.c,v > retrieving revision 1.63 > diff -u -p -r1.63 httpd.c > --- httpd.c 9 Jan 2017 14:49:22 -0000 1.63 > +++ httpd.c 24 Jan 2017 11:20:17 -0000 > @@ -57,6 +57,8 @@ int parent_dispatch_server(int, struct > 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; > > @@ -253,6 +255,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"); > > @@ -288,6 +293,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"); > } > @@ -307,6 +316,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)); > } > @@ -450,6 +460,38 @@ parent_dispatch_logger(int fd, struct pr > } > > 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); > } > > /* > Index: httpd.conf.5 > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v > retrieving revision 1.76 > diff -u -p -r1.76 httpd.conf.5 > --- httpd.conf.5 14 Nov 2016 10:28:31 -0000 1.76 > +++ httpd.conf.5 24 Jan 2017 11:36:16 -0000 > @@ -556,6 +556,13 @@ will be used (secure protocols; TLSv1.2- > Refer to the > .Xr tls_config_parse_protocols 3 > function for other valid protocol string values. > +.It Ic tickets 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 > Index: httpd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v > retrieving revision 1.125 > diff -u -p -r1.125 httpd.h > --- httpd.h 9 Jan 2017 14:49:22 -0000 1.125 > +++ httpd.h 24 Jan 2017 11:22:59 -0000 > @@ -73,6 +73,9 @@ > #define SERVER_MAX_PREFETCH 256 > #define SERVER_MIN_PREFETCHED 32 > #define SERVER_HSTS_DEFAULT_AGE 31536000 > +#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 */ > @@ -105,6 +108,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 { > @@ -215,7 +219,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 { > @@ -420,6 +425,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; > @@ -452,6 +463,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; > @@ -515,6 +528,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; > @@ -548,6 +563,7 @@ void server(struct privsep *, struct pr > 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 *); > Index: parse.y > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/parse.y,v > retrieving revision 1.87 > diff -u -p -r1.87 parse.y > --- parse.y 5 Jan 2017 13:53:09 -0000 1.87 > +++ parse.y 24 Jan 2017 03:53:43 -0000 > @@ -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 > @@ -760,6 +760,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 > @@ -1212,6 +1229,7 @@ lookup(char *s) > { "index", INDEX }, > { "ip", IP }, > { "key", KEY }, > + { "lifetime", LIFETIME }, > { "listen", LISTEN }, > { "location", LOCATION }, > { "log", LOG }, > @@ -1240,6 +1258,7 @@ lookup(char *s) > { "subdomains", SUBDOMAINS }, > { "syslog", SYSLOG }, > { "tcp", TCP }, > + { "ticket", TICKET }, > { "timeout", TIMEOUT }, > { "tls", TLS }, > { "type", TYPE }, > Index: server.c > =================================================================== > RCS file: /cvs/src/usr.sbin/httpd/server.c,v > retrieving revision 1.101 > diff -u -p -r1.101 server.c > --- server.c 9 Jan 2017 14:49:22 -0000 1.101 > +++ server.c 24 Jan 2017 11:29:29 -0000 > @@ -58,6 +58,7 @@ int server_socket(struct sockaddr_stor > 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 > > 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) > @@ -281,6 +284,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)); > @@ -302,6 +330,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(); > @@ -453,6 +491,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) > @@ -1239,6 +1289,9 @@ server_close(struct client *clt, const c > 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); > @@ -1260,6 +1313,16 @@ server_dispatch_parent(int fd, struct pr > break; > 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);