xref: /openbsd/usr.sbin/relayd/ca.c (revision 668e5ba9)
1 /*	$OpenBSD: ca.c,v 1.45 2024/11/21 13:21:34 claudio Exp $	*/
2 
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  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
22 
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <poll.h>
27 #include <imsg.h>
28 
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/engine.h>
35 
36 #include "relayd.h"
37 
38 void	 ca_init(struct privsep *, struct privsep_proc *p, void *);
39 void	 ca_launch(void);
40 
41 int	 ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
42 int	 ca_dispatch_relay(int, struct privsep_proc *, struct imsg *);
43 
44 int	 rsae_priv_enc(int, const u_char *, u_char *, RSA *, int);
45 int	 rsae_priv_dec(int, const u_char *, u_char *, RSA *, int);
46 
47 static struct relayd *env = NULL;
48 
49 static struct privsep_proc procs[] = {
50 	{ "parent",	PROC_PARENT,	ca_dispatch_parent },
51 	{ "relay",	PROC_RELAY,	ca_dispatch_relay },
52 };
53 
54 void
ca(struct privsep * ps,struct privsep_proc * p)55 ca(struct privsep *ps, struct privsep_proc *p)
56 {
57 	env = ps->ps_env;
58 
59 	proc_run(ps, p, procs, nitems(procs), ca_init, NULL);
60 }
61 
62 void
ca_init(struct privsep * ps,struct privsep_proc * p,void * arg)63 ca_init(struct privsep *ps, struct privsep_proc *p, void *arg)
64 {
65 	if (pledge("stdio recvfd", NULL) == -1)
66 		fatal("pledge");
67 
68 	if (config_init(ps->ps_env) == -1)
69 		fatal("failed to initialize configuration");
70 
71 	env->sc_id = getpid() & 0xffff;
72 }
73 
74 void
hash_x509(X509 * cert,char * hash,size_t hashlen)75 hash_x509(X509 *cert, char *hash, size_t hashlen)
76 {
77 	static const char	hex[] = "0123456789abcdef";
78 	size_t			off;
79 	char			digest[EVP_MAX_MD_SIZE];
80 	int			dlen, i;
81 
82 	if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
83 		fatalx("%s: X509_pubkey_digest failed", __func__);
84 
85 	if (hashlen < 2 * dlen + sizeof("SHA256:"))
86 		fatalx("%s: hash buffer too small", __func__);
87 
88 	off = strlcpy(hash, "SHA256:", hashlen);
89 
90 	for (i = 0; i < dlen; i++) {
91 		hash[off++] = hex[(digest[i] >> 4) & 0x0f];
92 		hash[off++] = hex[digest[i] & 0x0f];
93 	}
94 	hash[off] = 0;
95 }
96 
97 void
ca_launch(void)98 ca_launch(void)
99 {
100 	char			 hash[TLS_CERT_HASH_SIZE];
101 	char			*buf;
102 	BIO			*in = NULL;
103 	EVP_PKEY		*pkey = NULL;
104 	struct relay		*rlay;
105 	struct relay_cert	*cert;
106 	X509			*x509 = NULL;
107 	off_t			 len;
108 
109 	TAILQ_FOREACH(cert, env->sc_certs, cert_entry) {
110 		if (cert->cert_fd == -1 || cert->cert_key_fd == -1)
111 			continue;
112 
113 		if ((buf = relay_load_fd(cert->cert_fd, &len)) == NULL)
114 			fatal("ca_launch: cert relay_load_fd");
115 
116 		if ((in = BIO_new_mem_buf(buf, len)) == NULL)
117 			fatalx("ca_launch: cert BIO_new_mem_buf");
118 
119 		if ((x509 = PEM_read_bio_X509(in, NULL,
120 		    NULL, NULL)) == NULL)
121 			fatalx("ca_launch: cert PEM_read_bio_X509");
122 
123 		hash_x509(x509, hash, sizeof(hash));
124 
125 		BIO_free(in);
126 		X509_free(x509);
127 		purge_key(&buf, len);
128 
129 		if ((buf = relay_load_fd(cert->cert_key_fd, &len)) == NULL)
130 			fatal("ca_launch: key relay_load_fd");
131 
132 		if ((in = BIO_new_mem_buf(buf, len)) == NULL)
133 			fatalx("%s: key", __func__);
134 
135 		if ((pkey = PEM_read_bio_PrivateKey(in,
136 		    NULL, NULL, NULL)) == NULL)
137 			fatalx("%s: PEM", __func__);
138 
139 		cert->cert_pkey = pkey;
140 
141 		if (pkey_add(env, pkey, hash) == NULL)
142 			fatalx("tls pkey");
143 
144 		BIO_free(in);
145 		purge_key(&buf, len);
146 	}
147 
148 	TAILQ_FOREACH(rlay, env->sc_relays, rl_entry) {
149 		if ((rlay->rl_conf.flags & (F_TLS|F_TLSCLIENT)) == 0)
150 			continue;
151 
152 		if (rlay->rl_tls_cacert_fd != -1 &&
153 		    rlay->rl_conf.tls_cakey_len) {
154 			if ((buf = relay_load_fd(rlay->rl_tls_cacert_fd,
155 			    &len)) == NULL)
156 				fatal("ca_launch: cacert relay_load_fd");
157 
158 			if ((in = BIO_new_mem_buf(buf, len)) == NULL)
159 				fatalx("ca_launch: cacert BIO_new_mem_buf");
160 
161 			if ((x509 = PEM_read_bio_X509(in, NULL,
162 			    NULL, NULL)) == NULL)
163 				fatalx("ca_launch: cacert PEM_read_bio_X509");
164 
165 			hash_x509(x509, hash, sizeof(hash));
166 
167 			BIO_free(in);
168 			X509_free(x509);
169 			purge_key(&buf, len);
170 
171 			if ((in = BIO_new_mem_buf(rlay->rl_tls_cakey,
172 			    rlay->rl_conf.tls_cakey_len)) == NULL)
173 				fatalx("%s: key", __func__);
174 
175 			if ((pkey = PEM_read_bio_PrivateKey(in,
176 			    NULL, NULL, NULL)) == NULL)
177 				fatalx("%s: PEM", __func__);
178 			BIO_free(in);
179 
180 			rlay->rl_tls_capkey = pkey;
181 
182 			if (pkey_add(env, pkey, hash) == NULL)
183 				fatalx("ca pkey");
184 
185 			purge_key(&rlay->rl_tls_cakey,
186 			    rlay->rl_conf.tls_cakey_len);
187 		}
188 		close(rlay->rl_tls_ca_fd);
189 	}
190 }
191 
192 int
ca_dispatch_parent(int fd,struct privsep_proc * p,struct imsg * imsg)193 ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
194 {
195 	switch (imsg->hdr.type) {
196 	case IMSG_CFG_RELAY:
197 		config_getrelay(env, imsg);
198 		break;
199 	case IMSG_CFG_RELAY_FD:
200 		config_getrelayfd(env, imsg);
201 		break;
202 	case IMSG_CFG_DONE:
203 		config_getcfg(env, imsg);
204 		break;
205 	case IMSG_CTL_START:
206 		ca_launch();
207 		break;
208 	case IMSG_CTL_RESET:
209 		config_getreset(env, imsg);
210 		break;
211 	default:
212 		return -1;
213 	}
214 
215 	return 0;
216 }
217 
218 int
ca_dispatch_relay(int fd,struct privsep_proc * p,struct imsg * imsg)219 ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
220 {
221 	struct ctl_keyop	 cko;
222 	EVP_PKEY		*pkey;
223 	RSA			*rsa;
224 	u_char			*from = NULL, *to = NULL;
225 	struct iovec		 iov[2];
226 	int			 c = 0;
227 
228 	switch (imsg->hdr.type) {
229 	case IMSG_CA_PRIVENC:
230 	case IMSG_CA_PRIVDEC:
231 		IMSG_SIZE_CHECK(imsg, (&cko));
232 		bcopy(imsg->data, &cko, sizeof(cko));
233 		if (cko.cko_proc > env->sc_conf.prefork_relay)
234 			fatalx("%s: invalid relay proc", __func__);
235 		if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
236 			fatalx("%s: invalid key operation", __func__);
237 		if ((pkey = pkey_find(env, cko.cko_hash)) == NULL)
238 			fatalx("%s: invalid relay hash '%s'",
239 			    __func__, cko.cko_hash);
240 		if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
241 			fatalx("%s: invalid relay key", __func__);
242 
243 		DPRINTF("%s:%d: key hash %s proc %d",
244 		    __func__, __LINE__, cko.cko_hash, cko.cko_proc);
245 
246 		from = (u_char *)imsg->data + sizeof(cko);
247 		if ((to = calloc(1, cko.cko_tlen)) == NULL)
248 			fatalx("%s: calloc", __func__);
249 
250 		switch (imsg->hdr.type) {
251 		case IMSG_CA_PRIVENC:
252 			cko.cko_tlen = RSA_private_encrypt(cko.cko_flen,
253 			    from, to, rsa, cko.cko_padding);
254 			break;
255 		case IMSG_CA_PRIVDEC:
256 			cko.cko_tlen = RSA_private_decrypt(cko.cko_flen,
257 			    from, to, rsa, cko.cko_padding);
258 			break;
259 		}
260 
261 		if (cko.cko_tlen == -1) {
262 			char buf[256];
263 			log_warnx("%s: %s", __func__,
264 			    ERR_error_string(ERR_get_error(), buf));
265 		}
266 
267 		iov[c].iov_base = &cko;
268 		iov[c++].iov_len = sizeof(cko);
269 		if (cko.cko_tlen > 0) {
270 			iov[c].iov_base = to;
271 			iov[c++].iov_len = cko.cko_tlen;
272 		}
273 
274 		if (proc_composev_imsg(env->sc_ps, PROC_RELAY, cko.cko_proc,
275 		    imsg->hdr.type, -1, -1, iov, c) == -1)
276 			log_warn("%s: proc_composev_imsg", __func__);
277 
278 		free(to);
279 		RSA_free(rsa);
280 		break;
281 	default:
282 		return -1;
283 	}
284 
285 	return 0;
286 }
287 
288 /*
289  * RSA privsep engine (called from unprivileged processes)
290  */
291 
292 static const RSA_METHOD *rsa_default;
293 static RSA_METHOD *rsae_method;
294 
295 static int
rsae_send_imsg(int flen,const u_char * from,u_char * to,RSA * rsa,int padding,u_int cmd)296 rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa,
297     int padding, u_int cmd)
298 {
299 	struct privsep	*ps = env->sc_ps;
300 	struct pollfd	 pfd[1];
301 	struct ctl_keyop cko;
302 	int		 ret = 0;
303 	char		*hash;
304 	struct iovec	 iov[2];
305 	struct imsgbuf	*ibuf;
306 	struct imsgev	*iev;
307 	struct imsg	 imsg;
308 	int		 n, done = 0, cnt = 0;
309 	u_char		*toptr;
310 	static u_int	 seq = 0;
311 
312 	if ((hash = RSA_get_ex_data(rsa, 0)) == NULL)
313 		return 0;
314 
315 	iev = proc_iev(ps, PROC_CA, ps->ps_instance);
316 	ibuf = &iev->ibuf;
317 
318 	/*
319 	 * XXX this could be nicer...
320 	 */
321 
322 	(void)strlcpy(cko.cko_hash, hash, sizeof(cko.cko_hash));
323 	cko.cko_proc = ps->ps_instance;
324 	cko.cko_flen = flen;
325 	cko.cko_tlen = RSA_size(rsa);
326 	cko.cko_padding = padding;
327 	cko.cko_cookie = seq++;
328 
329 	iov[cnt].iov_base = &cko;
330 	iov[cnt++].iov_len = sizeof(cko);
331 	iov[cnt].iov_base = (void *)(uintptr_t)from;
332 	iov[cnt++].iov_len = flen;
333 
334 	/*
335 	 * Send a synchronous imsg because we cannot defer the RSA
336 	 * operation in OpenSSL's engine layer.
337 	 */
338 	if (imsg_composev(ibuf, cmd, 0, 0, -1, iov, cnt) == -1)
339 		log_warn("%s: imsg_composev", __func__);
340 	if (imsgbuf_flush(ibuf) == -1)
341 		log_warn("%s: imsgbuf_flush", __func__);
342 
343 	pfd[0].fd = ibuf->fd;
344 	pfd[0].events = POLLIN;
345 	while (!done) {
346 		switch (poll(pfd, 1, RELAY_TLS_PRIV_TIMEOUT)) {
347 		case -1:
348 			if (errno != EINTR)
349 				fatal("%s: poll", __func__);
350 			continue;
351 		case 0:
352 			log_warnx("%s: priv%s poll timeout, keyop #%x",
353 			    __func__,
354 			    cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
355 			    cko.cko_cookie);
356 			return -1;
357 		default:
358 			break;
359 		}
360 		if ((n = imsgbuf_read(ibuf)) == -1)
361 			fatalx("imsgbuf_read");
362 		if (n == 0)
363 			fatalx("pipe closed");
364 
365 		while (!done) {
366 			if ((n = imsg_get(ibuf, &imsg)) == -1)
367 				fatalx("imsg_get error");
368 			if (n == 0)
369 				break;
370 
371 			IMSG_SIZE_CHECK(&imsg, (&cko));
372 			memcpy(&cko, imsg.data, sizeof(cko));
373 
374 			/*
375 			 * Due to earlier timed out requests, there may be
376 			 * responses that need to be skipped.
377 			 */
378 			if (cko.cko_cookie != seq - 1) {
379 				log_warnx(
380 				    "%s: priv%s obsolete keyop #%x", __func__,
381 				    cmd == IMSG_CA_PRIVENC ? "enc" : "dec",
382 				    cko.cko_cookie);
383 				continue;
384 			}
385 
386 			if (imsg.hdr.type != cmd)
387 				fatalx("invalid response");
388 
389 			ret = cko.cko_tlen;
390 			if (ret > 0) {
391 				if (IMSG_DATA_SIZE(&imsg) !=
392 				    (sizeof(cko) + ret))
393 					fatalx("data size");
394 				toptr = (u_char *)imsg.data + sizeof(cko);
395 				memcpy(to, toptr, ret);
396 			}
397 			done = 1;
398 
399 			imsg_free(&imsg);
400 		}
401 	}
402 	imsg_event_add(iev);
403 
404 	return ret;
405 }
406 
407 int
rsae_priv_enc(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)408 rsae_priv_enc(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
409 {
410 	DPRINTF("%s:%d", __func__, __LINE__);
411 	return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVENC);
412 }
413 
414 int
rsae_priv_dec(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)415 rsae_priv_dec(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
416 {
417 	DPRINTF("%s:%d", __func__, __LINE__);
418 	return rsae_send_imsg(flen, from, to, rsa, padding, IMSG_CA_PRIVDEC);
419 }
420 
421 void
ca_engine_init(struct relayd * x_env)422 ca_engine_init(struct relayd *x_env)
423 {
424 	const char	*errstr;
425 
426 	if (env == NULL)
427 		env = x_env;
428 
429 	if (rsa_default != NULL)
430 		return;
431 
432 	if ((rsa_default = RSA_get_default_method()) == NULL) {
433 		errstr = "RSA_get_default_method";
434 		goto fail;
435 	}
436 
437 	if ((rsae_method = RSA_meth_dup(rsa_default)) == NULL) {
438 		errstr = "RSA_meth_dup";
439 		goto fail;
440 	}
441 
442 	RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc);
443 	RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec);
444 
445 	RSA_meth_set_flags(rsae_method,
446 	    RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK);
447 	RSA_meth_set0_app_data(rsae_method,
448 	    RSA_meth_get0_app_data(rsa_default));
449 
450 	RSA_set_default_method(rsae_method);
451 
452 	return;
453 
454  fail:
455 	RSA_meth_free(rsae_method);
456 	fatalx("%s: %s", __func__, errstr);
457 }
458