xref: /openbsd/usr.sbin/rpki-client/filemode.c (revision 39b34cbd)
1 /*	$OpenBSD: filemode.c,v 1.57 2024/12/16 13:53:37 tb Exp $ */
2 /*
3  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
4  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
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/queue.h>
20 #include <sys/tree.h>
21 #include <sys/types.h>
22 
23 #include <assert.h>
24 #include <err.h>
25 #include <fcntl.h>
26 #include <poll.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <unistd.h>
32 #include <imsg.h>
33 
34 #include <openssl/asn1.h>
35 #include <openssl/err.h>
36 #include <openssl/evp.h>
37 #include <openssl/pem.h>
38 #include <openssl/x509.h>
39 #include <openssl/x509v3.h>
40 
41 #include "extern.h"
42 #include "json.h"
43 
44 extern BN_CTX		*bn_ctx;
45 
46 static X509_STORE_CTX	*ctx;
47 static struct auth_tree	 auths = RB_INITIALIZER(&auths);
48 static struct crl_tree	 crlt = RB_INITIALIZER(&crlt);
49 
50 struct tal		*talobj[TALSZ_MAX];
51 
52 struct uripath {
53 	RB_ENTRY(uripath)	 entry;
54 	const char		*uri;
55 	struct cert		*cert;
56 };
57 
58 static RB_HEAD(uripath_tree, uripath) uritree;
59 
60 static inline int
uripathcmp(const struct uripath * a,const struct uripath * b)61 uripathcmp(const struct uripath *a, const struct uripath *b)
62 {
63 	return strcmp(a->uri, b->uri);
64 }
65 
66 RB_PROTOTYPE(uripath_tree, uripath, entry, uripathcmp);
67 
68 static void
uripath_add(const char * uri,struct cert * cert)69 uripath_add(const char *uri, struct cert *cert)
70 {
71 	struct uripath *up;
72 
73 	if ((up = calloc(1, sizeof(*up))) == NULL)
74 		err(1, NULL);
75 	if ((up->uri = strdup(uri)) == NULL)
76 		err(1, NULL);
77 	up->cert = cert;
78 	if (RB_INSERT(uripath_tree, &uritree, up) != NULL)
79 		errx(1, "corrupt AIA lookup tree");
80 }
81 
82 static struct cert *
uripath_lookup(const char * uri)83 uripath_lookup(const char *uri)
84 {
85 	struct uripath needle = { .uri = uri };
86 	struct uripath *up;
87 
88 	up = RB_FIND(uripath_tree, &uritree, &needle);
89 	if (up == NULL)
90 		return NULL;
91 	return up->cert;
92 }
93 
94 RB_GENERATE(uripath_tree, uripath, entry, uripathcmp);
95 
96 /*
97  * Use the X509 CRL Distribution Points to locate the CRL needed for
98  * verification.
99  */
100 static void
parse_load_crl(char * uri)101 parse_load_crl(char *uri)
102 {
103 	struct crl *crl;
104 	char *f;
105 	size_t flen;
106 
107 	if (uri == NULL)
108 		return;
109 	if (strncmp(uri, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) {
110 		warnx("bad CRL distribution point URI %s", uri);
111 		return;
112 	}
113 	uri += RSYNC_PROTO_LEN;
114 
115 	f = load_file(uri, &flen);
116 	if (f == NULL) {
117 		warn("parse file %s", uri);
118 		return;
119 	}
120 
121 	crl = crl_parse(uri, f, flen);
122 	if (crl != NULL && !crl_insert(&crlt, crl))
123 		crl_free(crl);
124 
125 	free(f);
126 }
127 
128 /*
129  * Parse the cert pointed at by the AIA URI while doing that also load
130  * the CRL of this cert. While the CRL is validated the returned cert
131  * is not. The caller needs to make sure it is validated once all
132  * necessary certs were loaded. Returns NULL on failure.
133  */
134 static struct cert *
parse_load_cert(char * uri)135 parse_load_cert(char *uri)
136 {
137 	struct cert *cert = NULL;
138 	char *f;
139 	size_t flen;
140 
141 	if (uri == NULL)
142 		return NULL;
143 
144 	if (strncmp(uri, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) {
145 		warnx("bad authority information access URI %s", uri);
146 		return NULL;
147 	}
148 	uri += RSYNC_PROTO_LEN;
149 
150 	f = load_file(uri, &flen);
151 	if (f == NULL) {
152 		warn("parse file %s", uri);
153 		goto done;
154 	}
155 
156 	cert = cert_parse_pre(uri, f, flen);
157 	free(f);
158 
159 	if (cert == NULL)
160 		goto done;
161 	if (cert->purpose != CERT_PURPOSE_CA) {
162 		warnx("AIA reference to %s in %s",
163 		    purpose2str(cert->purpose), uri);
164 		goto done;
165 	}
166 	/* try to load the CRL of this cert */
167 	parse_load_crl(cert->crl);
168 
169 	return cert;
170 
171  done:
172 	cert_free(cert);
173 	return NULL;
174 }
175 
176 /*
177  * Build the certificate chain by using the Authority Information Access.
178  * This requires that the TA are already validated and added to the auths
179  * tree. Once the TA is located in the chain the chain is validated in
180  * reverse order.
181  */
182 static struct auth *
parse_load_certchain(char * uri)183 parse_load_certchain(char *uri)
184 {
185 	struct cert *stack[MAX_CERT_DEPTH] = { 0 };
186 	char *filestack[MAX_CERT_DEPTH];
187 	struct cert *cert;
188 	struct crl *crl;
189 	struct auth *a;
190 	const char *errstr;
191 	int i;
192 
193 	for (i = 0; i < MAX_CERT_DEPTH; i++) {
194 		if ((cert = uripath_lookup(uri)) != NULL) {
195 			a = auth_find(&auths, cert->certid);
196 			if (a == NULL) {
197 				warnx("failed to find issuer for %s", uri);
198 				goto fail;
199 			}
200 			break;
201 		}
202 		filestack[i] = uri;
203 		stack[i] = cert = parse_load_cert(uri);
204 		if (cert == NULL || cert->purpose != CERT_PURPOSE_CA) {
205 			warnx("failed to build authority chain: %s", uri);
206 			goto fail;
207 		}
208 		uri = cert->aia;
209 	}
210 
211 	if (i >= MAX_CERT_DEPTH) {
212 		warnx("authority chain exceeds max depth of %d",
213 		    MAX_CERT_DEPTH);
214 		goto fail;
215 	}
216 
217 	/* TA found play back the stack and add all certs */
218 	for (; i > 0; i--) {
219 		cert = stack[i - 1];
220 		uri = filestack[i - 1];
221 
222 		crl = crl_get(&crlt, a);
223 		if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) ||
224 		    !valid_cert(uri, a, cert)) {
225 			if (errstr != NULL)
226 				warnx("%s: %s", uri, errstr);
227 			goto fail;
228 		}
229 		cert->talid = a->cert->talid;
230 		a = auth_insert(uri, &auths, cert, a);
231 		uripath_add(uri, cert);
232 		stack[i - 1] = NULL;
233 	}
234 
235 	return a;
236 fail:
237 	for (i = 0; i < MAX_CERT_DEPTH; i++)
238 		cert_free(stack[i]);
239 	return NULL;
240 }
241 
242 static void
parse_load_ta(struct tal * tal)243 parse_load_ta(struct tal *tal)
244 {
245 	const char *filename;
246 	struct cert *cert;
247 	unsigned char *f = NULL;
248 	char *file;
249 	size_t flen, i;
250 
251 	/* does not matter which URI, all end with same filename */
252 	filename = strrchr(tal->uri[0], '/');
253 	assert(filename);
254 
255 	if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1)
256 		err(1, NULL);
257 
258 	f = load_file(file, &flen);
259 	if (f == NULL) {
260 		warn("parse file %s", file);
261 		goto out;
262 	}
263 
264 	/* Extract certificate data. */
265 	cert = cert_parse_pre(file, f, flen);
266 	cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
267 	if (cert == NULL)
268 		goto out;
269 
270 	cert->talid = tal->id;
271 	auth_insert(file, &auths, cert, NULL);
272 	for (i = 0; i < tal->num_uris; i++) {
273 		if (strncasecmp(tal->uri[i], RSYNC_PROTO, RSYNC_PROTO_LEN) != 0)
274 			continue;
275 		/* Add all rsync uri since any of them could be used as AIA. */
276 		uripath_add(tal->uri[i], cert);
277 	}
278 
279 out:
280 	free(file);
281 	free(f);
282 }
283 
284 static struct tal *
find_tal(struct cert * cert)285 find_tal(struct cert *cert)
286 {
287 	EVP_PKEY	*pk, *opk;
288 	struct tal	*tal;
289 	int		 i;
290 
291 	if ((opk = X509_get0_pubkey(cert->x509)) == NULL)
292 		return NULL;
293 
294 	for (i = 0; i < TALSZ_MAX; i++) {
295 		const unsigned char *pkey;
296 
297 		if (talobj[i] == NULL)
298 			break;
299 		tal = talobj[i];
300 		pkey = tal->pkey;
301 		pk = d2i_PUBKEY(NULL, &pkey, tal->pkeysz);
302 		if (pk == NULL)
303 			continue;
304 		if (EVP_PKEY_cmp(pk, opk) == 1) {
305 			EVP_PKEY_free(pk);
306 			return tal;
307 		}
308 		EVP_PKEY_free(pk);
309 	}
310 	return NULL;
311 }
312 
313 static void
print_signature_path(const char * crl,const char * aia,const struct auth * a)314 print_signature_path(const char *crl, const char *aia, const struct auth *a)
315 {
316 	if (crl != NULL)
317 		printf("Signature path:           %s\n", crl);
318 	if (a != NULL && a->cert != NULL && a->cert->mft != NULL)
319 		printf("                          %s\n", a->cert->mft);
320 	if (aia != NULL)
321 		printf("                          %s\n", aia);
322 
323 	for (; a != NULL; a = a->issuer) {
324 		if (a->cert->crl != NULL)
325 			printf("                          %s\n", a->cert->crl);
326 		if (a->issuer != NULL && a->issuer->cert != NULL &&
327 		    a->issuer->cert->mft != NULL)
328 			printf("                          %s\n",
329 			    a->issuer->cert->mft);
330 		if (a->cert->aia != NULL)
331 			printf("                          %s\n", a->cert->aia);
332 	}
333 }
334 
335 /*
336  * Parse file passed with -f option.
337  */
338 static void
proc_parser_file(char * file,unsigned char * buf,size_t len)339 proc_parser_file(char *file, unsigned char *buf, size_t len)
340 {
341 	static int num;
342 	X509 *x509 = NULL;
343 	struct aspa *aspa = NULL;
344 	struct cert *cert = NULL;
345 	struct crl *crl = NULL;
346 	struct gbr *gbr = NULL;
347 	struct geofeed *geofeed = NULL;
348 	struct mft *mft = NULL;
349 	struct roa *roa = NULL;
350 	struct rsc *rsc = NULL;
351 	struct spl *spl = NULL;
352 	struct tak *tak = NULL;
353 	struct tal *tal = NULL;
354 	char *aia = NULL;
355 	char *crl_uri = NULL;
356 	time_t *notbefore = NULL, *expires = NULL, *notafter = NULL;
357 	time_t now;
358 	struct auth *a = NULL;
359 	struct crl *c;
360 	const char *errstr = NULL, *valid;
361 	int status = 0;
362 	char filehash[SHA256_DIGEST_LENGTH];
363 	char *hash;
364 	enum rtype type;
365 	int is_ta = 0;
366 
367 	now = get_current_time();
368 
369 	if (outformats & FORMAT_JSON) {
370 		json_do_start(stdout);
371 	} else {
372 		if (num++ > 0)
373 			printf("--\n");
374 	}
375 
376 	if (strncmp(file, RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) {
377 		file += RSYNC_PROTO_LEN;
378 		buf = load_file(file, &len);
379 		if (buf == NULL) {
380 			warn("parse file %s", file);
381 			return;
382 		}
383 	}
384 
385 	if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
386 		errx(1, "EVP_Digest failed in %s", __func__);
387 
388 	if (base64_encode(filehash, sizeof(filehash), &hash) == -1)
389 		errx(1, "base64_encode failed in %s", __func__);
390 
391 	if (outformats & FORMAT_JSON) {
392 		json_do_string("file", file);
393 		json_do_string("hash_id", hash);
394 	} else {
395 		printf("File:                     %s\n", file);
396 		printf("Hash identifier:          %s\n", hash);
397 	}
398 
399 	free(hash);
400 
401 	type = rtype_from_file_extension(file);
402 
403 	switch (type) {
404 	case RTYPE_ASPA:
405 		aspa = aspa_parse(&x509, file, -1, buf, len);
406 		if (aspa == NULL)
407 			break;
408 		aia = aspa->aia;
409 		expires = &aspa->expires;
410 		notbefore = &aspa->notbefore;
411 		notafter = &aspa->notafter;
412 		break;
413 	case RTYPE_CER:
414 		cert = cert_parse_pre(file, buf, len);
415 		if (cert == NULL)
416 			break;
417 		is_ta = (cert->purpose == CERT_PURPOSE_TA);
418 		if (!is_ta)
419 			cert = cert_parse(file, cert);
420 		if (cert == NULL)
421 			break;
422 		aia = cert->aia;
423 		x509 = cert->x509;
424 		if (X509_up_ref(x509) == 0)
425 			errx(1, "%s: X509_up_ref failed", __func__);
426 		expires = &cert->expires;
427 		notbefore = &cert->notbefore;
428 		notafter = &cert->notafter;
429 		break;
430 	case RTYPE_CRL:
431 		crl = crl_parse(file, buf, len);
432 		if (crl == NULL)
433 			break;
434 		crl_print(crl);
435 		break;
436 	case RTYPE_MFT:
437 		mft = mft_parse(&x509, file, -1, buf, len);
438 		if (mft == NULL)
439 			break;
440 		aia = mft->aia;
441 		expires = &mft->expires;
442 		notbefore = &mft->thisupdate;
443 		notafter = &mft->nextupdate;
444 		break;
445 	case RTYPE_GBR:
446 		gbr = gbr_parse(&x509, file, -1, buf, len);
447 		if (gbr == NULL)
448 			break;
449 		aia = gbr->aia;
450 		expires = &gbr->expires;
451 		notbefore = &gbr->notbefore;
452 		notafter = &gbr->notafter;
453 		break;
454 	case RTYPE_GEOFEED:
455 		geofeed = geofeed_parse(&x509, file, -1, buf, len);
456 		if (geofeed == NULL)
457 			break;
458 		aia = geofeed->aia;
459 		expires = &geofeed->expires;
460 		notbefore = &geofeed->notbefore;
461 		notafter = &geofeed->notafter;
462 		break;
463 	case RTYPE_ROA:
464 		roa = roa_parse(&x509, file, -1, buf, len);
465 		if (roa == NULL)
466 			break;
467 		aia = roa->aia;
468 		expires = &roa->expires;
469 		notbefore = &roa->notbefore;
470 		notafter = &roa->notafter;
471 		break;
472 	case RTYPE_RSC:
473 		rsc = rsc_parse(&x509, file, -1, buf, len);
474 		if (rsc == NULL)
475 			break;
476 		aia = rsc->aia;
477 		expires = &rsc->expires;
478 		notbefore = &rsc->notbefore;
479 		notafter = &rsc->notafter;
480 		break;
481 	case RTYPE_SPL:
482 		spl = spl_parse(&x509, file, -1, buf, len);
483 		if (spl == NULL)
484 			break;
485 		aia = spl->aia;
486 		expires = &spl->expires;
487 		notbefore = &spl->notbefore;
488 		notafter = &spl->notafter;
489 		break;
490 	case RTYPE_TAK:
491 		tak = tak_parse(&x509, file, -1, buf, len);
492 		if (tak == NULL)
493 			break;
494 		aia = tak->aia;
495 		expires = &tak->expires;
496 		notbefore = &tak->notbefore;
497 		notafter = &tak->notafter;
498 		break;
499 	case RTYPE_TAL:
500 		tal = tal_parse(file, buf, len);
501 		if (tal == NULL)
502 			break;
503 		tal_print(tal);
504 		break;
505 	default:
506 		printf("%s: unsupported file type\n", file);
507 		break;
508 	}
509 
510 	if (aia != NULL) {
511 		x509_get_crl(x509, file, &crl_uri);
512 		parse_load_crl(crl_uri);
513 		a = parse_load_certchain(aia);
514 		c = crl_get(&crlt, a);
515 
516 		if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) {
517 			switch (type) {
518 			case RTYPE_ASPA:
519 				status = aspa->valid;
520 				break;
521 			case RTYPE_GEOFEED:
522 				status = geofeed->valid;
523 				break;
524 			case RTYPE_ROA:
525 				status = roa->valid;
526 				break;
527 			case RTYPE_RSC:
528 				status = rsc->valid;
529 				break;
530 			case RTYPE_SPL:
531 				status = spl->valid;
532 			default:
533 				break;
534 			}
535 		}
536 		if (status && cert == NULL) {
537 			struct cert *eecert;
538 
539 			eecert = cert_parse_ee_cert(file, a->cert->talid, x509);
540 			if (eecert == NULL)
541 				status = 0;
542 			cert_free(eecert);
543 		} else if (status) {
544 			cert->talid = a->cert->talid;
545 			constraints_validate(file, cert);
546 		}
547 	} else if (is_ta) {
548 		expires = NULL;
549 		notafter = NULL;
550 		if ((tal = find_tal(cert)) != NULL) {
551 			cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
552 			status = (cert != NULL);
553 			if (status) {
554 				expires = &cert->expires;
555 				notafter = &cert->notafter;
556 			}
557 			if (outformats & FORMAT_JSON)
558 				json_do_string("tal", tal->descr);
559 			else
560 				printf("TAL:                      %s\n",
561 				    tal->descr);
562 			tal = NULL;
563 		} else {
564 			cert_free(cert);
565 			cert = NULL;
566 			status = 0;
567 		}
568 	}
569 
570 	if (expires != NULL) {
571 		if ((status && aia != NULL) || is_ta)
572 			*expires = x509_find_expires(*notafter, a, &crlt);
573 
574 		switch (type) {
575 		case RTYPE_ASPA:
576 			aspa_print(x509, aspa);
577 			break;
578 		case RTYPE_CER:
579 			cert_print(cert);
580 			break;
581 		case RTYPE_GBR:
582 			gbr_print(x509, gbr);
583 			break;
584 		case RTYPE_GEOFEED:
585 			geofeed_print(x509, geofeed);
586 			break;
587 		case RTYPE_MFT:
588 			mft_print(x509, mft);
589 			break;
590 		case RTYPE_ROA:
591 			roa_print(x509, roa);
592 			break;
593 		case RTYPE_RSC:
594 			rsc_print(x509, rsc);
595 			break;
596 		case RTYPE_SPL:
597 			spl_print(x509, spl);
598 			break;
599 		case RTYPE_TAK:
600 			tak_print(x509, tak);
601 			break;
602 		default:
603 			break;
604 		}
605 	}
606 
607 	if (status) {
608 		if (notbefore != NULL && *notbefore > now)
609 			valid = "Not yet valid";
610 		else if (notafter != NULL && *notafter < now)
611 			valid = "Expired";
612 		else if (expires != NULL && *expires < now)
613 			valid = "Signature path expired";
614 		else
615 			valid = "OK";
616 	} else if (aia == NULL)
617 		valid = "N/A";
618 	else
619 		valid = "Failed";
620 
621 	if (outformats & FORMAT_JSON) {
622 		json_do_string("validation", valid);
623 		if (errstr != NULL)
624 			json_do_string("error", errstr);
625 	} else {
626 		printf("Validation:               %s", valid);
627 		if (errstr != NULL)
628 			printf(", %s", errstr);
629 	}
630 
631 	if (outformats & FORMAT_JSON)
632 		json_do_finish();
633 	else {
634 		printf("\n");
635 
636 		if (aia != NULL && status) {
637 			print_signature_path(crl_uri, aia, a);
638 			if (expires != NULL)
639 				printf("Signature path expires:   %s\n",
640 				    time2str(*expires));
641 		}
642 
643 		if (x509 == NULL)
644 			goto out;
645 		if (type == RTYPE_TAL || type == RTYPE_CRL)
646 			goto out;
647 
648 		if (verbose) {
649 			if (!X509_print_fp(stdout, x509))
650 				errx(1, "X509_print_fp");
651 		}
652 
653 		if (verbose > 1) {
654 			if (!PEM_write_X509(stdout, x509))
655 				errx(1, "PEM_write_X509");
656 		}
657 	}
658 
659  out:
660 	free(crl_uri);
661 	X509_free(x509);
662 	aspa_free(aspa);
663 	cert_free(cert);
664 	crl_free(crl);
665 	gbr_free(gbr);
666 	geofeed_free(geofeed);
667 	mft_free(mft);
668 	roa_free(roa);
669 	rsc_free(rsc);
670 	tak_free(tak);
671 	tal_free(tal);
672 }
673 
674 /*
675  * Process a file request, in general don't send anything back.
676  */
677 static void
parse_file(struct entityq * q,struct msgbuf * msgq)678 parse_file(struct entityq *q, struct msgbuf *msgq)
679 {
680 	struct entity	*entp;
681 	struct ibuf	*b;
682 	struct tal	*tal;
683 	time_t		 dummy = 0;
684 
685 	while ((entp = TAILQ_FIRST(q)) != NULL) {
686 		TAILQ_REMOVE(q, entp, entries);
687 
688 		switch (entp->type) {
689 		case RTYPE_FILE:
690 			proc_parser_file(entp->file, entp->data, entp->datasz);
691 			break;
692 		case RTYPE_TAL:
693 			if ((tal = tal_parse(entp->file, entp->data,
694 			    entp->datasz)) == NULL)
695 				errx(1, "%s: could not parse tal file",
696 				    entp->file);
697 			tal->id = entp->talid;
698 			talobj[tal->id] = tal;
699 			parse_load_ta(tal);
700 			break;
701 		default:
702 			errx(1, "unhandled entity type %d", entp->type);
703 		}
704 
705 		b = io_new_buffer();
706 		io_simple_buffer(b, &entp->type, sizeof(entp->type));
707 		io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
708 		io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
709 		io_str_buffer(b, entp->file);
710 		io_simple_buffer(b, &dummy, sizeof(dummy));
711 		io_close_buffer(msgq, b);
712 		entity_free(entp);
713 	}
714 }
715 
716 /*
717  * Process responsible for parsing and validating content.
718  * All this process does is wait to be told about a file to parse, then
719  * it parses it and makes sure that the data being returned is fully
720  * validated and verified.
721  * The process will exit cleanly only when fd is closed.
722  */
723 void
proc_filemode(int fd)724 proc_filemode(int fd)
725 {
726 	struct entityq	 q;
727 	struct pollfd	 pfd;
728 	struct msgbuf	*msgq;
729 	struct entity	*entp;
730 	struct ibuf	*b, *inbuf = NULL;
731 
732 	/* Only allow access to the cache directory. */
733 	if (unveil(".", "r") == -1)
734 		err(1, "unveil cachedir");
735 	if (pledge("stdio rpath", NULL) == -1)
736 		err(1, "pledge");
737 
738 	ERR_load_crypto_strings();
739 	OpenSSL_add_all_ciphers();
740 	OpenSSL_add_all_digests();
741 	x509_init_oid();
742 	constraints_parse();
743 
744 	if ((ctx = X509_STORE_CTX_new()) == NULL)
745 		err(1, "X509_STORE_CTX_new");
746 	if ((bn_ctx = BN_CTX_new()) == NULL)
747 		err(1, "BN_CTX_new");
748 
749 	TAILQ_INIT(&q);
750 
751 	if ((msgq = msgbuf_new_reader(sizeof(size_t), io_parse_hdr, NULL)) ==
752 	    NULL)
753 		err(1, NULL);
754 	pfd.fd = fd;
755 
756 	for (;;) {
757 		pfd.events = POLLIN;
758 		if (msgbuf_queuelen(msgq) > 0)
759 			pfd.events |= POLLOUT;
760 
761 		if (poll(&pfd, 1, INFTIM) == -1) {
762 			if (errno == EINTR)
763 				continue;
764 			err(1, "poll");
765 		}
766 		if ((pfd.revents & (POLLERR|POLLNVAL)))
767 			errx(1, "poll: bad descriptor");
768 
769 		/* If the parent closes, return immediately. */
770 
771 		if ((pfd.revents & POLLHUP))
772 			break;
773 
774 		if ((pfd.revents & POLLIN)) {
775 			switch (ibuf_read(fd, msgq)) {
776 			case -1:
777 				err(1, "ibuf_read");
778 			case 0:
779 				errx(1, "ibuf_read: connection closed");
780 			}
781 			while ((b = io_buf_get(msgq)) != NULL) {
782 				entp = calloc(1, sizeof(struct entity));
783 				if (entp == NULL)
784 					err(1, NULL);
785 				entity_read_req(b, entp);
786 				TAILQ_INSERT_TAIL(&q, entp, entries);
787 				ibuf_free(b);
788 			}
789 		}
790 
791 		if (pfd.revents & POLLOUT) {
792 			if (msgbuf_write(fd, msgq) == -1) {
793 				if (errno == EPIPE)
794 					errx(1, "write: connection closed");
795 				else
796 					err(1, "write");
797 			}
798 		}
799 
800 		parse_file(&q, msgq);
801 	}
802 
803 	msgbuf_free(msgq);
804 	while ((entp = TAILQ_FIRST(&q)) != NULL) {
805 		TAILQ_REMOVE(&q, entp, entries);
806 		entity_free(entp);
807 	}
808 
809 	auth_tree_free(&auths);
810 	crl_tree_free(&crlt);
811 
812 	X509_STORE_CTX_free(ctx);
813 	BN_CTX_free(bn_ctx);
814 
815 	ibuf_free(inbuf);
816 
817 	exit(0);
818 }
819