xref: /openbsd/usr.sbin/rpki-client/parser.c (revision 510d2225)
1 /*	$OpenBSD: parser.c,v 1.103 2023/12/11 19:05:20 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 
284 	if (!EVP_Digest(der, len, mft->mfthash, NULL, EVP_sha256(), NULL))
285 		errx(1, "EVP_Digest failed");
286 
287 	free(der);
288 
289 	*crl = parse_load_crl_from_mft(entp, mft, DIR_TEMP, crlfile);
290 	if (*crl == NULL)
291 		*crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile);
292 
293 	a = valid_ski_aki(*file, &auths, mft->ski, mft->aki, NULL);
294 	if (!valid_x509(*file, ctx, x509, a, *crl, errstr)) {
295 		X509_free(x509);
296 		mft_free(mft);
297 		crl_free(*crl);
298 		*crl = NULL;
299 		free(*crlfile);
300 		*crlfile = NULL;
301 		return NULL;
302 	}
303 	X509_free(x509);
304 
305 	mft->repoid = entp->repoid;
306 	mft->talid = a->cert->talid;
307 
308 	return mft;
309 }
310 
311 /*
312  * Do the end of manifest validation.
313  * Return the mft on success or NULL on failure.
314  */
315 static struct mft *
316 proc_parser_mft_post(char *file, struct mft *mft, const char *path,
317     const char *errstr, int *warned)
318 {
319 	/* check that now is not before from */
320 	time_t now = get_current_time();
321 
322 	if (mft == NULL) {
323 		if (errstr == NULL)
324 			errstr = "no valid mft available";
325 		if ((*warned)++ > 0)
326 			return NULL;
327 		warnx("%s: %s", file, errstr);
328 		return NULL;
329 	}
330 
331 	/* check that now is not before from */
332 	if (now < mft->thisupdate) {
333 		warnx("%s: mft not yet valid %s", file,
334 		    time2str(mft->thisupdate));
335 		mft->stale = 1;
336 	}
337 	/* check that now is not after until */
338 	if (now > mft->nextupdate) {
339 		warnx("%s: mft expired on %s", file,
340 		    time2str(mft->nextupdate));
341 		mft->stale = 1;
342 	}
343 
344 	if (path != NULL)
345 		if ((mft->path = strdup(path)) == NULL)
346 			err(1, NULL);
347 
348 	if (!mft->stale)
349 		if (!proc_parser_mft_check(file, mft)) {
350 			mft_free(mft);
351 			return NULL;
352 		}
353 
354 	return mft;
355 }
356 
357 /*
358  * Load the most recent MFT by opening both options and comparing the two.
359  */
360 static char *
361 proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
362     time_t *crlmtime)
363 {
364 	struct mft	*mft1 = NULL, *mft2 = NULL;
365 	struct crl	*crl, *crl1, *crl2;
366 	char		*file, *file1, *file2, *crl1file, *crl2file;
367 	const char	*err1, *err2;
368 	int		 r, warned = 0;
369 
370 	*mp = NULL;
371 	*crlmtime = 0;
372 
373 	mft1 = proc_parser_mft_pre(entp, DIR_TEMP, &file1, &crl1, &crl1file,
374 	    &err1);
375 	mft2 = proc_parser_mft_pre(entp, DIR_VALID, &file2, &crl2, &crl2file,
376 	    &err2);
377 
378 	/* overload error from temp file if it is set */
379 	if (mft1 == NULL && mft2 == NULL)
380 		if (err2 != NULL)
381 			err1 = err2;
382 
383 	r = mft_compare(mft1, mft2);
384 	if (r == -1 && mft1 != NULL && mft2 != NULL)
385 		warnx("%s: manifest replay detected (expected >= #%s, got #%s)",
386 		    file1, mft2->seqnum, mft1->seqnum);
387 
388 	if (r == 0 && memcmp(mft1->mfthash, mft2->mfthash,
389 	    SHA256_DIGEST_LENGTH) != 0)
390 		warnx("%s: manifest misissuance, #%s was recycled",
391 		    file1, mft1->seqnum);
392 
393 	if (r == 1) {
394 		*mp = proc_parser_mft_post(file1, mft1, entp->path, err1,
395 		    &warned);
396 		if (*mp == NULL) {
397 			mft1 = NULL;
398 			if (mft2 != NULL)
399 				warnx("%s: failed fetch, continuing with #%s",
400 				    file2, mft2->seqnum);
401 		}
402 	}
403 
404 	if (*mp != NULL) {
405 		mft_free(mft2);
406 		crl_free(crl2);
407 		free(crl2file);
408 		free(file2);
409 
410 		crl = crl1;
411 		file = file1;
412 		*crlfile = crl1file;
413 	} else {
414 		if (err2 == NULL)
415 			err2 = err1;
416 		*mp = proc_parser_mft_post(file2, mft2, entp->path, err2,
417 		    &warned);
418 
419 		mft_free(mft1);
420 		crl_free(crl1);
421 		free(crl1file);
422 		free(file1);
423 
424 		crl = crl2;
425 		file = file2;
426 		*crlfile = crl2file;
427 	}
428 
429 	if (*mp != NULL) {
430 		*crlmtime = crl->lastupdate;
431 		if (!crl_insert(&crlt, crl)) {
432 			warnx("%s: duplicate AKI %s", file, crl->aki);
433 			crl_free(crl);
434 		}
435 	} else {
436 		crl_free(crl);
437 	}
438 	return file;
439 }
440 
441 /*
442  * Certificates are from manifests (has a digest and is signed with
443  * another certificate) Parse the certificate, make sure its
444  * signatures are valid (with CRLs), then validate the RPKI content.
445  * This returns a certificate (which must not be freed) or NULL on
446  * parse failure.
447  */
448 static struct cert *
449 proc_parser_cert(char *file, const unsigned char *der, size_t len,
450     const char *mftaki)
451 {
452 	struct cert	*cert;
453 	struct crl	*crl;
454 	struct auth	*a;
455 	const char	*errstr = NULL;
456 
457 	/* Extract certificate data. */
458 
459 	cert = cert_parse_pre(file, der, len);
460 	cert = cert_parse(file, cert);
461 	if (cert == NULL)
462 		return NULL;
463 
464 	a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki);
465 	crl = crl_get(&crlt, a);
466 
467 	if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
468 	    !valid_cert(file, a, cert)) {
469 		if (errstr != NULL)
470 			warnx("%s: %s", file, errstr);
471 		cert_free(cert);
472 		return NULL;
473 	}
474 
475 	cert->talid = a->cert->talid;
476 
477 	if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
478 		if (!constraints_validate(file, cert)) {
479 			cert_free(cert);
480 			return NULL;
481 		}
482 	}
483 
484 	/*
485 	 * Add validated CA certs to the RPKI auth tree.
486 	 */
487 	if (cert->purpose == CERT_PURPOSE_CA)
488 		auth_insert(&auths, cert, a);
489 
490 	return cert;
491 }
492 
493 /*
494  * Root certificates come from TALs (has a pkey and is self-signed).
495  * Parse the certificate, ensure that its public key matches the
496  * known public key from the TAL, and then validate the RPKI
497  * content.
498  *
499  * This returns a certificate (which must not be freed) or NULL on
500  * parse failure.
501  */
502 static struct cert *
503 proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
504     unsigned char *pkey, size_t pkeysz, int talid)
505 {
506 	struct cert		*cert;
507 
508 	/* Extract certificate data. */
509 
510 	cert = cert_parse_pre(file, der, len);
511 	cert = ta_parse(file, cert, pkey, pkeysz);
512 	if (cert == NULL)
513 		return NULL;
514 
515 	if (!valid_ta(file, &auths, cert)) {
516 		warnx("%s: certificate not a valid ta", file);
517 		cert_free(cert);
518 		return NULL;
519 	}
520 
521 	cert->talid = talid;
522 
523 	/*
524 	 * Add valid roots to the RPKI auth tree.
525 	 */
526 	auth_insert(&auths, cert, NULL);
527 
528 	return cert;
529 }
530 
531 /*
532  * Parse a ghostbuster record
533  */
534 static struct gbr *
535 proc_parser_gbr(char *file, const unsigned char *der, size_t len,
536     const struct entity *entp)
537 {
538 	struct gbr	*gbr;
539 	X509		*x509;
540 	struct crl	*crl;
541 	struct auth	*a;
542 	const char	*errstr;
543 
544 	if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL)
545 		return NULL;
546 
547 	a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, entp->mftaki);
548 	crl = crl_get(&crlt, a);
549 
550 	/* return value can be ignored since nothing happens here */
551 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
552 		warnx("%s: %s", file, errstr);
553 		X509_free(x509);
554 		gbr_free(gbr);
555 		return NULL;
556 	}
557 	X509_free(x509);
558 
559 	gbr->talid = a->cert->talid;
560 
561 	return gbr;
562 }
563 
564 /*
565  * Parse an ASPA object
566  */
567 static struct aspa *
568 proc_parser_aspa(char *file, const unsigned char *der, size_t len,
569     const struct entity *entp)
570 {
571 	struct aspa	*aspa;
572 	struct auth	*a;
573 	struct crl	*crl;
574 	X509		*x509;
575 	const char	*errstr;
576 
577 	if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL)
578 		return NULL;
579 
580 	a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki, entp->mftaki);
581 	crl = crl_get(&crlt, a);
582 
583 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
584 		warnx("%s: %s", file, errstr);
585 		X509_free(x509);
586 		aspa_free(aspa);
587 		return NULL;
588 	}
589 	X509_free(x509);
590 
591 	aspa->talid = a->cert->talid;
592 
593 	aspa->expires = x509_find_expires(aspa->notafter, a, &crlt);
594 
595 	return aspa;
596 }
597 
598 /*
599  * Parse a TAK object.
600  */
601 static struct tak *
602 proc_parser_tak(char *file, const unsigned char *der, size_t len,
603     const struct entity *entp)
604 {
605 	struct tak	*tak;
606 	X509		*x509;
607 	struct crl	*crl;
608 	struct auth	*a;
609 	const char	*errstr;
610 	int		 rc = 0;
611 
612 	if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL)
613 		return NULL;
614 
615 	a = valid_ski_aki(file, &auths, tak->ski, tak->aki, entp->mftaki);
616 	crl = crl_get(&crlt, a);
617 
618 	if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
619 		warnx("%s: %s", file, errstr);
620 		goto out;
621 	}
622 
623 	/* TAK EE must be signed by self-signed CA */
624 	if (a->parent != NULL)
625 		goto out;
626 
627 	tak->talid = a->cert->talid;
628 	rc = 1;
629  out:
630 	if (rc == 0) {
631 		tak_free(tak);
632 		tak = NULL;
633 	}
634 	X509_free(x509);
635 	return tak;
636 }
637 
638 /*
639  * Load the file specified by the entity information.
640  */
641 static char *
642 parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
643 {
644 	char *file;
645 
646 	file = parse_filepath(entp->repoid, entp->path, entp->file,
647 	    entp->location);
648 	if (file == NULL)
649 		errx(1, "no path to file");
650 
651 	*f = load_file(file, flen);
652 	if (*f == NULL)
653 		warn("parse file %s", file);
654 
655 	return file;
656 }
657 
658 /*
659  * Process an entity and respond to parent process.
660  */
661 static void
662 parse_entity(struct entityq *q, struct msgbuf *msgq)
663 {
664 	struct entity	*entp;
665 	struct tal	*tal;
666 	struct cert	*cert;
667 	struct mft	*mft;
668 	struct roa	*roa;
669 	struct aspa	*aspa;
670 	struct gbr	*gbr;
671 	struct tak	*tak;
672 	struct ibuf	*b;
673 	unsigned char	*f;
674 	time_t		 mtime, crlmtime;
675 	size_t		 flen;
676 	char		*file, *crlfile;
677 	int		 c;
678 
679 	while ((entp = TAILQ_FIRST(q)) != NULL) {
680 		TAILQ_REMOVE(q, entp, entries);
681 
682 		/* handle RTYPE_REPO first */
683 		if (entp->type == RTYPE_REPO) {
684 			repo_add(entp->repoid, entp->path, entp->file);
685 			entity_free(entp);
686 			continue;
687 		}
688 
689 		/* pass back at least type, repoid and filename */
690 		b = io_new_buffer();
691 		io_simple_buffer(b, &entp->type, sizeof(entp->type));
692 		io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
693 		io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
694 
695 		file = NULL;
696 		f = NULL;
697 		mtime = 0;
698 		crlmtime = 0;
699 
700 		switch (entp->type) {
701 		case RTYPE_TAL:
702 			io_str_buffer(b, entp->file);
703 			io_simple_buffer(b, &mtime, sizeof(mtime));
704 			if ((tal = tal_parse(entp->file, entp->data,
705 			    entp->datasz)) == NULL)
706 				errx(1, "%s: could not parse tal file",
707 				    entp->file);
708 			tal->id = entp->talid;
709 			tal_buffer(b, tal);
710 			tal_free(tal);
711 			break;
712 		case RTYPE_CER:
713 			file = parse_load_file(entp, &f, &flen);
714 			io_str_buffer(b, file);
715 			if (entp->data != NULL)
716 				cert = proc_parser_root_cert(file,
717 				    f, flen, entp->data, entp->datasz,
718 				    entp->talid);
719 			else
720 				cert = proc_parser_cert(file, f, flen,
721 				    entp->mftaki);
722 			if (cert != NULL)
723 				mtime = cert->notbefore;
724 			io_simple_buffer(b, &mtime, sizeof(mtime));
725 			c = (cert != NULL);
726 			io_simple_buffer(b, &c, sizeof(int));
727 			if (cert != NULL) {
728 				cert->repoid = entp->repoid;
729 				cert_buffer(b, cert);
730 			}
731 			/*
732 			 * The parsed certificate data "cert" is now
733 			 * managed in the "auths" table, so don't free
734 			 * it here.
735 			 */
736 			break;
737 		case RTYPE_MFT:
738 			file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime);
739 			io_str_buffer(b, file);
740 			if (mft != NULL)
741 				mtime = mft->signtime;
742 			io_simple_buffer(b, &mtime, sizeof(mtime));
743 			c = (mft != NULL);
744 			io_simple_buffer(b, &c, sizeof(int));
745 			if (mft != NULL)
746 				mft_buffer(b, mft);
747 
748 			/* Push valid CRL together with the MFT. */
749 			if (crlfile != NULL) {
750 				enum rtype type;
751 				struct ibuf *b2;
752 
753 				b2 = io_new_buffer();
754 				type = RTYPE_CRL;
755 				io_simple_buffer(b2, &type, sizeof(type));
756 				io_simple_buffer(b2, &entp->repoid,
757 				    sizeof(entp->repoid));
758 				io_simple_buffer(b2, &entp->talid,
759 				    sizeof(entp->talid));
760 				io_str_buffer(b2, crlfile);
761 				io_simple_buffer(b2, &crlmtime,
762 				    sizeof(crlmtime));
763 				free(crlfile);
764 
765 				io_close_buffer(msgq, b2);
766 			}
767 			mft_free(mft);
768 			break;
769 		case RTYPE_ROA:
770 			file = parse_load_file(entp, &f, &flen);
771 			io_str_buffer(b, file);
772 			roa = proc_parser_roa(file, f, flen, entp);
773 			if (roa != NULL)
774 				mtime = roa->signtime;
775 			io_simple_buffer(b, &mtime, sizeof(mtime));
776 			c = (roa != NULL);
777 			io_simple_buffer(b, &c, sizeof(int));
778 			if (roa != NULL)
779 				roa_buffer(b, roa);
780 			roa_free(roa);
781 			break;
782 		case RTYPE_GBR:
783 			file = parse_load_file(entp, &f, &flen);
784 			io_str_buffer(b, file);
785 			gbr = proc_parser_gbr(file, f, flen, entp);
786 			if (gbr != NULL)
787 				mtime = gbr->signtime;
788 			io_simple_buffer(b, &mtime, sizeof(mtime));
789 			gbr_free(gbr);
790 			break;
791 		case RTYPE_ASPA:
792 			file = parse_load_file(entp, &f, &flen);
793 			io_str_buffer(b, file);
794 			aspa = proc_parser_aspa(file, f, flen, entp);
795 			if (aspa != NULL)
796 				mtime = aspa->signtime;
797 			io_simple_buffer(b, &mtime, sizeof(mtime));
798 			c = (aspa != NULL);
799 			io_simple_buffer(b, &c, sizeof(int));
800 			if (aspa != NULL)
801 				aspa_buffer(b, aspa);
802 			aspa_free(aspa);
803 			break;
804 		case RTYPE_TAK:
805 			file = parse_load_file(entp, &f, &flen);
806 			io_str_buffer(b, file);
807 			tak = proc_parser_tak(file, f, flen, entp);
808 			if (tak != NULL)
809 				mtime = tak->signtime;
810 			io_simple_buffer(b, &mtime, sizeof(mtime));
811 			tak_free(tak);
812 			break;
813 		case RTYPE_CRL:
814 		default:
815 			file = parse_filepath(entp->repoid, entp->path,
816 			    entp->file, entp->location);
817 			io_str_buffer(b, file);
818 			io_simple_buffer(b, &mtime, sizeof(mtime));
819 			warnx("%s: unhandled type %d", file, entp->type);
820 			break;
821 		}
822 
823 		free(f);
824 		free(file);
825 		io_close_buffer(msgq, b);
826 		entity_free(entp);
827 	}
828 }
829 
830 /*
831  * Process responsible for parsing and validating content.
832  * All this process does is wait to be told about a file to parse, then
833  * it parses it and makes sure that the data being returned is fully
834  * validated and verified.
835  * The process will exit cleanly only when fd is closed.
836  */
837 void
838 proc_parser(int fd)
839 {
840 	struct entityq	 q;
841 	struct msgbuf	 msgq;
842 	struct pollfd	 pfd;
843 	struct entity	*entp;
844 	struct ibuf	*b, *inbuf = NULL;
845 
846 	/* Only allow access to the cache directory. */
847 	if (unveil(".", "r") == -1)
848 		err(1, "unveil cachedir");
849 	if (pledge("stdio rpath", NULL) == -1)
850 		err(1, "pledge");
851 
852 	ERR_load_crypto_strings();
853 	OpenSSL_add_all_ciphers();
854 	OpenSSL_add_all_digests();
855 	x509_init_oid();
856 	constraints_parse();
857 
858 	if ((ctx = X509_STORE_CTX_new()) == NULL)
859 		err(1, "X509_STORE_CTX_new");
860 
861 	TAILQ_INIT(&q);
862 
863 	msgbuf_init(&msgq);
864 	msgq.fd = fd;
865 
866 	pfd.fd = fd;
867 
868 	for (;;) {
869 		pfd.events = POLLIN;
870 		if (msgq.queued)
871 			pfd.events |= POLLOUT;
872 
873 		if (poll(&pfd, 1, INFTIM) == -1) {
874 			if (errno == EINTR)
875 				continue;
876 			err(1, "poll");
877 		}
878 		if ((pfd.revents & (POLLERR|POLLNVAL)))
879 			errx(1, "poll: bad descriptor");
880 
881 		/* If the parent closes, return immediately. */
882 
883 		if ((pfd.revents & POLLHUP))
884 			break;
885 
886 		if ((pfd.revents & POLLIN)) {
887 			b = io_buf_read(fd, &inbuf);
888 			if (b != NULL) {
889 				entp = calloc(1, sizeof(struct entity));
890 				if (entp == NULL)
891 					err(1, NULL);
892 				entity_read_req(b, entp);
893 				TAILQ_INSERT_TAIL(&q, entp, entries);
894 				ibuf_free(b);
895 			}
896 		}
897 
898 		if (pfd.revents & POLLOUT) {
899 			switch (msgbuf_write(&msgq)) {
900 			case 0:
901 				errx(1, "write: connection closed");
902 			case -1:
903 				err(1, "write");
904 			}
905 		}
906 
907 		parse_entity(&q, &msgq);
908 	}
909 
910 	while ((entp = TAILQ_FIRST(&q)) != NULL) {
911 		TAILQ_REMOVE(&q, entp, entries);
912 		entity_free(entp);
913 	}
914 
915 	auth_tree_free(&auths);
916 	crl_tree_free(&crlt);
917 
918 	X509_STORE_CTX_free(ctx);
919 	msgbuf_clear(&msgq);
920 
921 	ibuf_free(inbuf);
922 
923 	exit(0);
924 }
925