On Thu, May 09, 2019 at 02:51:23PM +0200, Reyk Floeter wrote:
> Hi,
>
> this diff adds SNI support to relayd.
>
Below is the same diff again -current minus one debug line.
jsing@ has noted that calling tls_config_set_keypair_ocsp_mem() with
NULL ocsp options could be replaced with tls_config_set_keypair_mem(),
but I'd like to keep it for now because I have an OCSP diff on top of
it that I'll send once SNI is in.
OK?
Reyk
Index: usr.sbin/relayd/ca.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ca.c,v
retrieving revision 1.34
diff -u -p -u -p -r1.34 ca.c
--- usr.sbin/relayd/ca.c 19 Sep 2018 11:28:02 -0000 1.34
+++ usr.sbin/relayd/ca.c 13 May 2019 08:53:17 -0000
@@ -108,56 +108,60 @@ hash_x509(X509 *cert, char *hash, size_t
void
ca_launch(void)
{
- char hash[TLS_CERT_HASH_SIZE];
- char *buf;
- BIO *in = NULL;
- EVP_PKEY *pkey = NULL;
- struct relay *rlay;
- X509 *cert = NULL;
- off_t len;
+ char hash[TLS_CERT_HASH_SIZE];
+ char *buf;
+ BIO *in = NULL;
+ EVP_PKEY *pkey = NULL;
+ struct relay *rlay;
+ struct relay_cert *cert;
+ X509 *x509 = NULL;
+ off_t len;
- TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
- if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
+ TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
+ if (cert->cert_fd == -1 || cert->cert_key_fd == -1)
continue;
- if (rlay->rl_tls_cert_fd != -1) {
- if ((buf = relay_load_fd(rlay->rl_tls_cert_fd,
- &len)) == NULL)
- fatal("ca_launch: cert relay_load_fd");
+ if ((buf = relay_load_fd(cert->cert_fd, &len)) == NULL)
+ fatal("ca_launch: cert relay_load_fd");
- if ((in = BIO_new_mem_buf(buf, len)) == NULL)
- fatalx("ca_launch: cert BIO_new_mem_buf");
+ if ((in = BIO_new_mem_buf(buf, len)) == NULL)
+ fatalx("ca_launch: cert BIO_new_mem_buf");
- if ((cert = PEM_read_bio_X509(in, NULL,
- NULL, NULL)) == NULL)
- fatalx("ca_launch: cert PEM_read_bio_X509");
+ if ((x509 = PEM_read_bio_X509(in, NULL,
+ NULL, NULL)) == NULL)
+ fatalx("ca_launch: cert PEM_read_bio_X509");
- hash_x509(cert, hash, sizeof(hash));
+ hash_x509(x509, hash, sizeof(hash));
- BIO_free(in);
- X509_free(cert);
- purge_key(&buf, len);
- }
- if (rlay->rl_conf.tls_key_len) {
- if ((in = BIO_new_mem_buf(rlay->rl_tls_key,
- rlay->rl_conf.tls_key_len)) == NULL)
- fatalx("%s: key", __func__);
-
- if ((pkey = PEM_read_bio_PrivateKey(in,
- NULL, NULL, NULL)) == NULL)
- fatalx("%s: PEM", __func__);
- BIO_free(in);
+ BIO_free(in);
+ X509_free(x509);
+ purge_key(&buf, len);
- rlay->rl_tls_pkey = pkey;
+ if ((buf = relay_load_fd(cert->cert_key_fd, &len)) == NULL)
+ fatal("ca_launch: key relay_load_fd");
- if (pkey_add(env, pkey, hash) == NULL)
- fatalx("tls pkey");
+ if ((in = BIO_new_mem_buf(buf, len)) == NULL)
+ fatalx("%s: key", __func__);
- purge_key(&rlay->rl_tls_key,
- rlay->rl_conf.tls_key_len);
- }
+ if ((pkey = PEM_read_bio_PrivateKey(in,
+ NULL, NULL, NULL)) == NULL)
+ fatalx("%s: PEM", __func__);
- if (rlay->rl_tls_cacert_fd != -1) {
+ cert->cert_pkey = pkey;
+
+ if (pkey_add(env, pkey, hash) == NULL)
+ fatalx("tls pkey");
+
+ BIO_free(in);
+ purge_key(&buf, len);
+ }
+
+ TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
+ if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
+ continue;
+
+ if (rlay->rl_tls_cacert_fd != -1 &&
+ rlay->rl_conf.tls_cakey_len) {
if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd,
&len)) == NULL)
fatal("ca_launch: cacert relay_load_fd");
@@ -165,17 +169,16 @@ ca_launch(void)
if ((in = BIO_new_mem_buf(buf, len)) == NULL)
fatalx("ca_launch: cacert BIO_new_mem_buf");
- if ((cert = PEM_read_bio_X509(in, NULL,
+ if ((x509 = PEM_read_bio_X509(in, NULL,
NULL, NULL)) == NULL)
fatalx("ca_launch: cacert PEM_read_bio_X509");
- hash_x509(cert, hash, sizeof(hash));
+ hash_x509(x509, hash, sizeof(hash));
BIO_free(in);
- X509_free(cert);
+ X509_free(x509);
purge_key(&buf, len);
- }
- if (rlay->rl_conf.tls_cakey_len) {
+
if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
rlay->rl_conf.tls_cakey_len)) == NULL)
fatalx("%s: key", __func__);
Index: usr.sbin/relayd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
retrieving revision 1.36
diff -u -p -u -p -r1.36 config.c
--- usr.sbin/relayd/config.c 29 Nov 2017 15:24:50 -0000 1.36
+++ usr.sbin/relayd/config.c 13 May 2019 08:53:17 -0000
@@ -81,6 +81,12 @@ config_init(struct relayd *env)
calloc(1, sizeof(*env->sc_relays))) == NULL)
return (-1);
TAILQ_INIT(env->sc_relays);
+
+ if ((env->sc_certs =
+ calloc(1, sizeof(*env->sc_certs))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_certs);
+
if ((env->sc_pkeys =
calloc(1, sizeof(*env->sc_pkeys))) == NULL)
return (-1);
@@ -98,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));
@@ -140,6 +147,7 @@ config_purge(struct relayd *env, u_int r
struct netroute *nr;
struct router *rt;
struct ca_pkey *pkey;
+ struct keyname *keyname;
u_int what;
what = ps->ps_what[privsep_process] & reset;
@@ -185,6 +193,12 @@ config_purge(struct relayd *env, u_int r
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;
}
@@ -690,6 +704,7 @@ config_getproto(struct relayd *env, stru
}
TAILQ_INIT(&proto->rules);
+ TAILQ_INIT(&proto->tlscerts);
proto->tlscapass = NULL;
TAILQ_INSERT_TAIL(env->sc_protos, proto, entry);
@@ -773,12 +788,13 @@ config_getrule(struct relayd *env, struc
}
static int
-config_setrelayfd(struct privsep *ps, int id, int n, int rlay_id, int type,
- int ofd)
+config_setrelayfd(struct privsep *ps, int id, int n,
+ objid_t obj_id, objid_t rlay_id, enum fd_type type, int ofd)
{
struct ctl_relayfd rfd;
int fd;
+ rfd.id = obj_id;
rfd.relayid = rlay_id;
rfd.type = type;
@@ -798,6 +814,7 @@ config_setrelay(struct relayd *env, stru
struct ctl_relaytable crt;
struct relay_table *rlt;
struct relay_config rl;
+ struct relay_cert *cert;
int id;
int fd, n, m;
struct iovec iov[6];
@@ -824,12 +841,6 @@ config_setrelay(struct relayd *env, stru
iov[c++].iov_len = sizeof(rl);
if ((what & CONFIG_CA_ENGINE) == 0 &&
- rl.tls_key_len) {
- iov[c].iov_base = rlay->rl_tls_key;
- iov[c++].iov_len = rl.tls_key_len;
- } else
- rl.tls_key_len = 0;
- if ((what & CONFIG_CA_ENGINE) == 0 &&
rl.tls_cakey_len) {
iov[c].iov_base = rlay->rl_tls_cakey;
iov[c++].iov_len = rl.tls_cakey_len;
@@ -868,22 +879,42 @@ config_setrelay(struct relayd *env, stru
}
}
-
- if (what & CONFIG_CERTS) {
+ /* cert keypairs */
+ TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
+ if (cert->cert_relayid != rlay->rl_conf.id)
+ continue;
n = -1;
proc_range(ps, id, &n, &m);
- for (n = 0; n < m; n++) {
- if (rlay->rl_tls_cert_fd != -1 &&
+ for (n = 0; (what & CONFIG_CERTS) && n < m; n++) {
+ if (cert->cert_fd != -1 &&
config_setrelayfd(ps, id, n,
- rlay->rl_conf.id, RELAY_FD_CERT,
- rlay->rl_tls_cert_fd) == -1) {
+ cert->cert_id, cert->cert_relayid,
+ RELAY_FD_CERT, cert->cert_fd) == -1) {
log_warn("%s: fd passing failed for "
"`%s'", __func__,
rlay->rl_conf.name);
return (-1);
}
- if (rlay->rl_tls_ca_fd != -1 &&
+ if (id == PROC_CA &&
+ cert->cert_key_fd != -1 &&
config_setrelayfd(ps, id, n,
+ cert->cert_id, cert->cert_relayid,
+ RELAY_FD_KEY, cert->cert_key_fd) == -1) {
+ log_warn("%s: fd passing failed for "
+ "`%s'", __func__,
+ rlay->rl_conf.name);
+ return (-1);
+ }
+ }
+ }
+
+ /* CA certs */
+ if (what & CONFIG_CERTS) {
+ n = -1;
+ proc_range(ps, id, &n, &m);
+ for (n = 0; n < m; n++) {
+ if (rlay->rl_tls_ca_fd != -1 &&
+ config_setrelayfd(ps, id, n, 0,
rlay->rl_conf.id, RELAY_FD_CACERT,
rlay->rl_tls_ca_fd) == -1) {
log_warn("%s: fd passing failed for "
@@ -892,7 +923,7 @@ config_setrelay(struct relayd *env, stru
return (-1);
}
if (rlay->rl_tls_cacert_fd != -1 &&
- config_setrelayfd(ps, id, n,
+ config_setrelayfd(ps, id, n, 0,
rlay->rl_conf.id, RELAY_FD_CAFILE,
rlay->rl_tls_cacert_fd) == -1) {
log_warn("%s: fd passing failed for "
@@ -933,10 +964,6 @@ config_setrelay(struct relayd *env, stru
close(rlay->rl_s);
rlay->rl_s = -1;
}
- if (rlay->rl_tls_cert_fd != -1) {
- close(rlay->rl_tls_cert_fd);
- rlay->rl_tls_cert_fd = -1;
- }
if (rlay->rl_tls_cacert_fd != -1) {
close(rlay->rl_tls_cacert_fd);
rlay->rl_tls_cacert_fd = -1;
@@ -945,6 +972,19 @@ config_setrelay(struct relayd *env, stru
close(rlay->rl_tls_ca_fd);
rlay->rl_tls_ca_fd = -1;
}
+ TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
+ if (cert->cert_relayid != rlay->rl_conf.id)
+ continue;
+
+ if (cert->cert_fd != -1) {
+ close(cert->cert_fd);
+ cert->cert_fd = -1;
+ }
+ if (cert->cert_key_fd != -1) {
+ close(cert->cert_key_fd);
+ cert->cert_key_fd = -1;
+ }
+ }
return (0);
}
@@ -965,7 +1005,6 @@ config_getrelay(struct relayd *env, stru
s = sizeof(rlay->rl_conf);
rlay->rl_s = imsg->fd;
- rlay->rl_tls_cert_fd = -1;
rlay->rl_tls_ca_fd = -1;
rlay->rl_tls_cacert_fd = -1;
@@ -980,17 +1019,11 @@ config_getrelay(struct relayd *env, stru
}
if ((off_t)(IMSG_DATA_SIZE(imsg) - s) <
- (rlay->rl_conf.tls_key_len + rlay->rl_conf.tls_cakey_len)) {
+ (rlay->rl_conf.tls_cakey_len)) {
log_debug("%s: invalid message length", __func__);
goto fail;
}
- if (rlay->rl_conf.tls_key_len) {
- if ((rlay->rl_tls_key = get_data(p + s,
- rlay->rl_conf.tls_key_len)) == NULL)
- goto fail;
- s += rlay->rl_conf.tls_key_len;
- }
if (rlay->rl_conf.tls_cakey_len) {
if ((rlay->rl_tls_cakey = get_data(p + s,
rlay->rl_conf.tls_cakey_len)) == NULL)
@@ -1010,7 +1043,6 @@ config_getrelay(struct relayd *env, stru
return (0);
fail:
- free(rlay->rl_tls_key);
free(rlay->rl_tls_cakey);
close(rlay->rl_s);
free(rlay);
@@ -1062,22 +1094,37 @@ config_getrelaytable(struct relayd *env,
int
config_getrelayfd(struct relayd *env, struct imsg *imsg)
{
- struct relay_table *rlt = NULL;
struct ctl_relayfd crfd;
- struct relay *rlay;
+ struct relay *rlay = NULL;
+ struct relay_cert *cert;
u_int8_t *p = imsg->data;
IMSG_SIZE_CHECK(imsg, &crfd);
memcpy(&crfd, p, sizeof(crfd));
- if ((rlay = relay_find(env, crfd.relayid)) == NULL) {
- log_debug("%s: unknown relay", __func__);
- goto fail;
+ switch (crfd.type) {
+ case RELAY_FD_CERT:
+ case RELAY_FD_KEY:
+ if ((cert = cert_find(env, crfd.id)) == NULL) {
+ if ((cert = cert_add(env, crfd.id)) == NULL)
+ return (-1);
+ cert->cert_relayid = crfd.relayid;
+ }
+ /* FALLTHROUGH */
+ default:
+ if ((rlay = relay_find(env, crfd.relayid)) == NULL) {
+ log_debug("%s: unknown relay", __func__);
+ return (-1);
+ }
+ break;
}
switch (crfd.type) {
case RELAY_FD_CERT:
- rlay->rl_tls_cert_fd = imsg->fd;
+ cert->cert_fd = imsg->fd;
+ break;
+ case RELAY_FD_KEY:
+ cert->cert_key_fd = imsg->fd;
break;
case RELAY_FD_CACERT:
rlay->rl_tls_ca_fd = imsg->fd;
@@ -1092,8 +1139,4 @@ config_getrelayfd(struct relayd *env, st
imsg->fd, crfd.type, rlay->rl_conf.name);
return (0);
-
- fail:
- free(rlt);
- return (-1);
}
Index: usr.sbin/relayd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/parse.y,v
retrieving revision 1.234
diff -u -p -u -p -r1.234 parse.y
--- usr.sbin/relayd/parse.y 10 May 2019 09:15:00 -0000 1.234
+++ usr.sbin/relayd/parse.y 13 May 2019 08:53:18 -0000
@@ -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
@@ -992,7 +992,7 @@ optdigest : digest {
;
proto : relay_proto PROTO STRING {
- struct protocol *p;
+ struct protocol *p;
if (!loadcfg) {
free($3);
@@ -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,17 @@ tlsflags : SESSION TICKETS { proto->tick
}
free($3);
}
+ | KEYPAIR STRING {
+ struct keyname *name;
+
+ 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; }
;
@@ -1688,18 +1700,9 @@ relay : RELAY STRING {
YYACCEPT;
}
- TAILQ_FOREACH(r, conf->sc_relays, rl_entry)
- if (!strcmp(r->rl_conf.name, $2))
- break;
- if (r != NULL) {
- yyerror("relay %s defined twice", $2);
- free($2);
- YYERROR;
- }
- TAILQ_INIT(&relays);
-
if ((r = calloc(1, sizeof (*r))) == NULL)
fatal("out of memory");
+ TAILQ_INIT(&relays);
if (strlcpy(r->rl_conf.name, $2,
sizeof(r->rl_conf.name)) >=
@@ -1719,7 +1722,6 @@ relay : RELAY STRING {
r->rl_proto = NULL;
r->rl_conf.proto = EMPTY_ID;
r->rl_conf.dstretry = 0;
- r->rl_tls_cert_fd = -1;
r->rl_tls_ca_fd = -1;
r->rl_tls_cacert_fd = -1;
TAILQ_INIT(&r->rl_tables);
@@ -1731,7 +1733,16 @@ relay : RELAY STRING {
dstmode = RELAY_DSTMODE_DEFAULT;
rlay = r;
} '{' optnl relayopts_l '}' {
- struct relay *r;
+ 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) {
+ yyerror("relay %s or listener defined twice",
+ rlconf->name);
+ YYERROR;
+ }
if (rlay->rl_conf.ss.ss_family == AF_UNSPEC) {
yyerror("relay %s has no listener",
@@ -1755,11 +1766,23 @@ relay : RELAY STRING {
rlay->rl_proto = &conf->sc_proto_default;
rlay->rl_conf.proto = conf->sc_proto_default.id;
}
- if (relay_load_certfiles(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);
TAILQ_INSERT_TAIL(conf->sc_relays, rlay, rl_entry);
@@ -2317,6 +2340,7 @@ lookup(char *s)
{ "interval", INTERVAL },
{ "ip", IP },
{ "key", KEY },
+ { "keypair", KEYPAIR },
{ "label", LABEL },
{ "least-states", LEASTSTATES },
{ "listen", LISTEN },
@@ -3268,11 +3292,8 @@ relay_inherit(struct relay *ra, struct r
rb->rl_conf.flags =
(ra->rl_conf.flags & ~F_TLS) | (rc.flags & F_TLS);
if (!(rb->rl_conf.flags & F_TLS)) {
- rb->rl_tls_cert_fd = -1;
rb->rl_tls_cacert_fd = -1;
rb->rl_tls_ca_fd = -1;
- rb->rl_tls_key = NULL;
- rb->rl_conf.tls_key_len = 0;
}
TAILQ_INIT(&rb->rl_tables);
@@ -3290,10 +3311,12 @@ relay_inherit(struct relay *ra, struct r
if (relay_findbyname(conf, rb->rl_conf.name) != NULL ||
relay_findbyaddr(conf, &rb->rl_conf) != NULL) {
- yyerror("relay %s defined twice", rb->rl_conf.name);
+ yyerror("relay %s or listener defined twice",
+ rb->rl_conf.name);
goto err;
}
- if (relay_load_certfiles(rb) == -1) {
+
+ if (relay_load_certfiles(conf, rb, NULL) == -1) {
yyerror("cannot load certificates for relay %s",
rb->rl_conf.name);
goto err;
Index: usr.sbin/relayd/relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.244
diff -u -p -u -p -r1.244 relay.c
--- usr.sbin/relayd/relay.c 10 May 2019 09:15:00 -0000 1.244
+++ usr.sbin/relayd/relay.c 13 May 2019 08:53:18 -0000
@@ -2098,8 +2098,9 @@ relay_tls_ctx_create(struct relay *rlay)
{
struct tls_config *tls_cfg, *tls_client_cfg;
struct tls *tls = NULL;
+ struct relay_cert *cert;
const char *fake_key;
- int fake_keylen;
+ int fake_keylen, keyfound = 0;
char *buf = NULL, *cabuf = NULL;
off_t len = 0, calen = 0;
@@ -2131,6 +2132,7 @@ relay_tls_ctx_create(struct relay *rlay)
log_warn("failed to read root certificates");
goto err;
}
+ rlay->rl_tls_ca_fd = -1;
if (tls_config_set_ca_mem(tls_client_cfg, buf, len) !=
0) {
@@ -2159,24 +2161,47 @@ relay_tls_ctx_create(struct relay *rlay)
*/
tls_config_skip_private_key_check(tls_cfg);
- if ((buf = relay_load_fd(rlay->rl_tls_cert_fd, &len)) == NULL) {
- log_warn("failed to load tls certificate");
- goto err;
- }
+ TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
+ if (cert->cert_relayid != rlay->rl_conf.id ||
+ cert->cert_fd == -1)
+ continue;
+ keyfound++;
+
+ if ((buf = relay_load_fd(cert->cert_fd,
+ &len)) == NULL) {
+ log_warn("failed to load tls certificate");
+ goto err;
+ }
+ cert->cert_fd = -1;
- if ((fake_keylen = ssl_ctx_fake_private_key(buf, len,
- &fake_key)) == -1) {
- /* error already printed */
- goto err;
- }
+ if ((fake_keylen = ssl_ctx_fake_private_key(buf, len,
+ &fake_key)) == -1) {
+ /* error already printed */
+ goto err;
+ }
- if (tls_config_set_keypair_ocsp_mem(tls_cfg, buf, len,
- fake_key, fake_keylen, NULL, 0) != 0) {
- log_warnx("failed to set tls certificate: %s",
- tls_config_error(tls_cfg));
- goto err;
- }
+ if (keyfound == 1 &&
+ tls_config_set_keypair_ocsp_mem(tls_cfg, buf, len,
+ fake_key, fake_keylen, NULL, 0) != 0) {
+ log_warnx("failed to set tls certificate: %s",
+ tls_config_error(tls_cfg));
+ goto err;
+ }
+
+ /* loading certificate public key */
+ if (keyfound == 1 &&
+ !ssl_load_pkey(buf, len, NULL, &rlay->rl_tls_pkey))
+ goto err;
+ if (tls_config_add_keypair_ocsp_mem(tls_cfg, buf, len,
+ fake_key, fake_keylen, NULL, 0) != 0) {
+ log_warnx("failed to add tls certificate: %s",
+ tls_config_error(tls_cfg));
+ goto err;
+ }
+
+ purge_key(&buf, len);
+ }
if (rlay->rl_tls_cacert_fd != -1) {
if ((cabuf = relay_load_fd(rlay->rl_tls_cacert_fd,
@@ -2188,11 +2213,8 @@ relay_tls_ctx_create(struct relay *rlay)
if (!ssl_load_pkey(cabuf, calen,
&rlay->rl_tls_cacertx509, &rlay->rl_tls_capkey))
goto err;
- /* loading certificate public key */
- log_debug("%s: loading certificate", __func__);
- if (!ssl_load_pkey(buf, len, NULL, &rlay->rl_tls_pkey))
- goto err;
}
+ rlay->rl_tls_cacert_fd = -1;
tls = tls_server();
if (tls == NULL) {
@@ -2209,14 +2231,8 @@ relay_tls_ctx_create(struct relay *rlay)
rlay->rl_tls_ctx = tls;
purge_key(&cabuf, calen);
- purge_key(&buf, len);
}
- /* The fd for the keys/certs are not needed anymore */
- close(rlay->rl_tls_cert_fd);
- close(rlay->rl_tls_cacert_fd);
- close(rlay->rl_tls_ca_fd);
-
if (rlay->rl_tls_client_cfg == NULL)
tls_config_free(tls_client_cfg);
if (rlay->rl_tls_cfg == NULL)
@@ -2663,75 +2679,6 @@ relay_load_fd(int fd, off_t *len)
close(fd);
errno = err;
return (NULL);
-}
-
-int
-relay_load_certfiles(struct relay *rlay)
-{
- char certfile[PATH_MAX];
- char hbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
- struct protocol *proto = rlay->rl_proto;
- int useport = htons(rlay->rl_conf.port);
-
- if (rlay->rl_conf.flags & F_TLSCLIENT) {
- if (strlen(proto->tlsca)) {
- if ((rlay->rl_tls_ca_fd =
- open(proto->tlsca, O_RDONLY)) == -1)
- return (-1);
- log_debug("%s: using ca %s", __func__, proto->tlsca);
- }
- if (strlen(proto->tlscacert)) {
- if ((rlay->rl_tls_cacert_fd =
- open(proto->tlscacert, O_RDONLY)) == -1)
- return (-1);
- log_debug("%s: using ca certificate %s", __func__,
- proto->tlscacert);
- }
- if (strlen(proto->tlscakey) && proto->tlscapass != NULL) {
- if ((rlay->rl_tls_cakey =
- ssl_load_key(env, proto->tlscakey,
- &rlay->rl_conf.tls_cakey_len,
- proto->tlscapass)) == NULL)
- return (-1);
- log_debug("%s: using ca key %s", __func__,
- proto->tlscakey);
- }
- }
-
- if ((rlay->rl_conf.flags & F_TLS) == 0)
- return (0);
-
- if (print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
- return (-1);
-
- if (snprintf(certfile, sizeof(certfile),
- "/etc/ssl/%s:%u.crt", hbuf, useport) == -1)
- return (-1);
- if ((rlay->rl_tls_cert_fd = open(certfile, O_RDONLY)) == -1) {
- if (snprintf(certfile, sizeof(certfile),
- "/etc/ssl/%s.crt", hbuf) == -1)
- return (-1);
- if ((rlay->rl_tls_cert_fd = open(certfile, O_RDONLY)) == -1)
- return (-1);
- useport = 0;
- }
- log_debug("%s: using certificate %s", __func__, certfile);
-
- if (useport) {
- if (snprintf(certfile, sizeof(certfile),
- "/etc/ssl/private/%s:%u.key", hbuf, useport) == -1)
- return -1;
- } else {
- if (snprintf(certfile, sizeof(certfile),
- "/etc/ssl/private/%s.key", hbuf) == -1)
- return -1;
- }
- if ((rlay->rl_tls_key = ssl_load_key(env, certfile,
- &rlay->rl_conf.tls_key_len, NULL)) == NULL)
- return (-1);
- log_debug("%s: using private key %s", __func__, certfile);
-
- return (0);
}
int
Index: usr.sbin/relayd/relayd.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v
retrieving revision 1.176
diff -u -p -u -p -r1.176 relayd.c
--- usr.sbin/relayd/relayd.c 8 May 2019 23:22:19 -0000 1.176
+++ usr.sbin/relayd/relayd.c 13 May 2019 08:53:18 -0000
@@ -554,6 +554,7 @@ purge_relay(struct relayd *env, struct r
{
struct rsession *con;
struct relay_table *rlt;
+ struct relay_cert *cert, *tmpcert;
/* shutdown and remove relay */
if (event_initialized(&rlay->rl_ev))
@@ -572,7 +573,6 @@ purge_relay(struct relayd *env, struct r
if (rlay->rl_dstbev != NULL)
bufferevent_free(rlay->rl_dstbev);
- purge_key(&rlay->rl_tls_key, rlay->rl_conf.tls_key_len);
purge_key(&rlay->rl_tls_cakey, rlay->rl_conf.tls_cakey_len);
if (rlay->rl_tls_pkey != NULL) {
@@ -597,6 +597,19 @@ purge_relay(struct relayd *env, struct r
free(rlt);
}
+ TAILQ_FOREACH_SAFE(cert, env->sc_certs, cert_entry, tmpcert) {
+ if (rlay->rl_conf.id != cert->cert_relayid)
+ continue;
+ if (cert->cert_fd != -1)
+ close(cert->cert_fd);
+ if (cert->cert_key_fd != -1)
+ close(cert->cert_key_fd);
+ if (cert->cert_pkey != NULL)
+ EVP_PKEY_free(cert->cert_pkey);
+ TAILQ_REMOVE(env->sc_certs, cert, cert_entry);
+ free(cert);
+ }
+
free(rlay);
}
@@ -1234,6 +1247,127 @@ pkey_add(struct relayd *env, EVP_PKEY *p
TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry);
return (ca_pkey);
+}
+
+struct relay_cert *
+cert_add(struct relayd *env, objid_t id)
+{
+ static objid_t last_cert_id = 0;
+ struct relay_cert *cert;
+
+ if ((cert = calloc(1, sizeof(*cert))) == NULL)
+ return (NULL);
+
+ if (id == 0)
+ id = ++last_cert_id;
+ cert->cert_id = id;
+ cert->cert_fd = -1;
+ cert->cert_key_fd = -1;
+
+ TAILQ_INSERT_TAIL(env->sc_certs, cert, cert_entry);
+
+ return (cert);
+}
+
+struct relay_cert *
+cert_find(struct relayd *env, objid_t id)
+{
+ struct relay_cert *cert;
+
+ TAILQ_FOREACH(cert, env->sc_certs, cert_entry)
+ if (cert->cert_id == id)
+ return (cert);
+ return (NULL);
+}
+
+int
+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")];
+ struct protocol *proto = rlay->rl_proto;
+ struct relay_cert *cert;
+ int useport = htons(rlay->rl_conf.port);
+ int cert_fd = -1, key_fd = -1;
+
+ if (rlay->rl_conf.flags & F_TLSCLIENT) {
+ if (strlen(proto->tlsca) && rlay->rl_tls_ca_fd == -1) {
+ if ((rlay->rl_tls_ca_fd =
+ open(proto->tlsca, O_RDONLY)) == -1)
+ return (-1);
+ log_debug("%s: using ca %s", __func__, proto->tlsca);
+ }
+ if (strlen(proto->tlscacert) && rlay->rl_tls_cacert_fd == -1) {
+ if ((rlay->rl_tls_cacert_fd =
+ open(proto->tlscacert, O_RDONLY)) == -1)
+ return (-1);
+ log_debug("%s: using ca certificate %s", __func__,
+ proto->tlscacert);
+ }
+ if (strlen(proto->tlscakey) && !rlay->rl_conf.tls_cakey_len &&
+ proto->tlscapass != NULL) {
+ if ((rlay->rl_tls_cakey =
+ ssl_load_key(env, proto->tlscakey,
+ &rlay->rl_conf.tls_cakey_len,
+ proto->tlscapass)) == NULL)
+ return (-1);
+ log_debug("%s: using ca key %s", __func__,
+ proto->tlscakey);
+ }
+ }
+
+ if ((rlay->rl_conf.flags & F_TLS) == 0)
+ return (0);
+
+ 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)
+ goto fail;
+ if ((cert_fd = open(certfile, O_RDONLY)) == -1) {
+ if (snprintf(certfile, sizeof(certfile),
+ "/etc/ssl/%s.crt", hbuf) == -1)
+ goto fail;
+ if ((cert_fd = open(certfile, O_RDONLY)) == -1)
+ goto fail;
+ useport = 0;
+ }
+ log_debug("%s: using certificate %s", __func__, certfile);
+
+ if (useport) {
+ if (snprintf(certfile, sizeof(certfile),
+ "/etc/ssl/private/%s:%u.key", hbuf, useport) == -1)
+ goto fail;
+ } else {
+ if (snprintf(certfile, sizeof(certfile),
+ "/etc/ssl/private/%s.key", hbuf) == -1)
+ goto fail;
+ }
+ if ((key_fd = open(certfile, O_RDONLY)) == -1)
+ goto fail;
+ log_debug("%s: using private key %s", __func__, certfile);
+
+ if ((cert = cert_add(env, 0)) == NULL)
+ goto fail;
+
+ cert->cert_relayid = rlay->rl_conf.id;
+ cert->cert_fd = cert_fd;
+ cert->cert_key_fd = key_fd;
+
+ return (0);
+
+ fail:
+ if (cert_fd != -1)
+ close(cert_fd);
+ if (key_fd != -1)
+ close(key_fd);
+
+ return (-1);
}
void
Index: usr.sbin/relayd/relayd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.conf.5,v
retrieving revision 1.189
diff -u -p -u -p -r1.189 relayd.conf.5
--- usr.sbin/relayd/relayd.conf.5 10 May 2019 09:15:00 -0000 1.189
+++ usr.sbin/relayd/relayd.conf.5 13 May 2019 08:53:18 -0000
@@ -682,27 +682,10 @@ Like the previous directive, but for red
.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 i
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.
Index: usr.sbin/relayd/relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.254
diff -u -p -u -p -r1.254 relayd.h
--- usr.sbin/relayd/relayd.h 10 May 2019 09:15:00 -0000 1.254
+++ usr.sbin/relayd/relayd.h 13 May 2019 08:53:18 -0000
@@ -137,13 +137,18 @@ struct ctl_relaytable {
u_int32_t flags;
};
+enum fd_type {
+ RELAY_FD_CERT = 1,
+ RELAY_FD_CACERT = 2,
+ RELAY_FD_CAFILE = 3,
+ RELAY_FD_KEY = 4
+};
+
struct ctl_relayfd {
+ objid_t id;
objid_t relayid;
- int type;
+ enum fd_type type;
};
-#define RELAY_FD_CERT 1
-#define RELAY_FD_CACERT 2
-#define RELAY_FD_CAFILE 3
struct ctl_script {
objid_t host;
@@ -707,6 +712,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;
@@ -725,6 +736,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;
@@ -762,6 +774,16 @@ struct ca_pkey {
};
TAILQ_HEAD(ca_pkeylist, ca_pkey);
+struct relay_cert {
+ objid_t cert_id;
+ objid_t cert_relayid;
+ int cert_fd;
+ int cert_key_fd;
+ EVP_PKEY *cert_pkey;
+ TAILQ_ENTRY(relay_cert) cert_entry;
+};
+TAILQ_HEAD(relaycertlist, relay_cert);
+
struct relay_config {
objid_t id;
u_int32_t flags;
@@ -776,7 +798,6 @@ struct relay_config {
struct timeval timeout;
enum forwardmode fwdmode;
union hashkey hashkey;
- off_t tls_key_len;
off_t tls_cakey_len;
};
@@ -801,10 +822,8 @@ struct relay {
struct tls_config *rl_tls_client_cfg;
struct tls *rl_tls_ctx;
- int rl_tls_cert_fd;
- int rl_tls_ca_fd;
- int rl_tls_cacert_fd;
- char *rl_tls_key;
+ int rl_tls_ca_fd;
+ int rl_tls_cacert_fd;
EVP_PKEY *rl_tls_pkey;
X509 *rl_tls_cacertx509;
char *rl_tls_cakey;
@@ -1086,6 +1105,7 @@ struct relayd {
struct routerlist *sc_rts;
struct netroutelist *sc_routes;
struct ca_pkeylist *sc_pkeys;
+ struct relaycertlist *sc_certs;
struct sessionlist sc_sessions;
char sc_demote_group[IFNAMSIZ];
u_int16_t sc_id;
@@ -1179,7 +1199,6 @@ int relay_privinit(struct relay *);
void relay_notify_done(struct host *, const char *);
int relay_session_cmp(struct rsession *, struct rsession *);
char *relay_load_fd(int, off_t *);
-int relay_load_certfiles(struct relay *);
void relay_close(struct rsession *, const char *, int);
int relay_reset_event(struct ctl_relay_event *);
void relay_natlook(int, short, void *);
@@ -1293,6 +1312,10 @@ struct relay *relay_findbyname(struct re
struct relay *relay_findbyaddr(struct relayd *, struct relay_config *);
EVP_PKEY *pkey_find(struct relayd *, char *hash);
struct ca_pkey *pkey_add(struct relayd *, EVP_PKEY *, char *hash);
+struct relay_cert *cert_add(struct relayd *, objid_t);
+struct relay_cert *cert_find(struct relayd *, objid_t);
+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);