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.
--
: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);