Blob


1 /* $OpenBSD: ca.c,v 1.50 2026/03/05 07:27:01 rsadowski Exp $ */
3 /*
4 * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <poll.h>
27 #include <imsg.h>
29 #include <openssl/bio.h>
30 #include <openssl/err.h>
31 #include <openssl/evp.h>
32 #include <openssl/pem.h>
33 #include <openssl/rsa.h>
34 #include <openssl/x509.h>
36 #include "relayd.h"
37 #include "log.h"
39 void ca_init(struct privsep *, struct privsep_proc *p, void *);
40 void ca_launch(void);
42 int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
43 int ca_dispatch_relay(int, struct privsep_proc *, struct imsg *);
45 int rsae_priv_enc(int, const u_char *, u_char *, RSA *, int);
46 int rsae_priv_dec(int, const u_char *, u_char *, RSA *, int);
48 static struct relayd *env = NULL;
50 static struct privsep_proc procs[] = {
51 { "parent", PROC_PARENT, ca_dispatch_parent },
52 { "relay", PROC_RELAY, ca_dispatch_relay },
53 };
55 void
56 ca(struct privsep *ps, struct privsep_proc *p)
57 {
58 env = ps->ps_env;
60 proc_run(ps, p, procs, nitems(procs), ca_init, NULL);
61 }
63 void
64 ca_init(struct privsep *ps, struct privsep_proc *p, void *arg)
65 {
66 if (pledge("stdio recvfd", NULL) == -1)
67 fatal("pledge");
69 if (config_init(ps->ps_env) == -1)
70 fatal("failed to initialize configuration");
72 env->sc_id = getpid() & 0xffff;
73 }
75 void
76 hash_x509(X509 *cert, char *hash, size_t hashlen)
77 {
78 static const char hex[] = "0123456789abcdef";
79 size_t off;
80 char digest[EVP_MAX_MD_SIZE];
81 int dlen, i;
83 if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
84 fatalx("%s: X509_pubkey_digest failed", __func__);
86 if (hashlen < 2 * dlen + sizeof("SHA256:"))
87 fatalx("%s: hash buffer too small", __func__);
89 off = strlcpy(hash, "SHA256:", hashlen);
91 for (i = 0; i < dlen; i++) {
92 hash[off++] = hex[(digest[i] >> 4) & 0x0f];
93 hash[off++] = hex[digest[i] & 0x0f];
94 }
95 hash[off] = 0;
96 }
98 void
99 ca_launch(void)
101 char hash[TLS_CERT_HASH_SIZE];
102 char *buf;
103 BIO *in = NULL;
104 EVP_PKEY *pkey = NULL;
105 struct relay *rlay;
106 struct relay_cert *cert;
107 X509 *x509 = NULL;
108 off_t len;
110 TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
111 if (cert->cert_fd == -1 || cert->cert_key_fd == -1)
112 continue;
114 if ((buf = relay_load_fd(cert->cert_fd, &len)) == NULL)
115 fatal("ca_launch: cert relay_load_fd");
117 if ((in = BIO_new_mem_buf(buf, len)) == NULL)
118 fatalx("ca_launch: cert BIO_new_mem_buf");
120 if ((x509 = PEM_read_bio_X509(in, NULL,
121 NULL, NULL)) == NULL)
122 fatalx("ca_launch: cert PEM_read_bio_X509");
124 hash_x509(x509, hash, sizeof(hash));
126 BIO_free(in);
127 X509_free(x509);
128 purge_key(&buf, len);
130 if ((buf = relay_load_fd(cert->cert_key_fd, &len)) == NULL)
131 fatal("ca_launch: key relay_load_fd");
133 if ((in = BIO_new_mem_buf(buf, len)) == NULL)
134 fatalx("%s: key", __func__);
136 if ((pkey = PEM_read_bio_PrivateKey(in,
137 NULL, NULL, NULL)) == NULL)
138 fatalx("%s: PEM", __func__);
140 cert->cert_pkey = pkey;
142 if (pkey_add(env, pkey, hash) == NULL)
143 fatalx("tls pkey");
145 BIO_free(in);
146 purge_key(&buf, len);
149 TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
150 if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
151 continue;
153 if (rlay->rl_tls_cacert_fd != -1 &&
154 rlay->rl_conf.tls_cakey_len) {
155 if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd,
156 &len)) == NULL)
157 fatal("ca_launch: cacert relay_load_fd");
159 if ((in = BIO_new_mem_buf(buf, len)) == NULL)
160 fatalx("ca_launch: cacert BIO_new_mem_buf");
162 if ((x509 = PEM_read_bio_X509(in, NULL,
163 NULL, NULL)) == NULL)
164 fatalx("ca_launch: cacert PEM_read_bio_X509");
166 hash_x509(x509, hash, sizeof(hash));
168 BIO_free(in);
169 X509_free(x509);
170 purge_key(&buf, len);
172 if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
173 rlay->rl_conf.tls_cakey_len)) == NULL)
174 fatalx("%s: key", __func__);
176 if ((pkey = PEM_read_bio_PrivateKey(in,
177 NULL, NULL, NULL)) == NULL)
178 fatalx("%s: PEM", __func__);
179 BIO_free(in);
181 rlay->rl_tls_capkey = pkey;
183 if (pkey_add(env, pkey, hash) == NULL)
184 fatalx("ca pkey");
186 purge_key(&rlay->rl_tls_cakey,
187 rlay->rl_conf.tls_cakey_len);
189 close(rlay->rl_tls_ca_fd);
193 int
194 ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
196 switch (imsg->hdr.type) {
197 case IMSG_CFG_RELAY:
198 config_getrelay(env, imsg);
199 break;
200 case IMSG_CFG_RELAY_FD:
201 config_getrelayfd(env, imsg);
202 break;
203 case IMSG_CFG_DONE:
204 config_getcfg(env, imsg);
205 break;
206 case IMSG_CTL_START:
207 ca_launch();
208 break;
209 case IMSG_CTL_RESET:
210 config_getreset(env, imsg);
211 break;
212 default:
213 return -1;
216 return 0;
219 int
220 ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
222 struct ctl_keyop cko;
223 EVP_PKEY *pkey;
224 RSA *rsa;
225 u_char *from = NULL, *to = NULL;
226 struct iovec iov[2];
227 int c = 0;
229 switch (imsg->hdr.type) {
230 case IMSG_CA_PRIVENC:
231 case IMSG_CA_PRIVDEC:
232 IMSG_SIZE_CHECK(imsg, (&cko));
233 bcopy(imsg->data, &cko, sizeof(cko));
234 if (cko.cko_proc > env->sc_conf.prefork_relay)
235 fatalx("%s: invalid relay proc", __func__);
236 if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
237 fatalx("%s: invalid key operation", __func__);
239 if ((pkey = pkey_find(env, cko.cko_hash)) == NULL) {
240 log_warnx("%s: invalid relay hash '%s'",
241 __func__, cko.cko_hash);
242 /* Signal failure to the waiting relay worker. */
243 cko.cko_tlen = -1;
244 iov[c].iov_base = &cko;
245 iov[c++].iov_len = sizeof(cko);
246 if (proc_composev_imsg(env->sc_ps, PROC_RELAY,
247 cko.cko_proc, imsg->hdr.type, -1, -1, iov,
248 c) == -1)
249 log_warn("%s: proc_composev_imsg", __func__);
250 break;
253 if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
254 fatalx("%s: invalid relay key", __func__);
256 DPRINTF("%s:%d: key hash %s proc %d",
257 __func__, __LINE__, cko.cko_hash, cko.cko_proc);
259 from = (u_char *)imsg->data + sizeof(cko);
260 if ((to = calloc(1, cko.cko_tlen)) == NULL)
261 fatalx("%s: calloc", __func__);
263 switch (imsg->hdr.type) {
264 case IMSG_CA_PRIVENC:
265 cko.cko_tlen = RSA_private_encrypt(cko.cko_flen,
266 from, to, rsa, cko.cko_padding);
267 break;
268 case IMSG_CA_PRIVDEC:
269 cko.cko_tlen = RSA_private_decrypt(cko.cko_flen,
270 from, to, rsa, cko.cko_padding);
271 break;
274 if (cko.cko_tlen == -1) {
275 char buf[256];
276 log_warnx("%s: %s", __func__,
277 ERR_error_string(ERR_get_error(), buf));
280 iov[c].iov_base = &cko;
281 iov[c++].iov_len = sizeof(cko);
282 if (cko.cko_tlen > 0) {
283 iov[c].iov_base = to;
284 iov[c++].iov_len = cko.cko_tlen;
287 if (proc_composev_imsg(env->sc_ps, PROC_RELAY, cko.cko_proc,
288 imsg->hdr.type, -1, -1, iov, c) == -1)
289 log_warn("%s: proc_composev_imsg", __func__);
291 free(to);
292 RSA_free(rsa);
293 break;
294 default:
295 return -1;
298 return 0;
301 /*
302 * RSA privsep engine (called from unprivileged processes)
303 */
305 static const RSA_METHOD *rsa_default;
306 static RSA_METHOD *rsae_method;
308 static int
309 rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa,
310 int padding, u_int cmd)
312 struct privsep *ps = env->sc_ps;
313 struct pollfd pfd[1];
314 struct ctl_keyop cko;
315 int ret = 0;
316 char *hash;
317 struct iovec iov[2];
318 struct imsgbuf *ibuf;
319 struct imsgev *iev;
320 struct imsg imsg;
321 int n, done = 0, cnt = 0;
322 u_char *toptr;
323 static u_int seq = 0;
325 if ((hash = RSA_get_ex_data(rsa, 0)) == NULL)
326 return 0;
328 iev = proc_iev(ps, PROC_CA, ps->ps_instance);
329 ibuf = &iev->ibuf;
331 /*
332 * XXX this could be nicer...
333 */
335 (void)strlcpy(cko.cko_hash, hash, sizeof(cko.cko_hash));
336 cko.cko_proc = ps->ps_instance;
337 cko.cko_flen = flen;
338 cko.cko_tlen = RSA_size(rsa);
339 cko.cko_padding = padding;
340 cko.cko_cookie = seq++;
342 iov[cnt].iov_base = &cko;
343 iov[cnt++].iov_len = sizeof(cko);
344 iov[cnt].iov_base = (void *)(uintptr_t)from;
345 iov[cnt++].iov_len = flen;
347 /*
348 * Send a synchronous imsg because we cannot defer the RSA
349 * operation in OpenSSL.
350 */
351 if (imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt) == -1) {
352 log_warn("%s: imsg_composev", __func__);
353 return -1;
355 if (imsgbuf_flush(ibuf) == -1) {
356 log_warn("%s: imsgbuf_flush", __func__);
357 return -1;
360 pfd[0].fd = ibuf->fd;
361 pfd[0].events = POLLIN;
362 while (!done) {
363 switch (poll(pfd, 1, RELAY_TLS_PRIV_TIMEOUT)) {
364 case -1:
365 if (errno != EINTR)
366 fatal("%s: poll", __func__);
367 continue;
368 case 0:
369 log_warnx("%s: priv%s poll timeout, keyop #%x",
370 __func__,
371 cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
372 cko.cko_cookie);
373 return -1;
374 default:
375 break;
377 if ((n = imsgbuf_read(ibuf)) == -1)
378 fatalx("imsgbuf_read");
379 if (n == 0)
380 fatalx("pipe closed");
382 while (!done) {
383 if ((n = imsg_get(ibuf, &imsg)) == -1)
384 fatalx("imsg_get error");
385 if (n == 0)
386 break;
388 IMSG_SIZE_CHECK(&imsg, (&cko));
389 memcpy(&cko, imsg.data, sizeof(cko));
391 /*
392 * Due to earlier timed out requests, there may be
393 * responses that need to be skipped.
394 */
395 if (cko.cko_cookie != seq - 1) {
396 log_warnx(
397 "%s: priv%s obsolete keyop #%x", __func__,
398 cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
399 cko.cko_cookie);
400 imsg_free(&imsg);
401 continue;
404 if (imsg.hdr.type != cmd)
405 fatalx("invalid response");
407 ret = cko.cko_tlen;
408 if (ret == -1) {
409 log_warnx("%s: priv%s failed for key %s",
410 __func__, cmd == IMSG_CA_PRIVENC ?
411 "enc" : "dec", cko.cko_hash);
412 } else if (ret > 0) {
413 if (IMSG_DATA_SIZE(&imsg) !=
414 (sizeof(cko) + ret))
415 fatalx("data size");
416 toptr = (u_char *)imsg.data + sizeof(cko);
417 memcpy(to, toptr, ret);
419 done = 1;
421 imsg_free(&imsg);
424 imsg_event_add(iev);
426 return ret;
429 int
430 rsae_priv_enc(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
432 DPRINTF("%s:%d", __func__, __LINE__);
433 return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVENC);
436 int
437 rsae_priv_dec(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
439 DPRINTF("%s:%d", __func__, __LINE__);
440 return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVDEC);
443 void
444 ca_engine_init(struct relayd *x_env)
446 const char *errstr;
448 if (env == NULL)
449 env = x_env;
451 if (rsa_default != NULL)
452 return;
454 if ((rsa_default = RSA_get_default_method()) == NULL) {
455 errstr = "RSA_get_default_method";
456 goto fail;
459 if ((rsae_method = RSA_meth_dup(rsa_default)) == NULL) {
460 errstr = "RSA_meth_dup";
461 goto fail;
464 RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc);
465 RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec);
467 RSA_meth_set_flags(rsae_method,
468 RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK);
469 RSA_meth_set0_app_data(rsae_method,
470 RSA_meth_get0_app_data(rsa_default));
472 RSA_set_default_method(rsae_method);
474 return;
476 fail:
477 RSA_meth_free(rsae_method);
478 fatalx("%s: %s", __func__, errstr);