xref: /openbsd/usr.sbin/rpki-client/parser.c (revision 379777c0)
1 /*	$OpenBSD: parser.c,v 1.100 2023/10/13 12:06:49 job 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 <err.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <unistd.h>
31 #include <imsg.h>
32 
33 #include <openssl/asn1.h>
34 #include <openssl/err.h>
35 #include <openssl/evp.h>
36 #include <openssl/x509.h>
37 #include <openssl/x509v3.h>
38 
39 #include "extern.h"
40 
41 static X509_STORE_CTX	*ctx;
42 static struct auth_tree	 auths = RB_INITIALIZER(&auths);
43 static struct crl_tree	 crlt = RB_INITIALIZER(&crlt);
44 
45 struct parse_repo {
46 	RB_ENTRY(parse_repo)	 entry;
47 	char			*path;
48 	char			*validpath;
49 	unsigned int		 id;
50 };
51 
52 static RB_HEAD(repo_tree, parse_repo)	repos = RB_INITIALIZER(&repos);
53 
54 static inline int
55 repocmp(struct parse_repo *a, struct parse_repo *b)
56 {
57 	return a->id - b->id;
58 }
59 
60 RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp);
61 
62 static struct parse_repo *
63 repo_get(unsigned int id)
64 {
65 	struct parse_repo needle = { .id = id };
66 
67 	return RB_FIND(repo_tree, &repos, &needle);
68 }
69 
70 static void
71 repo_add(unsigned int id, char *path, char *validpath)
72 {
73 	struct parse_repo *rp;
74 
75 	if ((rp = calloc(1, sizeof(*rp))) == NULL)
76 		err(1, NULL);
77 	rp->id = id;
78 	if (path != NULL)
79 		if ((rp->path = strdup(path)) == NULL)
80 			err(1, NULL);
81 	if (validpath != NULL)
82 		if ((rp->validpath = strdup(validpath)) == NULL)
83 			err(1, NULL);
84 
85 	if (RB_INSERT(repo_tree, &repos, rp) != NULL)
86 		errx(1, "repository already added: id %d, %s", id, path);
87 }
88 
89 /*
90  * Build access path to file based on repoid, path, location and file values.
91  */
92 static char *
93 parse_filepath(unsigned int repoid, const char *path, const char *file,
94     enum location loc)
95 {
96 	struct parse_repo	*rp;
97 	char			*fn, *repopath;
98 
99 	/* build file path based on repoid, entity path and filename */
100 	rp = repo_get(repoid);
101 	if (rp == NULL)
102 		errx(1, "build file path: repository %u missing", repoid);
103 
104 	if (loc == DIR_VALID)
105 		repopath = rp->validpath;
106 	else
107 		repopath = rp->path;
108 
109 	if (repopath == NULL)
110 		return NULL;
111 
112 	if (path == NULL) {
113 		if (asprintf(&fn, "%s/%s", repopath, file) == -1)
114 			err(1, NULL);
115 	} else {
116 		if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1)
117 			err(1, NULL);
118 	}
119 	return fn;
120 }
121 
122 /*
123  * Parse and validate a ROA.
124  * This is standard stuff.
125  * Returns the roa on success, NULL on failure.
126  */
127 static struct roa *
128 proc_parser_roa(char *file, const unsigned char *der, size_t len,
129     const struct entity *entp)
130 {
131 	struct roa		*roa;
132 	struct auth		*a;
133 	struct crl		*crl;
134 	X509			*x509;
135 	const char		*errstr;
136 
137 	if ((roa = roa_parse(&x509, file, entp->talid, der, len)) == NULL)
138 		return NULL;
139 
140 	a = valid_ski_aki(file, &auths, roa->ski, roa->aki, entp->mftaki);
141 	crl = crl_get(&crlt, a);
142 
143 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
144 		warnx("%s: %s", file, errstr);
145 		X509_free(x509);
146 		roa_free(roa);
147 		return NULL;
148 	}
149 	X509_free(x509);
150 
151 	roa->talid = a->cert->talid;
152 
153 	roa->expires = x509_find_expires(roa->notafter, a, &crlt);
154 
155 	return roa;
156 }
157 
158 /*
159  * Check all files and their hashes in a MFT structure.
160  * Return zero on failure, non-zero on success.
161  */
162 static int
163 proc_parser_mft_check(const char *fn, struct mft *p)
164 {
165 	const enum location loc[2] = { DIR_TEMP, DIR_VALID };
166 	size_t	 i;
167 	int	 rc = 1;
168 	char	*path;
169 
170 	for (i = 0; i < p->filesz; i++) {
171 		struct mftfile *m = &p->files[i];
172 		int try, fd = -1, noent = 0, valid = 0;
173 		for (try = 0; try < 2 && !valid; try++) {
174 			if ((path = parse_filepath(p->repoid, p->path, m->file,
175 			    loc[try])) == NULL)
176 				continue;
177 			fd = open(path, O_RDONLY);
178 			if (fd == -1 && errno == ENOENT)
179 				noent++;
180 			free(path);
181 
182 			/* remember which path was checked */
183 			m->location = loc[try];
184 			valid = valid_filehash(fd, m->hash, sizeof(m->hash));
185 		}
186 
187 		if (!valid) {
188 			/* silently skip not-existing unknown files */
189 			if (m->type == RTYPE_INVALID && noent == 2)
190 				continue;
191 			warnx("%s#%s: bad message digest for %s", fn,
192 			    p->seqnum, m->file);
193 			rc = 0;
194 			continue;
195 		}
196 	}
197 
198 	return rc;
199 }
200 
201 /*
202  * Load the CRL from loc using the info from the MFT.
203  */
204 static struct crl *
205 parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location loc,
206     char **crlfile)
207 {
208 	struct crl	*crl = NULL;
209 	unsigned char	*f = NULL;
210 	char		*fn = NULL;
211 	size_t		 flen;
212 
213 	*crlfile = NULL;
214 
215 	fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc);
216 	if (fn == NULL)
217 		goto out;
218 
219 	f = load_file(fn, &flen);
220 	if (f == NULL) {
221 		if (errno != ENOENT)
222 			warn("parse file %s", fn);
223 		goto out;
224 	}
225 
226 	if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
227 		goto out;
228 
229 	crl = crl_parse(fn, f, flen);
230 	if (crl == NULL)
231 		goto out;
232 
233 	if (strcmp(crl->aki, mft->aki) != 0) {
234 		warnx("%s: AKI doesn't match Manifest AKI", fn);
235 		goto out;
236 	}
237 
238 	*crlfile = fn;
239 	free(f);
240 
241 	return crl;
242 
243  out:
244 	crl_free(crl);
245 	free(f);
246 	free(fn);
247 
248 	return NULL;
249 }
250 
251 /*
252  * Parse and validate a manifest file. Skip checking the fileandhash
253  * this is done in the post check. After this step we know the mft is
254  * valid and can be compared.
255  * Return the mft on success or NULL on failure.
256  */
257 static struct mft *
258 proc_parser_mft_pre(struct entity *entp, enum location loc, char **file,
259     struct crl **crl, char **crlfile, const char **errstr)
260 {
261 	struct mft	*mft;
262 	X509		*x509;
263 	struct auth	*a;
264 	unsigned char	*der;
265 	size_t		 len;
266 
267 	*crl = NULL;
268 	*crlfile = NULL;
269 	*errstr = NULL;
270 
271 	*file = parse_filepath(entp->repoid, entp->path, entp->file, loc);
272 	if (*file == NULL)
273 		return NULL;
274 
275 	der = load_file(*file, &len);
276 	if (der == NULL && errno != ENOENT)
277 		warn("parse file %s", *file);
278 
279 	if ((mft = mft_parse(&x509, *file, entp->talid, der, len)) == NULL) {
280 		free(der);
281 		return NULL;
282 	}
283 	free(der);
284 
285 	*crl = parse_load_crl_from_mft(entp, mft, DIR_TEMP, crlfile);
286 	if (*crl == NULL)
287 		*crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile);
288 
289 	a = valid_ski_aki(*file, &auths, mft->ski, mft->aki, NULL);
290 	if (!valid_x509(*file, ctx, x509, a, *crl, errstr)) {
291 		X509_free(x509);
292 		mft_free(mft);
293 		crl_free(*crl);
294 		*crl = NULL;
295 		free(*crlfile);
296 		*crlfile = NULL;
297 		return NULL;
298 	}
299 	X509_free(x509);
300 
301 	mft->repoid = entp->repoid;
302 	mft->talid = a->cert->talid;
303 
304 	return mft;
305 }
306 
307 /*
308  * Do the end of manifest validation.
309  * Return the mft on success or NULL on failure.
310  */
311 static struct mft *
312 proc_parser_mft_post(char *file, struct mft *mft, const char *path,
313     const char *errstr)
314 {
315 	/* check that now is not before from */
316 	time_t now = get_current_time();
317 
318 	if (mft == NULL) {
319 		if (errstr == NULL)
320 			errstr = "no valid mft available";
321 		warnx("%s: %s", file, errstr);
322 		return NULL;
323 	}
324 
325 	/* check that now is not before from */
326 	if (now < mft->thisupdate) {
327 		warnx("%s: mft not yet valid %s", file,
328 		    time2str(mft->thisupdate));
329 		mft->stale = 1;
330 	}
331 	/* check that now is not after until */
332 	if (now > mft->nextupdate) {
333 		warnx("%s: mft expired on %s", file,
334 		    time2str(mft->nextupdate));
335 		mft->stale = 1;
336 	}
337 
338 	if (path != NULL)
339 		if ((mft->path = strdup(path)) == NULL)
340 			err(1, NULL);
341 
342 	if (!mft->stale)
343 		if (!proc_parser_mft_check(file, mft)) {
344 			mft_free(mft);
345 			return NULL;
346 		}
347 
348 	return mft;
349 }
350 
351 /*
352  * Load the most recent MFT by opening both options and comparing the two.
353  */
354 static char *
355 proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
356     time_t *crlmtime)
357 {
358 	struct mft	*mft1 = NULL, *mft2 = NULL;
359 	struct crl	*crl, *crl1, *crl2;
360 	char		*file, *file1, *file2, *crl1file, *crl2file;
361 	const char	*err1, *err2;
362 
363 	*mp = NULL;
364 	*crlmtime = 0;
365 
366 	mft1 = proc_parser_mft_pre(entp, DIR_VALID, &file1, &crl1, &crl1file,
367 	    &err1);
368 	mft2 = proc_parser_mft_pre(entp, DIR_TEMP, &file2, &crl2, &crl2file,
369 	    &err2);
370 
371 	/* overload error from temp file if it is set */
372 	if (mft1 == NULL && mft2 == NULL)
373 		if (err2 != NULL)
374 			err1 = err2;
375 
376 	if (mft_compare(mft1, mft2) == 1) {
377 		mft_free(mft2);
378 		crl_free(crl2);
379 		free(crl2file);
380 		free(file2);
381 		*mp = proc_parser_mft_post(file1, mft1, entp->path, err1);
382 		crl = crl1;
383 		file = file1;
384 		*crlfile = crl1file;
385 	} else {
386 		mft_free(mft1);
387 		crl_free(crl1);
388 		free(crl1file);
389 		free(file1);
390 		*mp = proc_parser_mft_post(file2, mft2, entp->path, err2);
391 		crl = crl2;
392 		file = file2;
393 		*crlfile = crl2file;
394 	}
395 
396 	if (*mp != NULL) {
397 		*crlmtime = crl->lastupdate;
398 		if (!crl_insert(&crlt, crl)) {
399 			warnx("%s: duplicate AKI %s", file, crl->aki);
400 			crl_free(crl);
401 		}
402 	} else {
403 		crl_free(crl);
404 	}
405 	return file;
406 }
407 
408 /*
409  * Certificates are from manifests (has a digest and is signed with
410  * another certificate) Parse the certificate, make sure its
411  * signatures are valid (with CRLs), then validate the RPKI content.
412  * This returns a certificate (which must not be freed) or NULL on
413  * parse failure.
414  */
415 static struct cert *
416 proc_parser_cert(char *file, const unsigned char *der, size_t len,
417     const char *mftaki)
418 {
419 	struct cert	*cert;
420 	struct crl	*crl;
421 	struct auth	*a;
422 	const char	*errstr = NULL;
423 
424 	/* Extract certificate data. */
425 
426 	cert = cert_parse_pre(file, der, len);
427 	cert = cert_parse(file, cert);
428 	if (cert == NULL)
429 		return NULL;
430 
431 	a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki);
432 	crl = crl_get(&crlt, a);
433 
434 	if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
435 	    !valid_cert(file, a, cert)) {
436 		if (errstr != NULL)
437 			warnx("%s: %s", file, errstr);
438 		cert_free(cert);
439 		return NULL;
440 	}
441 
442 	cert->talid = a->cert->talid;
443 
444 	if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
445 		if (!constraints_validate(file, cert)) {
446 			cert_free(cert);
447 			return NULL;
448 		}
449 	}
450 
451 	/*
452 	 * Add validated CA certs to the RPKI auth tree.
453 	 */
454 	if (cert->purpose == CERT_PURPOSE_CA)
455 		auth_insert(&auths, cert, a);
456 
457 	return cert;
458 }
459 
460 /*
461  * Root certificates come from TALs (has a pkey and is self-signed).
462  * Parse the certificate, ensure that its public key matches the
463  * known public key from the TAL, and then validate the RPKI
464  * content.
465  *
466  * This returns a certificate (which must not be freed) or NULL on
467  * parse failure.
468  */
469 static struct cert *
470 proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
471     unsigned char *pkey, size_t pkeysz, int talid)
472 {
473 	struct cert		*cert;
474 
475 	/* Extract certificate data. */
476 
477 	cert = cert_parse_pre(file, der, len);
478 	cert = ta_parse(file, cert, pkey, pkeysz);
479 	if (cert == NULL)
480 		return NULL;
481 
482 	if (!valid_ta(file, &auths, cert)) {
483 		warnx("%s: certificate not a valid ta", file);
484 		cert_free(cert);
485 		return NULL;
486 	}
487 
488 	cert->talid = talid;
489 
490 	/*
491 	 * Add valid roots to the RPKI auth tree.
492 	 */
493 	auth_insert(&auths, cert, NULL);
494 
495 	return cert;
496 }
497 
498 /*
499  * Parse a ghostbuster record
500  */
501 static struct gbr *
502 proc_parser_gbr(char *file, const unsigned char *der, size_t len,
503     const struct entity *entp)
504 {
505 	struct gbr	*gbr;
506 	X509		*x509;
507 	struct crl	*crl;
508 	struct auth	*a;
509 	const char	*errstr;
510 
511 	if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL)
512 		return NULL;
513 
514 	a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, entp->mftaki);
515 	crl = crl_get(&crlt, a);
516 
517 	/* return value can be ignored since nothing happens here */
518 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
519 		warnx("%s: %s", file, errstr);
520 		X509_free(x509);
521 		gbr_free(gbr);
522 		return NULL;
523 	}
524 	X509_free(x509);
525 
526 	gbr->talid = a->cert->talid;
527 
528 	return gbr;
529 }
530 
531 /*
532  * Parse an ASPA object
533  */
534 static struct aspa *
535 proc_parser_aspa(char *file, const unsigned char *der, size_t len,
536     const struct entity *entp)
537 {
538 	struct aspa	*aspa;
539 	struct auth	*a;
540 	struct crl	*crl;
541 	X509		*x509;
542 	const char	*errstr;
543 
544 	if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL)
545 		return NULL;
546 
547 	a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki, entp->mftaki);
548 	crl = crl_get(&crlt, a);
549 
550 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
551 		warnx("%s: %s", file, errstr);
552 		X509_free(x509);
553 		aspa_free(aspa);
554 		return NULL;
555 	}
556 	X509_free(x509);
557 
558 	aspa->talid = a->cert->talid;
559 
560 	aspa->expires = x509_find_expires(aspa->notafter, a, &crlt);
561 
562 	return aspa;
563 }
564 
565 /*
566  * Parse a TAK object.
567  */
568 static struct tak *
569 proc_parser_tak(char *file, const unsigned char *der, size_t len,
570     const struct entity *entp)
571 {
572 	struct tak	*tak;
573 	X509		*x509;
574 	struct crl	*crl;
575 	struct auth	*a;
576 	const char	*errstr;
577 	int		 rc = 0;
578 
579 	if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL)
580 		return NULL;
581 
582 	a = valid_ski_aki(file, &auths, tak->ski, tak->aki, entp->mftaki);
583 	crl = crl_get(&crlt, a);
584 
585 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
586 		warnx("%s: %s", file, errstr);
587 		goto out;
588 	}
589 
590 	/* TAK EE must be signed by self-signed CA */
591 	if (a->parent != NULL)
592 		goto out;
593 
594 	tak->talid = a->cert->talid;
595 	rc = 1;
596  out:
597 	if (rc == 0) {
598 		tak_free(tak);
599 		tak = NULL;
600 	}
601 	X509_free(x509);
602 	return tak;
603 }
604 
605 /*
606  * Load the file specified by the entity information.
607  */
608 static char *
609 parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
610 {
611 	char *file;
612 
613 	file = parse_filepath(entp->repoid, entp->path, entp->file,
614 	    entp->location);
615 	if (file == NULL)
616 		errx(1, "no path to file");
617 
618 	*f = load_file(file, flen);
619 	if (*f == NULL)
620 		warn("parse file %s", file);
621 
622 	return file;
623 }
624 
625 /*
626  * Process an entity and respond to parent process.
627  */
628 static void
629 parse_entity(struct entityq *q, struct msgbuf *msgq)
630 {
631 	struct entity	*entp;
632 	struct tal	*tal;
633 	struct cert	*cert;
634 	struct mft	*mft;
635 	struct roa	*roa;
636 	struct aspa	*aspa;
637 	struct gbr	*gbr;
638 	struct tak	*tak;
639 	struct ibuf	*b;
640 	unsigned char	*f;
641 	time_t		 mtime, crlmtime;
642 	size_t		 flen;
643 	char		*file, *crlfile;
644 	int		 c;
645 
646 	while ((entp = TAILQ_FIRST(q)) != NULL) {
647 		TAILQ_REMOVE(q, entp, entries);
648 
649 		/* handle RTYPE_REPO first */
650 		if (entp->type == RTYPE_REPO) {
651 			repo_add(entp->repoid, entp->path, entp->file);
652 			entity_free(entp);
653 			continue;
654 		}
655 
656 		/* pass back at least type, repoid and filename */
657 		b = io_new_buffer();
658 		io_simple_buffer(b, &entp->type, sizeof(entp->type));
659 		io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
660 		io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
661 
662 		file = NULL;
663 		f = NULL;
664 		mtime = 0;
665 		crlmtime = 0;
666 
667 		switch (entp->type) {
668 		case RTYPE_TAL:
669 			io_str_buffer(b, entp->file);
670 			io_simple_buffer(b, &mtime, sizeof(mtime));
671 			if ((tal = tal_parse(entp->file, entp->data,
672 			    entp->datasz)) == NULL)
673 				errx(1, "%s: could not parse tal file",
674 				    entp->file);
675 			tal->id = entp->talid;
676 			tal_buffer(b, tal);
677 			tal_free(tal);
678 			break;
679 		case RTYPE_CER:
680 			file = parse_load_file(entp, &f, &flen);
681 			io_str_buffer(b, file);
682 			if (entp->data != NULL)
683 				cert = proc_parser_root_cert(file,
684 				    f, flen, entp->data, entp->datasz,
685 				    entp->talid);
686 			else
687 				cert = proc_parser_cert(file, f, flen,
688 				    entp->mftaki);
689 			if (cert != NULL)
690 				mtime = cert->notbefore;
691 			io_simple_buffer(b, &mtime, sizeof(mtime));
692 			c = (cert != NULL);
693 			io_simple_buffer(b, &c, sizeof(int));
694 			if (cert != NULL) {
695 				cert->repoid = entp->repoid;
696 				cert_buffer(b, cert);
697 			}
698 			/*
699 			 * The parsed certificate data "cert" is now
700 			 * managed in the "auths" table, so don't free
701 			 * it here.
702 			 */
703 			break;
704 		case RTYPE_MFT:
705 			file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime);
706 			io_str_buffer(b, file);
707 			if (mft != NULL)
708 				mtime = mft->signtime;
709 			io_simple_buffer(b, &mtime, sizeof(mtime));
710 			c = (mft != NULL);
711 			io_simple_buffer(b, &c, sizeof(int));
712 			if (mft != NULL)
713 				mft_buffer(b, mft);
714 
715 			/* Push valid CRL together with the MFT. */
716 			if (crlfile != NULL) {
717 				enum rtype type;
718 				struct ibuf *b2;
719 
720 				b2 = io_new_buffer();
721 				type = RTYPE_CRL;
722 				io_simple_buffer(b2, &type, sizeof(type));
723 				io_simple_buffer(b2, &entp->repoid,
724 				    sizeof(entp->repoid));
725 				io_simple_buffer(b2, &entp->talid,
726 				    sizeof(entp->talid));
727 				io_str_buffer(b2, crlfile);
728 				io_simple_buffer(b2, &crlmtime,
729 				    sizeof(crlmtime));
730 				free(crlfile);
731 
732 				io_close_buffer(msgq, b2);
733 			}
734 			mft_free(mft);
735 			break;
736 		case RTYPE_ROA:
737 			file = parse_load_file(entp, &f, &flen);
738 			io_str_buffer(b, file);
739 			roa = proc_parser_roa(file, f, flen, entp);
740 			if (roa != NULL)
741 				mtime = roa->signtime;
742 			io_simple_buffer(b, &mtime, sizeof(mtime));
743 			c = (roa != NULL);
744 			io_simple_buffer(b, &c, sizeof(int));
745 			if (roa != NULL)
746 				roa_buffer(b, roa);
747 			roa_free(roa);
748 			break;
749 		case RTYPE_GBR:
750 			file = parse_load_file(entp, &f, &flen);
751 			io_str_buffer(b, file);
752 			gbr = proc_parser_gbr(file, f, flen, entp);
753 			if (gbr != NULL)
754 				mtime = gbr->signtime;
755 			io_simple_buffer(b, &mtime, sizeof(mtime));
756 			gbr_free(gbr);
757 			break;
758 		case RTYPE_ASPA:
759 			file = parse_load_file(entp, &f, &flen);
760 			io_str_buffer(b, file);
761 			aspa = proc_parser_aspa(file, f, flen, entp);
762 			if (aspa != NULL)
763 				mtime = aspa->signtime;
764 			io_simple_buffer(b, &mtime, sizeof(mtime));
765 			c = (aspa != NULL);
766 			io_simple_buffer(b, &c, sizeof(int));
767 			if (aspa != NULL)
768 				aspa_buffer(b, aspa);
769 			aspa_free(aspa);
770 			break;
771 		case RTYPE_TAK:
772 			file = parse_load_file(entp, &f, &flen);
773 			io_str_buffer(b, file);
774 			tak = proc_parser_tak(file, f, flen, entp);
775 			if (tak != NULL)
776 				mtime = tak->signtime;
777 			io_simple_buffer(b, &mtime, sizeof(mtime));
778 			tak_free(tak);
779 			break;
780 		case RTYPE_CRL:
781 		default:
782 			file = parse_filepath(entp->repoid, entp->path,
783 			    entp->file, entp->location);
784 			io_str_buffer(b, file);
785 			io_simple_buffer(b, &mtime, sizeof(mtime));
786 			warnx("%s: unhandled type %d", file, entp->type);
787 			break;
788 		}
789 
790 		free(f);
791 		free(file);
792 		io_close_buffer(msgq, b);
793 		entity_free(entp);
794 	}
795 }
796 
797 /*
798  * Process responsible for parsing and validating content.
799  * All this process does is wait to be told about a file to parse, then
800  * it parses it and makes sure that the data being returned is fully
801  * validated and verified.
802  * The process will exit cleanly only when fd is closed.
803  */
804 void
805 proc_parser(int fd)
806 {
807 	struct entityq	 q;
808 	struct msgbuf	 msgq;
809 	struct pollfd	 pfd;
810 	struct entity	*entp;
811 	struct ibuf	*b, *inbuf = NULL;
812 
813 	/* Only allow access to the cache directory. */
814 	if (unveil(".", "r") == -1)
815 		err(1, "unveil cachedir");
816 	if (pledge("stdio rpath", NULL) == -1)
817 		err(1, "pledge");
818 
819 	ERR_load_crypto_strings();
820 	OpenSSL_add_all_ciphers();
821 	OpenSSL_add_all_digests();
822 	x509_init_oid();
823 	constraints_parse();
824 
825 	if ((ctx = X509_STORE_CTX_new()) == NULL)
826 		err(1, "X509_STORE_CTX_new");
827 
828 	TAILQ_INIT(&q);
829 
830 	msgbuf_init(&msgq);
831 	msgq.fd = fd;
832 
833 	pfd.fd = fd;
834 
835 	for (;;) {
836 		pfd.events = POLLIN;
837 		if (msgq.queued)
838 			pfd.events |= POLLOUT;
839 
840 		if (poll(&pfd, 1, INFTIM) == -1) {
841 			if (errno == EINTR)
842 				continue;
843 			err(1, "poll");
844 		}
845 		if ((pfd.revents & (POLLERR|POLLNVAL)))
846 			errx(1, "poll: bad descriptor");
847 
848 		/* If the parent closes, return immediately. */
849 
850 		if ((pfd.revents & POLLHUP))
851 			break;
852 
853 		if ((pfd.revents & POLLIN)) {
854 			b = io_buf_read(fd, &inbuf);
855 			if (b != NULL) {
856 				entp = calloc(1, sizeof(struct entity));
857 				if (entp == NULL)
858 					err(1, NULL);
859 				entity_read_req(b, entp);
860 				TAILQ_INSERT_TAIL(&q, entp, entries);
861 				ibuf_free(b);
862 			}
863 		}
864 
865 		if (pfd.revents & POLLOUT) {
866 			switch (msgbuf_write(&msgq)) {
867 			case 0:
868 				errx(1, "write: connection closed");
869 			case -1:
870 				err(1, "write");
871 			}
872 		}
873 
874 		parse_entity(&q, &msgq);
875 	}
876 
877 	while ((entp = TAILQ_FIRST(&q)) != NULL) {
878 		TAILQ_REMOVE(&q, entp, entries);
879 		entity_free(entp);
880 	}
881 
882 	auth_tree_free(&auths);
883 	crl_tree_free(&crlt);
884 
885 	X509_STORE_CTX_free(ctx);
886 	msgbuf_clear(&msgq);
887 
888 	ibuf_free(inbuf);
889 
890 	exit(0);
891 }
892