jcs's openbsd hax
openbsd

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

tb 92388dee 80a776f5

+82 -15
+22 -1
usr.sbin/relayd/config.c
··· 1 - /* $OpenBSD: config.c,v 1.45 2024/01/17 10:01:24 claudio Exp $ */ 1 + /* $OpenBSD: config.c,v 1.46 2024/10/28 19:56:18 tb Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org> ··· 953 953 rlay->rl_conf.name); 954 954 return (-1); 955 955 } 956 + if (rlay->rl_tls_client_ca_fd != -1 && 957 + config_setrelayfd(ps, id, n, 0, 958 + rlay->rl_conf.id, RELAY_FD_CLIENTCACERT, 959 + rlay->rl_tls_client_ca_fd) == -1) { 960 + log_warn("%s: fd passing failed for " 961 + "`%s'", __func__, 962 + rlay->rl_conf.name); 963 + return (-1); 964 + } 956 965 /* Prevent fd exhaustion in the parent. */ 957 966 if (proc_flush_imsg(ps, id, n) == -1) { 958 967 log_warn("%s: failed to flush " ··· 986 995 close(rlay->rl_s); 987 996 rlay->rl_s = -1; 988 997 } 998 + if (rlay->rl_tls_client_ca_fd != -1) { 999 + close(rlay->rl_tls_client_ca_fd); 1000 + rlay->rl_tls_client_ca_fd = -1; 1001 + } 989 1002 if (rlay->rl_tls_cacert_fd != -1) { 990 1003 close(rlay->rl_tls_cacert_fd); 991 1004 rlay->rl_tls_cacert_fd = -1; ··· 1011 1024 cert->cert_ocsp_fd = -1; 1012 1025 } 1013 1026 } 1027 + if (rlay->rl_tls_client_ca_fd != -1) { 1028 + close(rlay->rl_tls_client_ca_fd); 1029 + rlay->rl_tls_client_ca_fd = -1; 1030 + } 1014 1031 1015 1032 return (0); 1016 1033 } ··· 1033 1050 rlay->rl_s = imsg_get_fd(imsg); 1034 1051 rlay->rl_tls_ca_fd = -1; 1035 1052 rlay->rl_tls_cacert_fd = -1; 1053 + rlay->rl_tls_client_ca_fd = -1; 1036 1054 1037 1055 if (ps->ps_what[privsep_process] & CONFIG_PROTOS) { 1038 1056 if (rlay->rl_conf.proto == EMPTY_ID) ··· 1161 1179 break; 1162 1180 case RELAY_FD_CAFILE: 1163 1181 rlay->rl_tls_cacert_fd = imsg_get_fd(imsg); 1182 + break; 1183 + case RELAY_FD_CLIENTCACERT: 1184 + rlay->rl_tls_client_ca_fd = imsg->fd; 1164 1185 break; 1165 1186 } 1166 1187
+15 -2
usr.sbin/relayd/parse.y
··· 1 - /* $OpenBSD: parse.y,v 1.257 2024/08/10 05:47:29 tb Exp $ */ 1 + /* $OpenBSD: parse.y,v 1.258 2024/10/28 19:56:18 tb Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org> ··· 179 179 %token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT URL WITH TTL RTABLE 180 180 %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE PASSWORD ECDHE 181 181 %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE CHANGES CHECKS 182 - %token WEBSOCKETS PFLOG 182 + %token WEBSOCKETS PFLOG CLIENT 183 183 %token <v.string> STRING 184 184 %token <v.number> NUMBER 185 185 %type <v.string> context hostname interface table value path ··· 1351 1351 name->name = $2; 1352 1352 TAILQ_INSERT_TAIL(&proto->tlscerts, name, entry); 1353 1353 } 1354 + | CLIENT CA STRING { 1355 + if (strlcpy(proto->tlsclientca, $3, 1356 + sizeof(proto->tlsclientca)) >= 1357 + sizeof(proto->tlsclientca)) { 1358 + yyerror("tlsclientca truncated"); 1359 + free($3); 1360 + YYERROR; 1361 + } 1362 + free($3); 1363 + } 1354 1364 | NO flag { proto->tlsflags &= ~($2); } 1355 1365 | flag { proto->tlsflags |= $1; } 1356 1366 ; ··· 1822 1832 r->rl_conf.dstretry = 0; 1823 1833 r->rl_tls_ca_fd = -1; 1824 1834 r->rl_tls_cacert_fd = -1; 1835 + r->rl_tls_client_ca_fd = -1; 1825 1836 TAILQ_INIT(&r->rl_tables); 1826 1837 if (last_relay_id == INT_MAX) { 1827 1838 yyerror("too many relays defined"); ··· 2411 2422 { "check", CHECK }, 2412 2423 { "checks", CHECKS }, 2413 2424 { "ciphers", CIPHERS }, 2425 + { "client", CLIENT }, 2414 2426 { "code", CODE }, 2415 2427 { "connection", CONNECTION }, 2416 2428 { "context", CONTEXT }, ··· 3397 3409 if (!(rb->rl_conf.flags & F_TLS)) { 3398 3410 rb->rl_tls_cacert_fd = -1; 3399 3411 rb->rl_tls_ca_fd = -1; 3412 + rb->rl_tls_client_ca_fd = -1; 3400 3413 } 3401 3414 TAILQ_INIT(&rb->rl_tables); 3402 3415
+22 -3
usr.sbin/relayd/relay.c
··· 1 - /* $OpenBSD: relay.c,v 1.259 2024/01/17 10:01:24 claudio Exp $ */ 1 + /* $OpenBSD: relay.c,v 1.260 2024/10/28 19:56:18 tb Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org> ··· 2159 2159 tls_config_insecure_noverifyname(tls_client_cfg); 2160 2160 2161 2161 if (rlay->rl_tls_ca_fd != -1) { 2162 - if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) == 2163 - NULL) { 2162 + if ((buf = relay_load_fd(rlay->rl_tls_ca_fd, &len)) == NULL) { 2164 2163 log_warn("failed to read root certificates"); 2165 2164 goto err; 2166 2165 } ··· 2250 2249 goto err; 2251 2250 } 2252 2251 rlay->rl_tls_cacert_fd = -1; 2252 + 2253 + if (rlay->rl_tls_client_ca_fd != -1) { 2254 + if ((buf = relay_load_fd(rlay->rl_tls_client_ca_fd, 2255 + &len)) == NULL) { 2256 + log_warn( 2257 + "failed to read tls client CA certificate"); 2258 + goto err; 2259 + } 2260 + 2261 + if (tls_config_set_ca_mem(tls_cfg, buf, len) != 0) { 2262 + log_warnx( 2263 + "failed to set tls client CA cert: %s", 2264 + tls_config_error(tls_cfg)); 2265 + goto err; 2266 + } 2267 + purge_key(&buf, len); 2268 + 2269 + tls_config_verify_client(tls_cfg); 2270 + } 2271 + rlay->rl_tls_client_ca_fd = -1; 2253 2272 2254 2273 tls = tls_server(); 2255 2274 if (tls == NULL) {
+9 -1
usr.sbin/relayd/relayd.c
··· 1 - /* $OpenBSD: relayd.c,v 1.191 2023/06/25 08:07:38 op Exp $ */ 1 + /* $OpenBSD: relayd.c,v 1.192 2024/10/28 19:56:18 tb Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org> ··· 1358 1358 1359 1359 if ((rlay->rl_conf.flags & F_TLS) == 0) 1360 1360 return (0); 1361 + 1362 + if (strlen(proto->tlsclientca) && rlay->rl_tls_client_ca_fd == -1) { 1363 + if ((rlay->rl_tls_client_ca_fd = 1364 + open(proto->tlsclientca, O_RDONLY)) == -1) 1365 + return (-1); 1366 + log_debug("%s: using client ca %s", __func__, 1367 + proto->tlsclientca); 1368 + } 1361 1369 1362 1370 if (name == NULL && 1363 1371 print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
+5 -2
usr.sbin/relayd/relayd.conf.5
··· 1 - .\" $OpenBSD: relayd.conf.5,v 1.210 2024/09/21 05:37:26 aisha Exp $ 1 + .\" $OpenBSD: relayd.conf.5,v 1.211 2024/10/28 19:56:18 tb Exp $ 2 2 .\" 3 3 .\" Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org> 4 4 .\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> ··· 15 15 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 16 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 17 .\" 18 - .Dd $Mdocdate: September 21 2024 $ 18 + .Dd $Mdocdate: October 28 2024 $ 19 19 .Dt RELAYD.CONF 5 20 20 .Os 21 21 .Sh NAME ··· 954 954 See the CIPHERS section of 955 955 .Xr openssl 1 956 956 for information about TLS cipher suites and preference lists. 957 + .It Ic client ca Ar path 958 + Require TLS client certificates that can be verified against the CA 959 + certificates in the specified file. 957 960 .It Ic client-renegotiation 958 961 Allow client-initiated renegotiation. 959 962 To mitigate a potential DoS risk,
+9 -6
usr.sbin/relayd/relayd.h
··· 1 - /* $OpenBSD: relayd.h,v 1.275 2024/10/08 05:28:11 jsg Exp $ */ 1 + /* $OpenBSD: relayd.h,v 1.276 2024/10/28 19:56:18 tb Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org> ··· 137 137 }; 138 138 139 139 enum fd_type { 140 - RELAY_FD_CERT = 1, 141 - RELAY_FD_CACERT = 2, 142 - RELAY_FD_CAFILE = 3, 143 - RELAY_FD_KEY = 4, 144 - RELAY_FD_OCSP = 5 140 + RELAY_FD_CERT = 1, 141 + RELAY_FD_CACERT = 2, 142 + RELAY_FD_CAFILE = 3, 143 + RELAY_FD_KEY = 4, 144 + RELAY_FD_OCSP = 5, 145 + RELAY_FD_CLIENTCACERT = 6 145 146 }; 146 147 147 148 struct ctl_relayfd { ··· 744 745 char tlscacert[PATH_MAX]; 745 746 char tlscakey[PATH_MAX]; 746 747 char *tlscapass; 748 + char tlsclientca[PATH_MAX]; 747 749 struct keynamelist tlscerts; 748 750 char name[MAX_NAME_SIZE]; 749 751 int tickets; ··· 833 835 834 836 int rl_tls_ca_fd; 835 837 int rl_tls_cacert_fd; 838 + int rl_tls_client_ca_fd; 836 839 EVP_PKEY *rl_tls_pkey; 837 840 X509 *rl_tls_cacertx509; 838 841 char *rl_tls_cakey;