> On 24.01.2017, at 12:44, Claudio Jeker <[email protected]> wrote:
>
> On Tue, Jan 24, 2017 at 07:52:07AM +0100, Reyk Floeter wrote:
>>
>>> Am 24.01.2017 um 02:54 schrieb Claudio Jeker <[email protected]>:
>>>
>>> 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);