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