xref: /openbsd-src/usr.sbin/relayd/ca.c (revision 668e5ba9d849ae9114791a34abcbab5f3a0c54d7)
1*668e5ba9Sclaudio /*	$OpenBSD: ca.c,v 1.45 2024/11/21 13:21:34 claudio Exp $	*/
23d77879fSreyk 
33d77879fSreyk /*
43d77879fSreyk  * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
53d77879fSreyk  *
63d77879fSreyk  * Permission to use, copy, modify, and distribute this software for any
73d77879fSreyk  * purpose with or without fee is hereby granted, provided that the above
83d77879fSreyk  * copyright notice and this permission notice appear in all copies.
93d77879fSreyk  *
103d77879fSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113d77879fSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123d77879fSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133d77879fSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143d77879fSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153d77879fSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163d77879fSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173d77879fSreyk  */
183d77879fSreyk 
19f04ff968Sreyk #include <sys/types.h>
203d77879fSreyk #include <sys/queue.h>
213d77879fSreyk #include <sys/uio.h>
223d77879fSreyk 
233d77879fSreyk #include <unistd.h>
243d77879fSreyk #include <string.h>
253d77879fSreyk #include <stdlib.h>
266778e0bdSclaudio #include <poll.h>
27f04ff968Sreyk #include <imsg.h>
283d77879fSreyk 
29f04ff968Sreyk #include <openssl/bio.h>
30f1b4a8a5Stb #include <openssl/err.h>
313d77879fSreyk #include <openssl/evp.h>
32f1b4a8a5Stb #include <openssl/pem.h>
333d77879fSreyk #include <openssl/rsa.h>
343d77879fSreyk #include <openssl/engine.h>
353d77879fSreyk 
363d77879fSreyk #include "relayd.h"
373d77879fSreyk 
383d77879fSreyk void	 ca_init(struct privsep *, struct privsep_proc *p, void *);
393d77879fSreyk void	 ca_launch(void);
403d77879fSreyk 
413d77879fSreyk int	 ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
423d77879fSreyk int	 ca_dispatch_relay(int, struct privsep_proc *, struct imsg *);
433d77879fSreyk 
443d77879fSreyk int	 rsae_priv_enc(int, const u_char *, u_char *, RSA *, int);
453d77879fSreyk int	 rsae_priv_dec(int, const u_char *, u_char *, RSA *, int);
463d77879fSreyk 
473d77879fSreyk static struct relayd *env = NULL;
483d77879fSreyk 
493d77879fSreyk static struct privsep_proc procs[] = {
503d77879fSreyk 	{ "parent",	PROC_PARENT,	ca_dispatch_parent },
513d77879fSreyk 	{ "relay",	PROC_RELAY,	ca_dispatch_relay },
523d77879fSreyk };
533d77879fSreyk 
54f910ac11Sreyk void
553d77879fSreyk ca(struct privsep *ps, struct privsep_proc *p)
563d77879fSreyk {
573d77879fSreyk 	env = ps->ps_env;
583d77879fSreyk 
59f910ac11Sreyk 	proc_run(ps, p, procs, nitems(procs), ca_init, NULL);
603d77879fSreyk }
613d77879fSreyk 
623d77879fSreyk void
633d77879fSreyk ca_init(struct privsep *ps, struct privsep_proc *p, void *arg)
643d77879fSreyk {
653d6ff6edSreyk 	if (pledge("stdio recvfd", NULL) == -1)
669d396bfeSbenno 		fatal("pledge");
679d396bfeSbenno 
683d77879fSreyk 	if (config_init(ps->ps_env) == -1)
693d77879fSreyk 		fatal("failed to initialize configuration");
703d77879fSreyk 
713d77879fSreyk 	env->sc_id = getpid() & 0xffff;
723d77879fSreyk }
733d77879fSreyk 
74f8a1e24fSbluhm void
75f8a1e24fSbluhm hash_x509(X509 *cert, char *hash, size_t hashlen)
7685e5f500Sclaudio {
7785e5f500Sclaudio 	static const char	hex[] = "0123456789abcdef";
78f8a1e24fSbluhm 	size_t			off;
79f8a1e24fSbluhm 	char			digest[EVP_MAX_MD_SIZE];
80f8a1e24fSbluhm 	int			dlen, i;
81f8a1e24fSbluhm 
8223276981Sclaudio 	if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
8323276981Sclaudio 		fatalx("%s: X509_pubkey_digest failed", __func__);
8485e5f500Sclaudio 
8585e5f500Sclaudio 	if (hashlen < 2 * dlen + sizeof("SHA256:"))
867078bf6aSop 		fatalx("%s: hash buffer too small", __func__);
8785e5f500Sclaudio 
8885e5f500Sclaudio 	off = strlcpy(hash, "SHA256:", hashlen);
8985e5f500Sclaudio 
9085e5f500Sclaudio 	for (i = 0; i < dlen; i++) {
91f8a1e24fSbluhm 		hash[off++] = hex[(digest[i] >> 4) & 0x0f];
92f8a1e24fSbluhm 		hash[off++] = hex[digest[i] & 0x0f];
9385e5f500Sclaudio 	}
9485e5f500Sclaudio 	hash[off] = 0;
9585e5f500Sclaudio }
9685e5f500Sclaudio 
973d77879fSreyk void
983d77879fSreyk ca_launch(void)
993d77879fSreyk {
100f8a1e24fSbluhm 	char			 hash[TLS_CERT_HASH_SIZE];
101114ce177Sclaudio 	char			*buf;
1023d77879fSreyk 	BIO			*in = NULL;
1033d77879fSreyk 	EVP_PKEY		*pkey = NULL;
1043d77879fSreyk 	struct relay		*rlay;
105f2f4e153Sreyk 	struct relay_cert	*cert;
106f2f4e153Sreyk 	X509			*x509 = NULL;
107114ce177Sclaudio 	off_t			 len;
1083d77879fSreyk 
109f2f4e153Sreyk 	TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
110f2f4e153Sreyk 		if (cert->cert_fd == -1 || cert->cert_key_fd == -1)
1113d77879fSreyk 			continue;
1123d77879fSreyk 
113f2f4e153Sreyk 		if ((buf = relay_load_fd(cert->cert_fd, &len)) == NULL)
1140987b10dSclaudio 			fatal("ca_launch: cert relay_load_fd");
115114ce177Sclaudio 
116114ce177Sclaudio 		if ((in = BIO_new_mem_buf(buf, len)) == NULL)
117a7c0a300Sbluhm 			fatalx("ca_launch: cert BIO_new_mem_buf");
11885e5f500Sclaudio 
119f2f4e153Sreyk 		if ((x509 = PEM_read_bio_X509(in, NULL,
12085e5f500Sclaudio 		    NULL, NULL)) == NULL)
121a7c0a300Sbluhm 			fatalx("ca_launch: cert PEM_read_bio_X509");
12285e5f500Sclaudio 
123f2f4e153Sreyk 		hash_x509(x509, hash, sizeof(hash));
12485e5f500Sclaudio 
12585e5f500Sclaudio 		BIO_free(in);
126f2f4e153Sreyk 		X509_free(x509);
127114ce177Sclaudio 		purge_key(&buf, len);
128f2f4e153Sreyk 
129f2f4e153Sreyk 		if ((buf = relay_load_fd(cert->cert_key_fd, &len)) == NULL)
130f2f4e153Sreyk 			fatal("ca_launch: key relay_load_fd");
131f2f4e153Sreyk 
132f2f4e153Sreyk 		if ((in = BIO_new_mem_buf(buf, len)) == NULL)
133efc39811Sbenno 			fatalx("%s: key", __func__);
1343d77879fSreyk 
1353d77879fSreyk 		if ((pkey = PEM_read_bio_PrivateKey(in,
1363d77879fSreyk 		    NULL, NULL, NULL)) == NULL)
137efc39811Sbenno 			fatalx("%s: PEM", __func__);
1383d77879fSreyk 
139f2f4e153Sreyk 		cert->cert_pkey = pkey;
1403d77879fSreyk 
14185e5f500Sclaudio 		if (pkey_add(env, pkey, hash) == NULL)
1427bb52228Sreyk 			fatalx("tls pkey");
14300ae3104Sreyk 
144f2f4e153Sreyk 		BIO_free(in);
145f2f4e153Sreyk 		purge_key(&buf, len);
14632a86e7dSreyk 	}
14785e5f500Sclaudio 
148f2f4e153Sreyk 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
149f2f4e153Sreyk 		if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
150f2f4e153Sreyk 			continue;
151f2f4e153Sreyk 
152f2f4e153Sreyk 		if (rlay->rl_tls_cacert_fd != -1 &&
153f2f4e153Sreyk 		    rlay->rl_conf.tls_cakey_len) {
154114ce177Sclaudio 			if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd,
155114ce177Sclaudio 			    &len)) == NULL)
1560987b10dSclaudio 				fatal("ca_launch: cacert relay_load_fd");
157114ce177Sclaudio 
158114ce177Sclaudio 			if ((in = BIO_new_mem_buf(buf, len)) == NULL)
159a7c0a300Sbluhm 				fatalx("ca_launch: cacert BIO_new_mem_buf");
16085e5f500Sclaudio 
161f2f4e153Sreyk 			if ((x509 = PEM_read_bio_X509(in, NULL,
16285e5f500Sclaudio 			    NULL, NULL)) == NULL)
163a7c0a300Sbluhm 				fatalx("ca_launch: cacert PEM_read_bio_X509");
16485e5f500Sclaudio 
165f2f4e153Sreyk 			hash_x509(x509, hash, sizeof(hash));
16685e5f500Sclaudio 
16785e5f500Sclaudio 			BIO_free(in);
168f2f4e153Sreyk 			X509_free(x509);
169114ce177Sclaudio 			purge_key(&buf, len);
170f2f4e153Sreyk 
1717bb52228Sreyk 			if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
1727bb52228Sreyk 			    rlay->rl_conf.tls_cakey_len)) == NULL)
173efc39811Sbenno 				fatalx("%s: key", __func__);
17400ae3104Sreyk 
17500ae3104Sreyk 			if ((pkey = PEM_read_bio_PrivateKey(in,
17600ae3104Sreyk 			    NULL, NULL, NULL)) == NULL)
177efc39811Sbenno 				fatalx("%s: PEM", __func__);
17800ae3104Sreyk 			BIO_free(in);
17900ae3104Sreyk 
1807bb52228Sreyk 			rlay->rl_tls_capkey = pkey;
18100ae3104Sreyk 
18285e5f500Sclaudio 			if (pkey_add(env, pkey, hash) == NULL)
18300ae3104Sreyk 				fatalx("ca pkey");
18400ae3104Sreyk 
1857bb52228Sreyk 			purge_key(&rlay->rl_tls_cakey,
1867bb52228Sreyk 			    rlay->rl_conf.tls_cakey_len);
18700ae3104Sreyk 		}
188114ce177Sclaudio 		close(rlay->rl_tls_ca_fd);
1893d77879fSreyk 	}
1903d77879fSreyk }
1913d77879fSreyk 
1923d77879fSreyk int
1933d77879fSreyk ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
1943d77879fSreyk {
1953d77879fSreyk 	switch (imsg->hdr.type) {
1963d77879fSreyk 	case IMSG_CFG_RELAY:
1973d77879fSreyk 		config_getrelay(env, imsg);
1983d77879fSreyk 		break;
199114ce177Sclaudio 	case IMSG_CFG_RELAY_FD:
200114ce177Sclaudio 		config_getrelayfd(env, imsg);
201114ce177Sclaudio 		break;
2023d77879fSreyk 	case IMSG_CFG_DONE:
2033d77879fSreyk 		config_getcfg(env, imsg);
2043d77879fSreyk 		break;
2053d77879fSreyk 	case IMSG_CTL_START:
2063d77879fSreyk 		ca_launch();
2073d77879fSreyk 		break;
2083d77879fSreyk 	case IMSG_CTL_RESET:
2093d77879fSreyk 		config_getreset(env, imsg);
2103d77879fSreyk 		break;
2113d77879fSreyk 	default:
212ad3e8fb5Stb 		return -1;
2133d77879fSreyk 	}
2143d77879fSreyk 
215ad3e8fb5Stb 	return 0;
2163d77879fSreyk }
2173d77879fSreyk 
2183d77879fSreyk int
2193d77879fSreyk ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
2203d77879fSreyk {
2213d77879fSreyk 	struct ctl_keyop	 cko;
2223d77879fSreyk 	EVP_PKEY		*pkey;
2233d77879fSreyk 	RSA			*rsa;
2243d77879fSreyk 	u_char			*from = NULL, *to = NULL;
2253d77879fSreyk 	struct iovec		 iov[2];
2263d77879fSreyk 	int			 c = 0;
2273d77879fSreyk 
2283d77879fSreyk 	switch (imsg->hdr.type) {
2293d77879fSreyk 	case IMSG_CA_PRIVENC:
2303d77879fSreyk 	case IMSG_CA_PRIVDEC:
2313d77879fSreyk 		IMSG_SIZE_CHECK(imsg, (&cko));
2323d77879fSreyk 		bcopy(imsg->data, &cko, sizeof(cko));
233586b5f8aSreyk 		if (cko.cko_proc > env->sc_conf.prefork_relay)
234efc39811Sbenno 			fatalx("%s: invalid relay proc", __func__);
2353d77879fSreyk 		if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
236efc39811Sbenno 			fatalx("%s: invalid key operation", __func__);
237f8a1e24fSbluhm 		if ((pkey = pkey_find(env, cko.cko_hash)) == NULL)
238f8a1e24fSbluhm 			fatalx("%s: invalid relay hash '%s'",
239f8a1e24fSbluhm 			    __func__, cko.cko_hash);
240f8a1e24fSbluhm 		if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
241f8a1e24fSbluhm 			fatalx("%s: invalid relay key", __func__);
2423d77879fSreyk 
24385e5f500Sclaudio 		DPRINTF("%s:%d: key hash %s proc %d",
24485e5f500Sclaudio 		    __func__, __LINE__, cko.cko_hash, cko.cko_proc);
24500ae3104Sreyk 
2463d77879fSreyk 		from = (u_char *)imsg->data + sizeof(cko);
2473d77879fSreyk 		if ((to = calloc(1, cko.cko_tlen)) == NULL)
248efc39811Sbenno 			fatalx("%s: calloc", __func__);
2493d77879fSreyk 
2503d77879fSreyk 		switch (imsg->hdr.type) {
2513d77879fSreyk 		case IMSG_CA_PRIVENC:
2523d77879fSreyk 			cko.cko_tlen = RSA_private_encrypt(cko.cko_flen,
2533d77879fSreyk 			    from, to, rsa, cko.cko_padding);
2543d77879fSreyk 			break;
2553d77879fSreyk 		case IMSG_CA_PRIVDEC:
2563d77879fSreyk 			cko.cko_tlen = RSA_private_decrypt(cko.cko_flen,
2573d77879fSreyk 			    from, to, rsa, cko.cko_padding);
2583d77879fSreyk 			break;
2593d77879fSreyk 		}
2603d77879fSreyk 
261e45fc33aSclaudio 		if (cko.cko_tlen == -1) {
262e45fc33aSclaudio 			char buf[256];
263e45fc33aSclaudio 			log_warnx("%s: %s", __func__,
264e45fc33aSclaudio 			    ERR_error_string(ERR_get_error(), buf));
265e45fc33aSclaudio 		}
266e45fc33aSclaudio 
2673d77879fSreyk 		iov[c].iov_base = &cko;
2683d77879fSreyk 		iov[c++].iov_len = sizeof(cko);
269e45fc33aSclaudio 		if (cko.cko_tlen > 0) {
2703d77879fSreyk 			iov[c].iov_base = to;
2713d77879fSreyk 			iov[c++].iov_len = cko.cko_tlen;
2723d77879fSreyk 		}
2733d77879fSreyk 
2747084d095Sclaudio 		if (proc_composev_imsg(env->sc_ps, PROC_RELAY, cko.cko_proc,
2757084d095Sclaudio 		    imsg->hdr.type, -1, -1, iov, c) == -1)
2767084d095Sclaudio 			log_warn("%s: proc_composev_imsg", __func__);
2773d77879fSreyk 
2783d77879fSreyk 		free(to);
2793d77879fSreyk 		RSA_free(rsa);
2803d77879fSreyk 		break;
2813d77879fSreyk 	default:
282ad3e8fb5Stb 		return -1;
2833d77879fSreyk 	}
2843d77879fSreyk 
285ad3e8fb5Stb 	return 0;
2863d77879fSreyk }
2873d77879fSreyk 
2883d77879fSreyk /*
2893d77879fSreyk  * RSA privsep engine (called from unprivileged processes)
2903d77879fSreyk  */
2913d77879fSreyk 
29227f65520Stb static const RSA_METHOD *rsa_default;
293ad3e8fb5Stb static RSA_METHOD *rsae_method;
2943d77879fSreyk 
2953d77879fSreyk static int
2968b624d89Sreyk rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa,
2978b624d89Sreyk     int padding, u_int cmd)
2983d77879fSreyk {
299325f6e14Sreyk 	struct privsep	*ps = env->sc_ps;
3006778e0bdSclaudio 	struct pollfd	 pfd[1];
3013d77879fSreyk 	struct ctl_keyop cko;
3023d77879fSreyk 	int		 ret = 0;
30385e5f500Sclaudio 	char		*hash;
3043d77879fSreyk 	struct iovec	 iov[2];
3053d77879fSreyk 	struct imsgbuf	*ibuf;
3063d77879fSreyk 	struct imsgev	*iev;
3073d77879fSreyk 	struct imsg	 imsg;
3083d77879fSreyk 	int		 n, done = 0, cnt = 0;
3093d77879fSreyk 	u_char		*toptr;
310c7e61995Sclaudio 	static u_int	 seq = 0;
3113d77879fSreyk 
31285e5f500Sclaudio 	if ((hash = RSA_get_ex_data(rsa, 0)) == NULL)
313ad3e8fb5Stb 		return 0;
3143d77879fSreyk 
315325f6e14Sreyk 	iev = proc_iev(ps, PROC_CA, ps->ps_instance);
3163d77879fSreyk 	ibuf = &iev->ibuf;
3173d77879fSreyk 
3183d77879fSreyk 	/*
3193d77879fSreyk 	 * XXX this could be nicer...
3203d77879fSreyk 	 */
3213d77879fSreyk 
32285e5f500Sclaudio 	(void)strlcpy(cko.cko_hash, hash, sizeof(cko.cko_hash));
323325f6e14Sreyk 	cko.cko_proc = ps->ps_instance;
3243d77879fSreyk 	cko.cko_flen = flen;
3253d77879fSreyk 	cko.cko_tlen = RSA_size(rsa);
3263d77879fSreyk 	cko.cko_padding = padding;
327c7e61995Sclaudio 	cko.cko_cookie = seq++;
3283d77879fSreyk 
3293d77879fSreyk 	iov[cnt].iov_base = &cko;
3303d77879fSreyk 	iov[cnt++].iov_len = sizeof(cko);
331f9b0f55cSreyk 	iov[cnt].iov_base = (void *)(uintptr_t)from;
3323d77879fSreyk 	iov[cnt++].iov_len = flen;
3333d77879fSreyk 
3343d77879fSreyk 	/*
3353d77879fSreyk 	 * Send a synchronous imsg because we cannot defer the RSA
3363d77879fSreyk 	 * operation in OpenSSL's engine layer.
3373d77879fSreyk 	 */
3387084d095Sclaudio 	if (imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt) == -1)
3397084d095Sclaudio 		log_warn("%s: imsg_composev", __func__);
340dd7efffeSclaudio 	if (imsgbuf_flush(ibuf) == -1)
341dd7efffeSclaudio 		log_warn("%s: imsgbuf_flush", __func__);
3423d77879fSreyk 
3436778e0bdSclaudio 	pfd[0].fd = ibuf->fd;
3446778e0bdSclaudio 	pfd[0].events = POLLIN;
3453d77879fSreyk 	while (!done) {
3466778e0bdSclaudio 		switch (poll(pfd, 1, RELAY_TLS_PRIV_TIMEOUT)) {
3476778e0bdSclaudio 		case -1:
3485fa7fa1aSbenno 			if (errno != EINTR)
349efc39811Sbenno 				fatal("%s: poll", __func__);
3505fa7fa1aSbenno 			continue;
3516778e0bdSclaudio 		case 0:
352c7e61995Sclaudio 			log_warnx("%s: priv%s poll timeout, keyop #%x",
353c7e61995Sclaudio 			    __func__,
354c7e61995Sclaudio 			    cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
355c7e61995Sclaudio 			    cko.cko_cookie);
356ad3e8fb5Stb 			return -1;
3576778e0bdSclaudio 		default:
3586778e0bdSclaudio 			break;
3596778e0bdSclaudio 		}
360*668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
361dd7efffeSclaudio 			fatalx("imsgbuf_read");
3623d77879fSreyk 		if (n == 0)
3633d77879fSreyk 			fatalx("pipe closed");
3643d77879fSreyk 
3653d77879fSreyk 		while (!done) {
3663d77879fSreyk 			if ((n = imsg_get(ibuf, &imsg)) == -1)
3673d77879fSreyk 				fatalx("imsg_get error");
3683d77879fSreyk 			if (n == 0)
3693d77879fSreyk 				break;
3703d77879fSreyk 
3713d77879fSreyk 			IMSG_SIZE_CHECK(&imsg, (&cko));
3723d77879fSreyk 			memcpy(&cko, imsg.data, sizeof(cko));
3733d77879fSreyk 
374c7e61995Sclaudio 			/*
375c7e61995Sclaudio 			 * Due to earlier timed out requests, there may be
376c7e61995Sclaudio 			 * responses that need to be skipped.
377c7e61995Sclaudio 			 */
378c7e61995Sclaudio 			if (cko.cko_cookie != seq - 1) {
379c7e61995Sclaudio 				log_warnx(
380c7e61995Sclaudio 				    "%s: priv%s obsolete keyop #%x", __func__,
381c7e61995Sclaudio 				    cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
382c7e61995Sclaudio 				    cko.cko_cookie);
383c7e61995Sclaudio 				continue;
384c7e61995Sclaudio 			}
385c7e61995Sclaudio 
386c7e61995Sclaudio 			if (imsg.hdr.type != cmd)
387c7e61995Sclaudio 				fatalx("invalid response");
388c7e61995Sclaudio 
3893d77879fSreyk 			ret = cko.cko_tlen;
390e45fc33aSclaudio 			if (ret > 0) {
391e45fc33aSclaudio 				if (IMSG_DATA_SIZE(&imsg) !=
392e45fc33aSclaudio 				    (sizeof(cko) + ret))
393e45fc33aSclaudio 					fatalx("data size");
3943d77879fSreyk 				toptr = (u_char *)imsg.data + sizeof(cko);
3953d77879fSreyk 				memcpy(to, toptr, ret);
3963d77879fSreyk 			}
3973d77879fSreyk 			done = 1;
3983d77879fSreyk 
3993d77879fSreyk 			imsg_free(&imsg);
4003d77879fSreyk 		}
4013d77879fSreyk 	}
4023d77879fSreyk 	imsg_event_add(iev);
4033d77879fSreyk 
404ad3e8fb5Stb 	return ret;
4053d77879fSreyk }
4063d77879fSreyk 
4073d77879fSreyk int
4088b624d89Sreyk rsae_priv_enc(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
4093d77879fSreyk {
4103d77879fSreyk 	DPRINTF("%s:%d", __func__, __LINE__);
411ad3e8fb5Stb 	return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVENC);
4123d77879fSreyk }
4133d77879fSreyk 
4143d77879fSreyk int
4158b624d89Sreyk rsae_priv_dec(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
4163d77879fSreyk {
4173d77879fSreyk 	DPRINTF("%s:%d", __func__, __LINE__);
418ad3e8fb5Stb 	return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVDEC);
4193d77879fSreyk }
4203d77879fSreyk 
4211013dd2eSreyk void
4223d77879fSreyk ca_engine_init(struct relayd *x_env)
4233d77879fSreyk {
42427f65520Stb 	const char	*errstr;
4253d77879fSreyk 
4263d77879fSreyk 	if (env == NULL)
4273d77879fSreyk 		env = x_env;
4283d77879fSreyk 
4292c8c2287Sclaudio 	if (rsa_default != NULL)
4302c8c2287Sclaudio 		return;
4312c8c2287Sclaudio 
4321013dd2eSreyk 	if ((rsa_default = RSA_get_default_method()) == NULL) {
4331013dd2eSreyk 		errstr = "RSA_get_default_method";
4341013dd2eSreyk 		goto fail;
4351013dd2eSreyk 	}
43627f65520Stb 
43727f65520Stb 	if ((rsae_method = RSA_meth_dup(rsa_default)) == NULL) {
43827f65520Stb 		errstr = "RSA_meth_dup";
4391013dd2eSreyk 		goto fail;
4401013dd2eSreyk 	}
4411013dd2eSreyk 
44227f65520Stb 	RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc);
44327f65520Stb 	RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec);
4441013dd2eSreyk 
445ad3e8fb5Stb 	RSA_meth_set_flags(rsae_method,
446ad3e8fb5Stb 	    RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK);
447ad3e8fb5Stb 	RSA_meth_set0_app_data(rsae_method,
448ad3e8fb5Stb 	    RSA_meth_get0_app_data(rsa_default));
4493d77879fSreyk 
45027f65520Stb 	RSA_set_default_method(rsae_method);
4513d77879fSreyk 
4521013dd2eSreyk 	return;
4531013dd2eSreyk 
4541013dd2eSreyk  fail:
455ad3e8fb5Stb 	RSA_meth_free(rsae_method);
45685e5f500Sclaudio 	fatalx("%s: %s", __func__, errstr);
4573d77879fSreyk }
458