Commit Diff


commit - fe4913ec641bced939aab727cbc4124c761bdde9
commit + 9261e0d8173c20551ba0953a8492dfa0edb4568b
blob - 9b71565d9561f6094f976a16a3ec393e5cb1b647
blob + 50b03744b7265efeb12a59f244507b7e6c216a7b
--- config.c
+++ config.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: config.c,v 1.37 2019/05/31 15:15:37 reyk Exp $	*/
+/*	$OpenBSD: config.c,v 1.38 2019/05/31 15:25:57 reyk Exp $	*/
 
 /*
  * Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -104,6 +104,7 @@ config_init(struct relayd *env)
 		env->sc_proto_default.tcpflags = TCPFLAG_DEFAULT;
 		env->sc_proto_default.tcpbacklog = RELAY_BACKLOG;
 		env->sc_proto_default.tlsflags = TLSFLAG_DEFAULT;
+		TAILQ_INIT(&env->sc_proto_default.tlscerts);
 		(void)strlcpy(env->sc_proto_default.tlsciphers,
 		    TLSCIPHERS_DEFAULT,
 		    sizeof(env->sc_proto_default.tlsciphers));
@@ -146,6 +147,7 @@ config_purge(struct relayd *env, u_int reset)
 	struct netroute		*nr;
 	struct router		*rt;
 	struct ca_pkey		*pkey;
+	struct keyname		*keyname;
 	u_int			 what;
 
 	what = ps->ps_what[privsep_process] & reset;
@@ -191,6 +193,12 @@ config_purge(struct relayd *env, u_int reset)
 			free(proto->style);
 			free(proto->tlscapass);
 			free(proto);
+			while ((keyname =
+			    TAILQ_FIRST(&proto->tlscerts)) != NULL) {
+				TAILQ_REMOVE(&proto->tlscerts, keyname, entry);
+				free(keyname->name);
+				free(keyname);
+			}
 		}
 		env->sc_protocount = 0;
 	}
@@ -696,6 +704,7 @@ config_getproto(struct relayd *env, struct imsg *imsg)
 	}
 
 	TAILQ_INIT(&proto->rules);
+	TAILQ_INIT(&proto->tlscerts);
 	proto->tlscapass = NULL;
 
 	TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
blob - bb1765ebe33787abe6d81b44f220a83e4e84171c
blob + 6cdbba67d5f99b63577c074a8e9f67beeb6a83ad
--- parse.y
+++ parse.y
@@ -1,4 +1,4 @@
-/*	$OpenBSD: parse.y,v 1.237 2019/05/31 15:15:37 reyk Exp $	*/
+/*	$OpenBSD: parse.y,v 1.238 2019/05/31 15:25:57 reyk Exp $	*/
 
 /*
  * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -169,8 +169,8 @@ typedef struct {
 %token	ALL APPEND BACKLOG BACKUP BUFFER CA CACHE SET CHECK CIPHERS CODE
 %token	COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT PASS BLOCK EXTERNAL FILENAME
 %token	FORWARD FROM HASH HEADER HEADERLEN HOST HTTP ICMP INCLUDE INET INET6
-%token	INTERFACE INTERVAL IP LABEL LISTEN VALUE LOADBALANCE LOG LOOKUP METHOD
-%token	MODE NAT NO DESTINATION NODELAY NOTHING ON PARENT PATH PFTAG PORT
+%token	INTERFACE INTERVAL IP KEYPAIR LABEL LISTEN VALUE LOADBALANCE LOG LOOKUP
+%token	METHOD MODE NAT NO DESTINATION NODELAY NOTHING ON PARENT PATH PFTAG PORT
 %token	PREFORK PRIORITY PROTO QUERYSTR REAL REDIRECT RELAY REMOVE REQUEST
 %token	RESPONSE RETRY QUICK RETURN ROUNDROBIN ROUTE SACK SCRIPT SEND SESSION
 %token	SNMP SOCKET SPLICE SSL STICKYADDR STYLE TABLE TAG TAGGED TCP TIMEOUT TLS
@@ -1029,6 +1029,7 @@ proto		: relay_proto PROTO STRING	{
 			p->tcpbacklog = RELAY_BACKLOG;
 			p->httpheaderlen = RELAY_DEFHEADERLENGTH;
 			TAILQ_INIT(&p->rules);
+			TAILQ_INIT(&p->tlscerts);
 			(void)strlcpy(p->tlsciphers, TLSCIPHERS_DEFAULT,
 			    sizeof(p->tlsciphers));
 			(void)strlcpy(p->tlsecdhecurves, TLSECDHECURVES_DEFAULT,
@@ -1257,6 +1258,22 @@ tlsflags	: SESSION TICKETS { proto->tickets = 1; }
 			}
 			free($3);
 		}
+		| KEYPAIR STRING		{
+			struct keyname	*name;
+
+			if (strlen($2) >= PATH_MAX) {
+				yyerror("keypair name too long");
+				free($2);
+				YYERROR;
+			}
+			if ((name = calloc(1, sizeof(*name))) == NULL) {
+				yyerror("calloc");
+				free($2);
+				YYERROR;
+			}
+			name->name = $2;
+			TAILQ_INSERT_TAIL(&proto->tlscerts, name, entry);
+		}
 		| NO flag			{ proto->tlsflags &= ~($2); }
 		| flag				{ proto->tlsflags |= $1; }
 		;
@@ -1723,6 +1740,7 @@ relay		: RELAY STRING	{
 		} '{' optnl relayopts_l '}'	{
 			struct relay		*r;
 			struct relay_config	*rlconf = &rlay->rl_conf;
+			struct keyname		*name;
 
 			if (relay_findbyname(conf, rlconf->name) != NULL ||
 			    relay_findbyaddr(conf, rlconf) != NULL) {
@@ -1754,11 +1772,21 @@ relay		: RELAY STRING	{
 				rlay->rl_conf.proto = conf->sc_proto_default.id;
 			}
 
-			if (relay_load_certfiles(conf, rlay) == -1) {
+			if (TAILQ_EMPTY(&rlay->rl_proto->tlscerts) &&
+			    relay_load_certfiles(conf, rlay, NULL) == -1) {
 				yyerror("cannot load certificates for relay %s",
 				    rlay->rl_conf.name);
 				YYERROR;
 			}
+			TAILQ_FOREACH(name, &rlay->rl_proto->tlscerts, entry) {
+				if (relay_load_certfiles(conf,
+				    rlay, name->name) == -1) {
+					yyerror("cannot load keypair %s"
+					    " for relay %s", name->name,
+					    rlay->rl_conf.name);
+					YYERROR;
+				}
+			}
 
 			conf->sc_relaycount++;
 			SPLAY_INIT(&rlay->rl_sessions);
@@ -2317,6 +2345,7 @@ lookup(char *s)
 		{ "interval",		INTERVAL },
 		{ "ip",			IP },
 		{ "key",		KEY },
+		{ "keypair",		KEYPAIR },
 		{ "label",		LABEL },
 		{ "least-states",	LEASTSTATES },
 		{ "listen",		LISTEN },
@@ -3292,7 +3321,7 @@ relay_inherit(struct relay *ra, struct relay *rb)
 		goto err;
 	}
 
-	if (relay_load_certfiles(conf, rb) == -1) {
+	if (relay_load_certfiles(conf, rb, NULL) == -1) {
 		yyerror("cannot load certificates for relay %s",
 		    rb->rl_conf.name);
 		goto err;
blob - 74ecc21a36034353304206125c0fe415b1a2aa3d
blob + 47edff9e077a68c40bd3d8ab6a1c84346dd1f9b8
--- relayd.c
+++ relayd.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: relayd.c,v 1.178 2019/05/31 15:15:37 reyk Exp $	*/
+/*	$OpenBSD: relayd.c,v 1.179 2019/05/31 15:25:57 reyk Exp $	*/
 
 /*
  * Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -1318,10 +1318,10 @@ relay_load_fd(int fd, off_t *len)
 }
 
 int
-relay_load_certfiles(struct relayd *env, struct relay *rlay)
+relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name)
 {
 	char	 certfile[PATH_MAX];
-	char	 hbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+	char	 hbuf[PATH_MAX];
 	struct protocol *proto = rlay->rl_proto;
 	struct relay_cert *cert;
 	int	 useport = htons(rlay->rl_conf.port);
@@ -1356,8 +1356,12 @@ relay_load_certfiles(struct relayd *env, struct relay 
 	if ((rlay->rl_conf.flags & F_TLS) == 0)
 		return (0);
 
-	if (print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
+	if (name == NULL &&
+	    print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
 		goto fail;
+	else if (name != NULL &&
+	    strlcpy(hbuf, name, sizeof(hbuf)) >= sizeof(hbuf))
+		goto fail;
 
 	if (snprintf(certfile, sizeof(certfile),
 	    "/etc/ssl/%s:%u.crt", hbuf, useport) == -1)
blob - ebfafc3f2dedd9c05d16b71f60eedb7ee3d3338b
blob + 9421661e8bcf5416f67cf0e302e604fd6c10509b
--- relayd.conf.5
+++ relayd.conf.5
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: relayd.conf.5,v 1.189 2019/05/10 09:15:00 reyk Exp $
+.\"	$OpenBSD: relayd.conf.5,v 1.190 2019/05/31 15:25:57 reyk Exp $
 .\"
 .\" Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
 .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -15,7 +15,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: May 10 2019 $
+.Dd $Mdocdate: May 31 2019 $
 .Dt RELAYD.CONF 5
 .Os
 .Sh NAME
@@ -682,27 +682,10 @@ Like the previous directive, but for redirections with
 .Xc
 Specify the address and port for the relay to listen on.
 The relay will accept incoming connections to the specified address.
-.Pp
 If the
 .Ic tls
 keyword is present, the relay will accept connections using the
 encrypted TLS protocol.
-The relay will attempt to look up a private key in
-.Pa /etc/ssl/private/address:port.key
-and a public certificate in
-.Pa /etc/ssl/address:port.crt ,
-where
-.Ar address
-is the specified IP address and
-.Ar port
-is the specified port that the relay listens on.
-If these files are not present, the relay will continue to look in
-.Pa /etc/ssl/private/address.key
-and
-.Pa /etc/ssl/address.crt .
-See
-.Xr ssl 8
-for details about SSL/TLS server certificates.
 .It Ic protocol Ar name
 Use the specified protocol definition for the relay.
 The generic TCP protocol options will be used by default;
@@ -963,6 +946,25 @@ Values higher than 1024 bits can cause incompatibiliti
 TLS clients.
 The default is
 .Ic no edh .
+.It Ic keypair Ar name
+The relay will attempt to look up a private key in
+.Pa /etc/ssl/private/name:port.key
+and a public certificate in
+.Pa /etc/ssl/name:port.crt ,
+where
+.Ar port
+is the specified port that the relay listens on.
+If these files are not present, the relay will continue to look in
+.Pa /etc/ssl/private/name.key
+and
+.Pa /etc/ssl/name.crt .
+This option can be specified multiple times for TLS Server Name Indication.
+If not specified,
+a keypair will be loaded using the specified IP address of the relay as
+.Ar name .
+See
+.Xr ssl 8
+for details about SSL/TLS server certificates.
 .It Ic no cipher-server-preference
 Prefer the client's cipher list over the server's preferences when
 choosing a cipher for the connection.
blob - ec76c38c79509c313478f4b6d8e8b4773c997c78
blob + 4314cec0a6bae2e2e9521cf329cf2ce63a3e107d
--- relayd.h
+++ relayd.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: relayd.h,v 1.257 2019/05/31 15:15:37 reyk Exp $	*/
+/*	$OpenBSD: relayd.h,v 1.258 2019/05/31 15:25:57 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -714,6 +714,12 @@ struct relay_ticket_key {
 
 #define HTTPFLAG_WEBSOCKETS	0x01
 
+struct keyname {
+	TAILQ_ENTRY(keyname)	 entry;
+	char			*name;
+};
+TAILQ_HEAD(keynamelist, keyname);
+
 struct protocol {
 	objid_t			 id;
 	u_int32_t		 flags;
@@ -732,6 +738,7 @@ struct protocol {
 	char			 tlscacert[PATH_MAX];
 	char			 tlscakey[PATH_MAX];
 	char			*tlscapass;
+	struct keynamelist	 tlscerts;
 	char			 name[MAX_NAME_SIZE];
 	int			 tickets;
 	enum prototype		 type;
@@ -1312,7 +1319,8 @@ struct ca_pkey	*pkey_add(struct relayd *, EVP_PKEY *, 
 struct relay_cert *cert_add(struct relayd *, objid_t);
 struct relay_cert *cert_find(struct relayd *, objid_t);
 char		*relay_load_fd(int, off_t *);
-int		 relay_load_certfiles(struct relayd *, struct relay *);
+int		 relay_load_certfiles(struct relayd *, struct relay *,
+		    const char *);
 int		 expand_string(char *, size_t, const char *, const char *);
 void		 translate_string(char *);
 void		 purge_key(char **, off_t);