From 9c8257350f691b5ea6ead6f91b3c3cc11a2be7bf Mon Sep 17 00:00:00 2001 From: Theo Buehler Date: Mon, 28 Oct 2024 19:56:19 +0000 Subject: relayd: add support for client certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature has been requested many times over the years. Various patches were provided by Asherah Connor, Rivo Nurges, Markus Läll and maybe others. These patches always stalled for various reasons. From Sören Tempel, mostly based on Asherah's latest patch. ok florian tb --- usr.sbin/relayd/config.c | 23 ++++++++++++++++++++++- usr.sbin/relayd/parse.y | 17 +++++++++++++++-- usr.sbin/relayd/relay.c | 25 ++++++++++++++++++++++--- usr.sbin/relayd/relayd.c | 10 +++++++++- usr.sbin/relayd/relayd.conf.5 | 7 +++++-- usr.sbin/relayd/relayd.h | 15 +++++++++------ 6 files changed, 82 insertions(+), 15 deletions(-) (limited to 'usr.sbin') diff --git a/usr.sbin/relayd/config.c b/usr.sbin/relayd/config.c index 3024c0768f0..83f4ec87fc8 100644 --- a/usr.sbin/relayd/config.c +++ b/usr.sbin/relayd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.45 2024/01/17 10:01:24 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.46 2024/10/28 19:56:18 tb Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter @@ -953,6 +953,15 @@ config_setrelay(struct relayd *env, struct relay *rlay) rlay->rl_conf.name); return (-1); } + if (rlay->rl_tls_client_ca_fd != -1 && + config_setrelayfd(ps, id, n, 0, + rlay->rl_conf.id, RELAY_FD_CLIENTCACERT, + rlay->rl_tls_client_ca_fd) == -1) { + log_warn("%s: fd passing failed for " + "`%s'", __func__, + rlay->rl_conf.name); + return (-1); + } /* Prevent fd exhaustion in the parent. */ if (proc_flush_imsg(ps, id, n) == -1) { log_warn("%s: failed to flush " @@ -986,6 +995,10 @@ config_setrelay(struct relayd *env, struct relay *rlay) close(rlay->rl_s); rlay->rl_s = -1; } + if (rlay->rl_tls_client_ca_fd != -1) { + close(rlay->rl_tls_client_ca_fd); + rlay->rl_tls_client_ca_fd = -1; + } if (rlay->rl_tls_cacert_fd != -1) { close(rlay->rl_tls_cacert_fd); rlay->rl_tls_cacert_fd = -1; @@ -1011,6 +1024,10 @@ config_setrelay(struct relayd *env, struct relay *rlay) cert->cert_ocsp_fd = -1; } } + if (rlay->rl_tls_client_ca_fd != -1) { + close(rlay->rl_tls_client_ca_fd); + rlay->rl_tls_client_ca_fd = -1; + } return (0); } @@ -1033,6 +1050,7 @@ config_getrelay(struct relayd *env, struct imsg *imsg) rlay->rl_s = imsg_get_fd(imsg); rlay->rl_tls_ca_fd = -1; rlay->rl_tls_cacert_fd = -1; + rlay->rl_tls_client_ca_fd = -1; if (ps->ps_what[privsep_process] & CONFIG_PROTOS) { if (rlay->rl_conf.proto == EMPTY_ID) @@ -1162,6 +1180,9 @@ config_getrelayfd(struct relayd *env, struct imsg *imsg) case RELAY_FD_CAFILE: rlay->rl_tls_cacert_fd = imsg_get_fd(imsg); break; + case RELAY_FD_CLIENTCACERT: + rlay->rl_tls_client_ca_fd = imsg->fd; + break; } DPRINTF("%s: %s %d received relay fd %d type %d for relay %s", __func__, diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y index eea485c4471..fcdfb8e92e3 100644 --- a/usr.sbin/relayd/parse.y +++ b/usr.sbin/relayd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.257 2024/08/10 05:47:29 tb Exp $ */ +/* $OpenBSD: parse.y,v 1.258 2024/10/28 19:56:18 tb Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter @@ -179,7 +179,7 @@ typedef struct { %token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT URL WITH TTL RTABLE %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDHE %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE CHANGES CHECKS -%token WEBSOCKETS PFLOG +%token WEBSOCKETS PFLOG CLIENT %token STRING %token NUMBER %type context hostname interface table value path @@ -1351,6 +1351,16 @@ tlsflags : SESSION TICKETS { proto->tickets = 1; } name->name = $2; TAILQ_INSERT_TAIL(&proto->tlscerts, name, entry); } + | CLIENT CA STRING { + if (strlcpy(proto->tlsclientca, $3, + sizeof(proto->tlsclientca)) >= + sizeof(proto->tlsclientca)) { + yyerror("tlsclientca truncated"); + free($3); + YYERROR; + } + free($3); + } | NO flag { proto->tlsflags &= ~($2); } | flag { proto->tlsflags |= $1; } ; @@ -1822,6 +1832,7 @@ relay : RELAY STRING { r->rl_conf.dstretry = 0; r->rl_tls_ca_fd = -1; r->rl_tls_cacert_fd = -1; + r->rl_tls_client_ca_fd = -1; TAILQ_INIT(&r->rl_tables); if (last_relay_id == INT_MAX) { yyerror("too many relays defined"); @@ -2411,6 +2422,7 @@ lookup(char *s) { "check", CHECK }, { "checks", CHECKS }, { "ciphers", CIPHERS }, + { "client", CLIENT }, { "code", CODE }, { "connection", CONNECTION }, { "context", CONTEXT }, @@ -3397,6 +3409,7 @@ relay_inherit(struct relay *ra, struct relay *rb) if (!(rb->rl_conf.flags & F_TLS)) { rb->rl_tls_cacert_fd = -1; rb->rl_tls_ca_fd = -1; + rb->rl_tls_client_ca_fd = -1; } TAILQ_INIT(&rb->rl_tables); diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c index c29f3917152..6d0970802c5 100644 --- a/usr.sbin/relayd/relay.c +++ b/usr.sbin/relayd/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.259 2024/01/17 10:01:24 claudio Exp $ */ +/* $OpenBSD: relay.c,v 1.260 2024/10/28 19:56:18 tb Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -2159,8 +2159,7 @@ relay_tls_ctx_create(struct relay *rlay) tls_config_insecure_noverifyname(tls_client_cfg); if (rlay->rl_tls_ca_fd != -1) { - if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) == - NULL) { + if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) == NULL) { log_warn("failed to read root certificates"); goto err; } @@ -2251,6 +2250,26 @@ relay_tls_ctx_create(struct relay *rlay) } rlay->rl_tls_cacert_fd = -1; + if (rlay->rl_tls_client_ca_fd != -1) { + if ((buf = relay_load_fd(rlay->rl_tls_client_ca_fd, + &len)) == NULL) { + log_warn( + "failed to read tls client CA certificate"); + goto err; + } + + if (tls_config_set_ca_mem(tls_cfg, buf, len) != 0) { + log_warnx( + "failed to set tls client CA cert: %s", + tls_config_error(tls_cfg)); + goto err; + } + purge_key(&buf, len); + + tls_config_verify_client(tls_cfg); + } + rlay->rl_tls_client_ca_fd = -1; + tls = tls_server(); if (tls == NULL) { log_warnx("unable to allocate TLS context"); diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c index df93c9527cb..76fa9e8b043 100644 --- a/usr.sbin/relayd/relayd.c +++ b/usr.sbin/relayd/relayd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.c,v 1.191 2023/06/25 08:07:38 op Exp $ */ +/* $OpenBSD: relayd.c,v 1.192 2024/10/28 19:56:18 tb Exp $ */ /* * Copyright (c) 2007 - 2016 Reyk Floeter @@ -1359,6 +1359,14 @@ relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name) if ((rlay->rl_conf.flags & F_TLS) == 0) return (0); + if (strlen(proto->tlsclientca) && rlay->rl_tls_client_ca_fd == -1) { + if ((rlay->rl_tls_client_ca_fd = + open(proto->tlsclientca, O_RDONLY)) == -1) + return (-1); + log_debug("%s: using client ca %s", __func__, + proto->tlsclientca); + } + if (name == NULL && print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL) goto fail; diff --git a/usr.sbin/relayd/relayd.conf.5 b/usr.sbin/relayd/relayd.conf.5 index 50c73cbec15..8372875b853 100644 --- a/usr.sbin/relayd/relayd.conf.5 +++ b/usr.sbin/relayd/relayd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: relayd.conf.5,v 1.210 2024/09/21 05:37:26 aisha Exp $ +.\" $OpenBSD: relayd.conf.5,v 1.211 2024/10/28 19:56:18 tb Exp $ .\" .\" Copyright (c) 2006 - 2016 Reyk Floeter .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard @@ -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: September 21 2024 $ +.Dd $Mdocdate: October 28 2024 $ .Dt RELAYD.CONF 5 .Os .Sh NAME @@ -954,6 +954,9 @@ will be used (strong crypto cipher suites without anonymous DH). See the CIPHERS section of .Xr openssl 1 for information about TLS cipher suites and preference lists. +.It Ic client ca Ar path +Require TLS client certificates that can be verified against the CA +certificates in the specified file. .It Ic client-renegotiation Allow client-initiated renegotiation. To mitigate a potential DoS risk, diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index 865cf31ad69..3b5c3987f93 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.275 2024/10/08 05:28:11 jsg Exp $ */ +/* $OpenBSD: relayd.h,v 1.276 2024/10/28 19:56:18 tb Exp $ */ /* * Copyright (c) 2006 - 2016 Reyk Floeter @@ -137,11 +137,12 @@ struct ctl_relaytable { }; enum fd_type { - RELAY_FD_CERT = 1, - RELAY_FD_CACERT = 2, - RELAY_FD_CAFILE = 3, - RELAY_FD_KEY = 4, - RELAY_FD_OCSP = 5 + RELAY_FD_CERT = 1, + RELAY_FD_CACERT = 2, + RELAY_FD_CAFILE = 3, + RELAY_FD_KEY = 4, + RELAY_FD_OCSP = 5, + RELAY_FD_CLIENTCACERT = 6 }; struct ctl_relayfd { @@ -744,6 +745,7 @@ struct protocol { char tlscacert[PATH_MAX]; char tlscakey[PATH_MAX]; char *tlscapass; + char tlsclientca[PATH_MAX]; struct keynamelist tlscerts; char name[MAX_NAME_SIZE]; int tickets; @@ -833,6 +835,7 @@ struct relay { int rl_tls_ca_fd; int rl_tls_cacert_fd; + int rl_tls_client_ca_fd; EVP_PKEY *rl_tls_pkey; X509 *rl_tls_cacertx509; char *rl_tls_cakey; -- cgit v1.2.3