commit c4efe747621091eebe4473e6bf136cb19c94288f from: tb date: Mon Oct 28 19:56:18 2024 UTC relayd: add support for client certificates 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 commit - 2247e7efae7f1538279d98e57f9c26710f516091 commit + c4efe747621091eebe4473e6bf136cb19c94288f blob - 3024c0768f01715a640e806aef0cf4b22e557fda blob + 83f4ec87fc83b3802ab504ff81b3dea0162ef9df --- config.c +++ 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 *ims 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__, blob - eea485c447120f402eeef37932b5b2509f6e5b74 blob + fcdfb8e92e3710e8fcc2ed2eb19593d716ab4a9f --- parse.y +++ 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); blob - c29f39171522e9163ac18ce68b7012f954ff6248 blob + 6d0970802c5edf8374b5aeb69be17b0814676cb9 --- relay.c +++ 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"); blob - df93c9527cb446a45002a63b61567e5784f87255 blob + 76fa9e8b04386370d57dcfb9c191fa839694178d --- relayd.c +++ 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 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; blob - 50c73cbec157974b7bc13b2706108caf5d97636f blob + 8372875b8537858ba8411bac64a34d4ecdf4085b --- relayd.conf.5 +++ 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 anon 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, blob - 865cf31ad69000f2a7a9e2bad67e3c1972117da9 blob + 3b5c3987f93e1a42fd5966a957cae82cf870d35a --- relayd.h +++ 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;