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