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