1 /* $OpenBSD: parser.c,v 1.148 2024/11/21 13:32:27 claudio 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 extern int certid;
42
43 extern BN_CTX *bn_ctx;
44
45 static X509_STORE_CTX *ctx;
46 static struct auth_tree auths = RB_INITIALIZER(&auths);
47 static struct crl_tree crlt = RB_INITIALIZER(&crlt);
48
49 struct parse_repo {
50 RB_ENTRY(parse_repo) entry;
51 char *path;
52 char *validpath;
53 unsigned int id;
54 };
55
56 static RB_HEAD(repo_tree, parse_repo) repos = RB_INITIALIZER(&repos);
57
58 static inline int
repocmp(struct parse_repo * a,struct parse_repo * b)59 repocmp(struct parse_repo *a, struct parse_repo *b)
60 {
61 return a->id - b->id;
62 }
63
64 RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp);
65
66 static struct parse_repo *
repo_get(unsigned int id)67 repo_get(unsigned int id)
68 {
69 struct parse_repo needle = { .id = id };
70
71 return RB_FIND(repo_tree, &repos, &needle);
72 }
73
74 static void
repo_add(unsigned int id,char * path,char * validpath)75 repo_add(unsigned int id, char *path, char *validpath)
76 {
77 struct parse_repo *rp;
78
79 if ((rp = calloc(1, sizeof(*rp))) == NULL)
80 err(1, NULL);
81 rp->id = id;
82 if (path != NULL)
83 if ((rp->path = strdup(path)) == NULL)
84 err(1, NULL);
85 if (validpath != NULL)
86 if ((rp->validpath = strdup(validpath)) == NULL)
87 err(1, NULL);
88
89 if (RB_INSERT(repo_tree, &repos, rp) != NULL)
90 errx(1, "repository already added: id %d, %s", id, path);
91 }
92
93 /*
94 * Return the issuer by its certificate id, or NULL on failure.
95 * Make sure the AKI is the same as the AKI listed on the Manifest,
96 * and that the SKI of the cert matches with the AKI.
97 */
98 static struct auth *
find_issuer(const char * fn,int id,const char * aki,const char * mftaki)99 find_issuer(const char *fn, int id, const char *aki, const char *mftaki)
100 {
101 struct auth *a;
102
103 a = auth_find(&auths, id);
104 if (a == NULL) {
105 if (certid <= CERTID_MAX)
106 warnx("%s: RFC 6487: unknown cert with SKI %s", fn,
107 aki);
108 return NULL;
109 }
110
111 if (mftaki != NULL) {
112 if (strcmp(aki, mftaki) != 0) {
113 warnx("%s: AKI %s doesn't match Manifest AKI %s", fn,
114 aki, mftaki);
115 return NULL;
116 }
117 }
118
119 if (strcmp(aki, a->cert->ski) != 0) {
120 warnx("%s: AKI %s doesn't match issuer SKI %s", fn,
121 aki, a->cert->ski);
122 return NULL;
123 }
124
125 return a;
126 }
127
128 /*
129 * Build access path to file based on repoid, path, location and file values.
130 */
131 static char *
parse_filepath(unsigned int repoid,const char * path,const char * file,enum location loc)132 parse_filepath(unsigned int repoid, const char *path, const char *file,
133 enum location loc)
134 {
135 struct parse_repo *rp;
136 char *fn, *repopath;
137
138 /* build file path based on repoid, entity path and filename */
139 rp = repo_get(repoid);
140 if (rp == NULL)
141 errx(1, "build file path: repository %u missing", repoid);
142
143 if (loc == DIR_VALID)
144 repopath = rp->validpath;
145 else
146 repopath = rp->path;
147
148 if (repopath == NULL)
149 return NULL;
150
151 if (path == NULL) {
152 if (asprintf(&fn, "%s/%s", repopath, file) == -1)
153 err(1, NULL);
154 } else {
155 if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1)
156 err(1, NULL);
157 }
158 return fn;
159 }
160
161 /*
162 * Parse and validate a ROA.
163 * This is standard stuff.
164 * Returns the roa on success, NULL on failure.
165 */
166 static struct roa *
proc_parser_roa(char * file,const unsigned char * der,size_t len,const struct entity * entp)167 proc_parser_roa(char *file, const unsigned char *der, size_t len,
168 const struct entity *entp)
169 {
170 struct roa *roa;
171 X509 *x509 = NULL;
172 struct auth *a;
173 struct crl *crl;
174 const char *errstr;
175
176 if ((roa = roa_parse(&x509, file, entp->talid, der, len)) == NULL)
177 goto out;
178
179 a = find_issuer(file, entp->certid, roa->aki, entp->mftaki);
180 if (a == NULL)
181 goto out;
182 crl = crl_get(&crlt, a);
183
184 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
185 warnx("%s: %s", file, errstr);
186 goto out;
187 }
188 X509_free(x509);
189 x509 = NULL;
190
191 roa->talid = a->cert->talid;
192
193 roa->expires = x509_find_expires(roa->notafter, a, &crlt);
194
195 return roa;
196
197 out:
198 roa_free(roa);
199 X509_free(x509);
200
201 return NULL;
202 }
203
204 /*
205 * Parse and validate a draft-ietf-sidrops-rpki-prefixlist SPL.
206 * Returns the spl on success, NULL on failure.
207 */
208 static struct spl *
proc_parser_spl(char * file,const unsigned char * der,size_t len,const struct entity * entp)209 proc_parser_spl(char *file, const unsigned char *der, size_t len,
210 const struct entity *entp)
211 {
212 struct spl *spl;
213 X509 *x509 = NULL;
214 struct auth *a;
215 struct crl *crl;
216 const char *errstr;
217
218 if ((spl = spl_parse(&x509, file, entp->talid, der, len)) == NULL)
219 goto out;
220
221 a = find_issuer(file, entp->certid, spl->aki, entp->mftaki);
222 if (a == NULL)
223 goto out;
224 crl = crl_get(&crlt, a);
225
226 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
227 warnx("%s: %s", file, errstr);
228 goto out;
229 }
230 X509_free(x509);
231 x509 = NULL;
232
233 spl->talid = a->cert->talid;
234
235 spl->expires = x509_find_expires(spl->notafter, a, &crlt);
236
237 return spl;
238
239 out:
240 spl_free(spl);
241 X509_free(x509);
242
243 return NULL;
244 }
245
246 /*
247 * Check all files and their hashes in a MFT structure.
248 * Return zero on failure, non-zero on success.
249 */
250 static int
proc_parser_mft_check(const char * fn,struct mft * p)251 proc_parser_mft_check(const char *fn, struct mft *p)
252 {
253 const enum location loc[2] = { DIR_TEMP, DIR_VALID };
254 size_t i;
255 int rc = 1;
256 char *path;
257
258 if (p == NULL)
259 return 0;
260
261 for (i = 0; i < p->filesz; i++) {
262 struct mftfile *m = &p->files[i];
263 int try, fd = -1, noent = 0, valid = 0;
264 for (try = 0; try < 2 && !valid; try++) {
265 if ((path = parse_filepath(p->repoid, p->path, m->file,
266 loc[try])) == NULL)
267 continue;
268 fd = open(path, O_RDONLY);
269 if (fd == -1 && errno == ENOENT)
270 noent++;
271 free(path);
272
273 /* remember which path was checked */
274 m->location = loc[try];
275 valid = valid_filehash(fd, m->hash, sizeof(m->hash));
276 }
277
278 if (!valid) {
279 /* silently skip not-existing unknown files */
280 if (m->type == RTYPE_INVALID && noent == 2)
281 continue;
282 warnx("%s#%s: bad message digest for %s", fn,
283 p->seqnum, m->file);
284 rc = 0;
285 continue;
286 }
287 }
288
289 return rc;
290 }
291
292 /*
293 * Load the CRL from loc using the info from the MFT.
294 */
295 static struct crl *
parse_load_crl_from_mft(struct entity * entp,struct mft * mft,enum location loc,char ** crlfile)296 parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location loc,
297 char **crlfile)
298 {
299 struct crl *crl = NULL;
300 unsigned char *f = NULL;
301 char *fn = NULL;
302 size_t flen;
303
304 *crlfile = NULL;
305
306 fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc);
307 if (fn == NULL)
308 goto out;
309
310 f = load_file(fn, &flen);
311 if (f == NULL) {
312 if (errno != ENOENT)
313 warn("parse file %s", fn);
314 goto out;
315 }
316
317 if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
318 goto out;
319
320 crl = crl_parse(fn, f, flen);
321 if (crl == NULL)
322 goto out;
323
324 if (strcmp(crl->aki, mft->aki) != 0) {
325 warnx("%s: AKI doesn't match Manifest AKI", fn);
326 goto out;
327 }
328
329 if ((crl->mftpath = strdup(mft->sia)) == NULL)
330 err(1, NULL);
331
332 *crlfile = fn;
333 free(f);
334
335 return crl;
336
337 out:
338 crl_free(crl);
339 free(f);
340 free(fn);
341
342 return NULL;
343 }
344
345 /*
346 * Parse and validate a manifest file.
347 * Don't check the fileandhash, this is done later on.
348 * Return the mft on success, or NULL on failure.
349 */
350 static struct mft *
proc_parser_mft_pre(struct entity * entp,char * file,struct crl ** crl,char ** crlfile,struct mft * cached_mft,const char ** errstr)351 proc_parser_mft_pre(struct entity *entp, char *file, struct crl **crl,
352 char **crlfile, struct mft *cached_mft, const char **errstr)
353 {
354 struct mft *mft;
355 X509 *x509;
356 struct auth *a;
357 unsigned char *der;
358 size_t len;
359 time_t now;
360 int issued_cmp, seqnum_cmp;
361
362 *crl = NULL;
363 *crlfile = NULL;
364 *errstr = NULL;
365
366 if (file == NULL)
367 return NULL;
368
369 der = load_file(file, &len);
370 if (der == NULL && errno != ENOENT)
371 warn("parse file %s", file);
372
373 if ((mft = mft_parse(&x509, file, entp->talid, der, len)) == NULL) {
374 free(der);
375 return NULL;
376 }
377
378 if (entp->path != NULL) {
379 if ((mft->path = strdup(entp->path)) == NULL)
380 err(1, NULL);
381 }
382
383 if (!EVP_Digest(der, len, mft->mfthash, NULL, EVP_sha256(), NULL))
384 errx(1, "EVP_Digest failed");
385
386 free(der);
387
388 *crl = parse_load_crl_from_mft(entp, mft, DIR_TEMP, crlfile);
389 if (*crl == NULL)
390 *crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile);
391
392 a = find_issuer(file, entp->certid, mft->aki, NULL);
393 if (a == NULL)
394 goto err;
395 if (!valid_x509(file, ctx, x509, a, *crl, errstr))
396 goto err;
397 X509_free(x509);
398 x509 = NULL;
399
400 mft->repoid = entp->repoid;
401 mft->talid = a->cert->talid;
402 mft->certid = entp->certid;
403
404 now = get_current_time();
405 /* check that now is not before from */
406 if (now < mft->thisupdate) {
407 warnx("%s: manifest not yet valid %s", file,
408 time2str(mft->thisupdate));
409 goto err;
410 }
411 /* check that now is not after until */
412 if (now > mft->nextupdate) {
413 warnx("%s: manifest expired on %s", file,
414 time2str(mft->nextupdate));
415 goto err;
416 }
417
418 /* if there is nothing to compare to, return now */
419 if (cached_mft == NULL)
420 return mft;
421
422 /*
423 * Check that the cached manifest is older in the sense that it was
424 * issued earlier and that it has a smaller sequence number.
425 */
426
427 if ((issued_cmp = mft_compare_issued(mft, cached_mft)) < 0) {
428 warnx("%s: unexpected manifest issuance date (want >= %lld, "
429 "got %lld)", file, (long long)cached_mft->thisupdate,
430 (long long)mft->thisupdate);
431 goto err;
432 }
433 if ((seqnum_cmp = mft_compare_seqnum(mft, cached_mft)) < 0) {
434 warnx("%s: unexpected manifest number (want >= #%s, got #%s)",
435 file, cached_mft->seqnum, mft->seqnum);
436 goto err;
437 }
438 if (issued_cmp > 0 && seqnum_cmp == 0) {
439 warnx("%s: manifest issued at %lld and %lld with same "
440 "manifest number #%s", file, (long long)mft->thisupdate,
441 (long long)cached_mft->thisupdate, cached_mft->seqnum);
442 goto err;
443 }
444 if (issued_cmp == 0 && seqnum_cmp > 0) {
445 warnx("%s: #%s and #%s were issued at same issuance date %lld",
446 file, mft->seqnum, cached_mft->seqnum,
447 (long long)mft->thisupdate);
448 goto err;
449 }
450 if (issued_cmp == 0 && seqnum_cmp == 0 && memcmp(mft->mfthash,
451 cached_mft->mfthash, SHA256_DIGEST_LENGTH) != 0) {
452 warnx("%s: misissuance, issuance date %lld and manifest number "
453 "#%s were recycled", file, (long long)mft->thisupdate,
454 mft->seqnum);
455 goto err;
456 }
457
458 if (seqnum_cmp > 0) {
459 if (mft_seqnum_gap_present(mft, cached_mft)) {
460 mft->seqnum_gap = 1;
461 warnx("%s: seqnum gap detected #%s -> #%s", file,
462 cached_mft->seqnum, mft->seqnum);
463 }
464 }
465
466 return mft;
467
468 err:
469 X509_free(x509);
470 mft_free(mft);
471 crl_free(*crl);
472 *crl = NULL;
473 free(*crlfile);
474 *crlfile = NULL;
475 return NULL;
476 }
477
478 /*
479 * Load the most recent MFT by opening both options and comparing the two.
480 */
481 static char *
proc_parser_mft(struct entity * entp,struct mft ** mp,char ** crlfile,time_t * crlmtime)482 proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
483 time_t *crlmtime)
484 {
485 struct mft *mft1 = NULL, *mft2 = NULL;
486 struct crl *crl, *crl1 = NULL, *crl2 = NULL;
487 char *file, *file1 = NULL, *file2 = NULL;
488 char *crl1file = NULL, *crl2file = NULL;
489 const char *err1 = NULL, *err2 = NULL;
490
491 *mp = NULL;
492 *crlmtime = 0;
493
494 file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID);
495 mft2 = proc_parser_mft_pre(entp, file2, &crl2, &crl2file, NULL, &err2);
496
497 if (!noop) {
498 file1 = parse_filepath(entp->repoid, entp->path, entp->file,
499 DIR_TEMP);
500 mft1 = proc_parser_mft_pre(entp, file1, &crl1, &crl1file, mft2,
501 &err1);
502 }
503
504 if (proc_parser_mft_check(file1, mft1)) {
505 mft_free(mft2);
506 crl_free(crl2);
507 free(crl2file);
508 free(file2);
509
510 *mp = mft1;
511 crl = crl1;
512 file = file1;
513 *crlfile = crl1file;
514 } else {
515 if (mft1 != NULL && mft2 != NULL)
516 warnx("%s: failed fetch, continuing with #%s "
517 "from cache", file2, mft2->seqnum);
518
519 if (!proc_parser_mft_check(file2, mft2)) {
520 mft_free(mft2);
521 mft2 = NULL;
522
523 if (err2 == NULL)
524 err2 = err1;
525 if (err2 == NULL)
526 err2 = "no valid manifest available";
527 if (certid <= CERTID_MAX)
528 warnx("%s: %s", file2, err2);
529 }
530
531 mft_free(mft1);
532 crl_free(crl1);
533 free(crl1file);
534 free(file1);
535
536 *mp = mft2;
537 crl = crl2;
538 file = file2;
539 *crlfile = crl2file;
540 }
541
542 if (*mp != NULL) {
543 *crlmtime = crl->thisupdate;
544 if (crl_insert(&crlt, crl))
545 crl = NULL;
546 }
547 crl_free(crl);
548
549 return file;
550 }
551
552 /*
553 * Certificates are from manifests (has a digest and is signed with
554 * another certificate) Parse the certificate, make sure its
555 * signatures are valid (with CRLs), then validate the RPKI content.
556 * This returns a certificate (which must not be freed) or NULL on
557 * parse failure.
558 */
559 static struct cert *
proc_parser_cert(char * file,const unsigned char * der,size_t len,const struct entity * entp)560 proc_parser_cert(char *file, const unsigned char *der, size_t len,
561 const struct entity *entp)
562 {
563 struct cert *cert;
564 struct crl *crl;
565 struct auth *a;
566 const char *errstr = NULL;
567
568 /* Extract certificate data. */
569
570 cert = cert_parse_pre(file, der, len);
571 cert = cert_parse(file, cert);
572 if (cert == NULL)
573 goto out;
574
575 a = find_issuer(file, entp->certid, cert->aki, entp->mftaki);
576 if (a == NULL)
577 goto out;
578 crl = crl_get(&crlt, a);
579
580 if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
581 !valid_cert(file, a, cert)) {
582 if (errstr != NULL)
583 warnx("%s: %s", file, errstr);
584 goto out;
585 }
586
587 cert->talid = a->cert->talid;
588
589 if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
590 if (!constraints_validate(file, cert))
591 goto out;
592 }
593
594 /*
595 * Add validated CA certs to the RPKI auth tree.
596 */
597 if (cert->purpose == CERT_PURPOSE_CA)
598 auth_insert(file, &auths, cert, a);
599
600 return cert;
601
602 out:
603 cert_free(cert);
604
605 return NULL;
606 }
607
608 static int
proc_parser_ta_cmp(const struct cert * cert1,const struct cert * cert2)609 proc_parser_ta_cmp(const struct cert *cert1, const struct cert *cert2)
610 {
611 if (cert1 == NULL)
612 return -1;
613 if (cert2 == NULL)
614 return 1;
615
616 /*
617 * The standards don't specify tiebreakers. While RFC 6487 and other
618 * sources advise against backdating, it's explicitly allowed and some
619 * TAs do. Some TAs have also re-issued with new dates and old
620 * serialNumber.
621 * Our tiebreaker logic: a more recent notBefore is taken to mean a
622 * more recent issuance, and thus preferable. Given equal notBefore
623 * values, prefer the TA cert with the narrower validity window. This
624 * hopefully encourages TA operators to reduce egregiously long TA
625 * validity periods.
626 */
627
628 if (cert1->notbefore < cert2->notbefore)
629 return -1;
630 if (cert1->notbefore > cert2->notbefore)
631 return 1;
632
633 if (cert1->notafter > cert2->notafter)
634 return -1;
635 if (cert1->notafter < cert2->notafter)
636 return 1;
637
638 /*
639 * Both certs are valid from our perspective. If anything changed,
640 * prefer the freshly-fetched one. We rely on cert_parse_pre() having
641 * cached the extensions and thus libcrypto has already computed the
642 * certs' hashes (SHA-1 for OpenSSL, SHA-512 for LibreSSL). The below
643 * compares them.
644 */
645
646 return X509_cmp(cert1->x509, cert2->x509) != 0;
647 }
648
649 /*
650 * Root certificates come from TALs. Inspect and validate both options and
651 * compare the two. The cert in out_cert must not be freed. Returns the file
652 * name of the chosen TA.
653 */
654 static char *
proc_parser_root_cert(struct entity * entp,struct cert ** out_cert)655 proc_parser_root_cert(struct entity *entp, struct cert **out_cert)
656 {
657 struct cert *cert1 = NULL, *cert2 = NULL;
658 char *file1 = NULL, *file2 = NULL;
659 unsigned char *der = NULL, *pkey = entp->data;
660 size_t der_len = 0, pkeysz = entp->datasz;
661 int cmp;
662
663 *out_cert = NULL;
664
665 file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID);
666 der = load_file(file2, &der_len);
667 cert2 = cert_parse_pre(file2, der, der_len);
668 free(der);
669 cert2 = ta_parse(file2, cert2, pkey, pkeysz);
670
671 if (!noop) {
672 file1 = parse_filepath(entp->repoid, entp->path, entp->file,
673 DIR_TEMP);
674 der = load_file(file1, &der_len);
675 cert1 = cert_parse_pre(file1, der, der_len);
676 free(der);
677 cert1 = ta_parse(file1, cert1, pkey, pkeysz);
678 }
679
680 if ((cmp = proc_parser_ta_cmp(cert1, cert2)) > 0) {
681 cert_free(cert2);
682 free(file2);
683
684 cert1->talid = entp->talid;
685 auth_insert(file1, &auths, cert1, NULL);
686
687 *out_cert = cert1;
688 return file1;
689 } else {
690 if (cmp < 0 && cert1 != NULL && cert2 != NULL)
691 warnx("%s: cached TA is newer", entp->file);
692 cert_free(cert1);
693 free(file1);
694
695 if (cert2 != 0) {
696 cert2->talid = entp->talid;
697 auth_insert(file2, &auths, cert2, NULL);
698 }
699
700 *out_cert = cert2;
701 return file2;
702 }
703 }
704
705 /*
706 * Parse a ghostbuster record
707 */
708 static struct gbr *
proc_parser_gbr(char * file,const unsigned char * der,size_t len,const struct entity * entp)709 proc_parser_gbr(char *file, const unsigned char *der, size_t len,
710 const struct entity *entp)
711 {
712 struct gbr *gbr;
713 X509 *x509 = NULL;
714 struct crl *crl;
715 struct auth *a;
716 const char *errstr;
717
718 if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL)
719 goto out;
720
721 a = find_issuer(file, entp->certid, gbr->aki, entp->mftaki);
722 if (a == NULL)
723 goto out;
724 crl = crl_get(&crlt, a);
725
726 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
727 warnx("%s: %s", file, errstr);
728 goto out;
729 }
730 X509_free(x509);
731 x509 = NULL;
732
733 gbr->talid = a->cert->talid;
734
735 return gbr;
736
737 out:
738 gbr_free(gbr);
739 X509_free(x509);
740
741 return NULL;
742 }
743
744 /*
745 * Parse an ASPA object
746 */
747 static struct aspa *
proc_parser_aspa(char * file,const unsigned char * der,size_t len,const struct entity * entp)748 proc_parser_aspa(char *file, const unsigned char *der, size_t len,
749 const struct entity *entp)
750 {
751 struct aspa *aspa;
752 X509 *x509 = NULL;
753 struct auth *a;
754 struct crl *crl;
755 const char *errstr;
756
757 if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL)
758 goto out;
759
760 a = find_issuer(file, entp->certid, aspa->aki, entp->mftaki);
761 if (a == NULL)
762 goto out;
763 crl = crl_get(&crlt, a);
764
765 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
766 warnx("%s: %s", file, errstr);
767 goto out;
768 }
769 X509_free(x509);
770 x509 = NULL;
771
772 aspa->talid = a->cert->talid;
773
774 aspa->expires = x509_find_expires(aspa->notafter, a, &crlt);
775
776 return aspa;
777
778 out:
779 aspa_free(aspa);
780 X509_free(x509);
781
782 return NULL;
783 }
784
785 /*
786 * Parse a TAK object.
787 */
788 static struct tak *
proc_parser_tak(char * file,const unsigned char * der,size_t len,const struct entity * entp)789 proc_parser_tak(char *file, const unsigned char *der, size_t len,
790 const struct entity *entp)
791 {
792 struct tak *tak;
793 X509 *x509 = NULL;
794 struct crl *crl;
795 struct auth *a;
796 const char *errstr;
797
798 if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL)
799 goto out;
800
801 a = find_issuer(file, entp->certid, tak->aki, entp->mftaki);
802 if (a == NULL)
803 goto out;
804 crl = crl_get(&crlt, a);
805
806 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
807 warnx("%s: %s", file, errstr);
808 goto out;
809 }
810 X509_free(x509);
811 x509 = NULL;
812
813 /* TAK EE must be signed by self-signed CA */
814 if (a->issuer != NULL)
815 goto out;
816
817 tak->talid = a->cert->talid;
818
819 return tak;
820
821 out:
822 tak_free(tak);
823 X509_free(x509);
824
825 return NULL;
826 }
827
828 /*
829 * Load the file specified by the entity information.
830 */
831 static char *
parse_load_file(struct entity * entp,unsigned char ** f,size_t * flen)832 parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
833 {
834 char *file;
835
836 file = parse_filepath(entp->repoid, entp->path, entp->file,
837 entp->location);
838 if (file == NULL)
839 errx(1, "no path to file");
840
841 *f = load_file(file, flen);
842 if (*f == NULL)
843 warn("parse file %s", file);
844
845 return file;
846 }
847
848 /*
849 * Process an entity and respond to parent process.
850 */
851 static void
parse_entity(struct entityq * q,struct msgbuf * msgq)852 parse_entity(struct entityq *q, struct msgbuf *msgq)
853 {
854 struct entity *entp;
855 struct tal *tal;
856 struct cert *cert;
857 struct mft *mft;
858 struct roa *roa;
859 struct aspa *aspa;
860 struct gbr *gbr;
861 struct tak *tak;
862 struct spl *spl;
863 struct ibuf *b;
864 unsigned char *f;
865 time_t mtime, crlmtime;
866 size_t flen;
867 char *file, *crlfile;
868 int c;
869
870 while ((entp = TAILQ_FIRST(q)) != NULL) {
871 TAILQ_REMOVE(q, entp, entries);
872
873 /* handle RTYPE_REPO first */
874 if (entp->type == RTYPE_REPO) {
875 repo_add(entp->repoid, entp->path, entp->file);
876 entity_free(entp);
877 continue;
878 }
879
880 /* pass back at least type, repoid and filename */
881 b = io_new_buffer();
882 io_simple_buffer(b, &entp->type, sizeof(entp->type));
883 io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
884 io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
885
886 file = NULL;
887 f = NULL;
888 mtime = 0;
889 crlmtime = 0;
890
891 switch (entp->type) {
892 case RTYPE_TAL:
893 io_str_buffer(b, entp->file);
894 io_simple_buffer(b, &mtime, sizeof(mtime));
895 if ((tal = tal_parse(entp->file, entp->data,
896 entp->datasz)) == NULL)
897 errx(1, "%s: could not parse tal file",
898 entp->file);
899 tal->id = entp->talid;
900 tal_buffer(b, tal);
901 tal_free(tal);
902 break;
903 case RTYPE_CER:
904 if (entp->data != NULL) {
905 file = proc_parser_root_cert(entp, &cert);
906 } else {
907 file = parse_load_file(entp, &f, &flen);
908 cert = proc_parser_cert(file, f, flen, entp);
909 }
910 io_str_buffer(b, file);
911 if (cert != NULL)
912 mtime = cert->notbefore;
913 io_simple_buffer(b, &mtime, sizeof(mtime));
914 c = (cert != NULL);
915 io_simple_buffer(b, &c, sizeof(int));
916 if (cert != NULL) {
917 cert->repoid = entp->repoid;
918 cert_buffer(b, cert);
919 }
920 /*
921 * The parsed certificate data "cert" is now
922 * managed in the "auths" table, so don't free
923 * it here.
924 */
925 break;
926 case RTYPE_MFT:
927 file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime);
928 io_str_buffer(b, file);
929 if (mft != NULL)
930 mtime = mft->signtime;
931 io_simple_buffer(b, &mtime, sizeof(mtime));
932 c = (mft != NULL);
933 io_simple_buffer(b, &c, sizeof(int));
934 if (mft != NULL)
935 mft_buffer(b, mft);
936
937 /* Push valid CRL together with the MFT. */
938 if (crlfile != NULL) {
939 enum rtype type;
940 struct ibuf *b2;
941
942 b2 = io_new_buffer();
943 type = RTYPE_CRL;
944 io_simple_buffer(b2, &type, sizeof(type));
945 io_simple_buffer(b2, &entp->repoid,
946 sizeof(entp->repoid));
947 io_simple_buffer(b2, &entp->talid,
948 sizeof(entp->talid));
949 io_str_buffer(b2, crlfile);
950 io_simple_buffer(b2, &crlmtime,
951 sizeof(crlmtime));
952 free(crlfile);
953
954 io_close_buffer(msgq, b2);
955 }
956 mft_free(mft);
957 break;
958 case RTYPE_ROA:
959 file = parse_load_file(entp, &f, &flen);
960 io_str_buffer(b, file);
961 roa = proc_parser_roa(file, f, flen, entp);
962 if (roa != NULL)
963 mtime = roa->signtime;
964 io_simple_buffer(b, &mtime, sizeof(mtime));
965 c = (roa != NULL);
966 io_simple_buffer(b, &c, sizeof(int));
967 if (roa != NULL)
968 roa_buffer(b, roa);
969 roa_free(roa);
970 break;
971 case RTYPE_GBR:
972 file = parse_load_file(entp, &f, &flen);
973 io_str_buffer(b, file);
974 gbr = proc_parser_gbr(file, f, flen, entp);
975 if (gbr != NULL)
976 mtime = gbr->signtime;
977 io_simple_buffer(b, &mtime, sizeof(mtime));
978 gbr_free(gbr);
979 break;
980 case RTYPE_ASPA:
981 file = parse_load_file(entp, &f, &flen);
982 io_str_buffer(b, file);
983 aspa = proc_parser_aspa(file, f, flen, entp);
984 if (aspa != NULL)
985 mtime = aspa->signtime;
986 io_simple_buffer(b, &mtime, sizeof(mtime));
987 c = (aspa != NULL);
988 io_simple_buffer(b, &c, sizeof(int));
989 if (aspa != NULL)
990 aspa_buffer(b, aspa);
991 aspa_free(aspa);
992 break;
993 case RTYPE_TAK:
994 file = parse_load_file(entp, &f, &flen);
995 io_str_buffer(b, file);
996 tak = proc_parser_tak(file, f, flen, entp);
997 if (tak != NULL)
998 mtime = tak->signtime;
999 io_simple_buffer(b, &mtime, sizeof(mtime));
1000 tak_free(tak);
1001 break;
1002 case RTYPE_SPL:
1003 file = parse_load_file(entp, &f, &flen);
1004 io_str_buffer(b, file);
1005 if (experimental) {
1006 spl = proc_parser_spl(file, f, flen, entp);
1007 if (spl != NULL)
1008 mtime = spl->signtime;
1009 } else {
1010 if (verbose > 0)
1011 warnx("%s: skipped", file);
1012 spl = NULL;
1013 }
1014 io_simple_buffer(b, &mtime, sizeof(mtime));
1015 c = (spl != NULL);
1016 io_simple_buffer(b, &c, sizeof(int));
1017 if (spl != NULL)
1018 spl_buffer(b, spl);
1019 spl_free(spl);
1020 break;
1021 case RTYPE_CRL:
1022 default:
1023 file = parse_filepath(entp->repoid, entp->path,
1024 entp->file, entp->location);
1025 io_str_buffer(b, file);
1026 io_simple_buffer(b, &mtime, sizeof(mtime));
1027 warnx("%s: unhandled type %d", file, entp->type);
1028 break;
1029 }
1030
1031 free(f);
1032 free(file);
1033 io_close_buffer(msgq, b);
1034 entity_free(entp);
1035 }
1036 }
1037
1038 /*
1039 * Process responsible for parsing and validating content.
1040 * All this process does is wait to be told about a file to parse, then
1041 * it parses it and makes sure that the data being returned is fully
1042 * validated and verified.
1043 * The process will exit cleanly only when fd is closed.
1044 */
1045 void
proc_parser(int fd)1046 proc_parser(int fd)
1047 {
1048 struct entityq q;
1049 struct msgbuf *msgq;
1050 struct pollfd pfd;
1051 struct entity *entp;
1052 struct ibuf *b, *inbuf = NULL;
1053
1054 /* Only allow access to the cache directory. */
1055 if (unveil(".", "r") == -1)
1056 err(1, "unveil cachedir");
1057 if (pledge("stdio rpath", NULL) == -1)
1058 err(1, "pledge");
1059
1060 ERR_load_crypto_strings();
1061 OpenSSL_add_all_ciphers();
1062 OpenSSL_add_all_digests();
1063 x509_init_oid();
1064 constraints_parse();
1065
1066 if ((ctx = X509_STORE_CTX_new()) == NULL)
1067 err(1, "X509_STORE_CTX_new");
1068 if ((bn_ctx = BN_CTX_new()) == NULL)
1069 err(1, "BN_CTX_new");
1070
1071 TAILQ_INIT(&q);
1072
1073 if ((msgq = msgbuf_new_reader(sizeof(size_t), io_parse_hdr, NULL)) ==
1074 NULL)
1075 err(1, NULL);
1076
1077 pfd.fd = fd;
1078
1079 for (;;) {
1080 pfd.events = POLLIN;
1081 if (msgbuf_queuelen(msgq) > 0)
1082 pfd.events |= POLLOUT;
1083
1084 if (poll(&pfd, 1, INFTIM) == -1) {
1085 if (errno == EINTR)
1086 continue;
1087 err(1, "poll");
1088 }
1089 if ((pfd.revents & (POLLERR|POLLNVAL)))
1090 errx(1, "poll: bad descriptor");
1091
1092 /* If the parent closes, return immediately. */
1093
1094 if ((pfd.revents & POLLHUP))
1095 break;
1096
1097 if ((pfd.revents & POLLIN)) {
1098 switch (ibuf_read(fd, msgq)) {
1099 case -1:
1100 err(1, "ibuf_read");
1101 case 0:
1102 errx(1, "ibuf_read: connection closed");
1103 }
1104 while ((b = io_buf_get(msgq)) != NULL) {
1105 entp = calloc(1, sizeof(struct entity));
1106 if (entp == NULL)
1107 err(1, NULL);
1108 entity_read_req(b, entp);
1109 TAILQ_INSERT_TAIL(&q, entp, entries);
1110 ibuf_free(b);
1111 }
1112 }
1113
1114 if (pfd.revents & POLLOUT) {
1115 if (msgbuf_write(fd, msgq) == -1) {
1116 if (errno == EPIPE)
1117 errx(1, "write: connection closed");
1118 else
1119 err(1, "write");
1120 }
1121 }
1122
1123 parse_entity(&q, msgq);
1124 }
1125
1126 while ((entp = TAILQ_FIRST(&q)) != NULL) {
1127 TAILQ_REMOVE(&q, entp, entries);
1128 entity_free(entp);
1129 }
1130
1131 auth_tree_free(&auths);
1132 crl_tree_free(&crlt);
1133
1134 X509_STORE_CTX_free(ctx);
1135 BN_CTX_free(bn_ctx);
1136
1137 msgbuf_free(msgq);
1138 ibuf_free(inbuf);
1139
1140 if (certid > CERTID_MAX)
1141 errx(1, "processing incomplete: too many certificates");
1142
1143 exit(0);
1144 }
1145