1 /* $OpenBSD: cert.c,v 1.155 2024/12/18 21:12:26 tb Exp $ */ 2 /* 3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2021 Job Snijders <job@openbsd.org> 5 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <assert.h> 21 #include <err.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include <openssl/asn1.h> 27 #include <openssl/x509.h> 28 #include <openssl/x509v3.h> 29 30 #include "extern.h" 31 32 extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ 33 extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ 34 extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ 35 extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ 36 37 int certid = TALSZ_MAX; 38 39 /* 40 * Append an IP address structure to our list of results. 41 * This will also constrain us to having at most one inheritance 42 * statement per AFI and also not have overlapping ranges (as prohibited 43 * in section 2.2.3.6). 44 * It does not make sure that ranges can't coalesce, that is, that any 45 * two ranges abut each other. 46 * This is warned against in section 2.2.3.6, but doesn't change the 47 * semantics of the system. 48 * Returns zero on failure (IP overlap) non-zero on success. 49 */ 50 static int 51 append_ip(const char *fn, struct cert_ip *ips, size_t *num_ips, 52 const struct cert_ip *ip) 53 { 54 if (!ip_addr_check_overlap(ip, fn, ips, *num_ips, 0)) 55 return 0; 56 ips[(*num_ips)++] = *ip; 57 return 1; 58 } 59 60 /* 61 * Append an AS identifier structure to our list of results. 62 * Makes sure that the identifiers do not overlap or improperly inherit 63 * as defined by RFC 3779 section 3.3. 64 */ 65 static int 66 append_as(const char *fn, struct cert_as *ases, size_t *num_ases, 67 const struct cert_as *as) 68 { 69 if (!as_check_overlap(as, fn, ases, *num_ases, 0)) 70 return 0; 71 ases[(*num_ases)++] = *as; 72 return 1; 73 } 74 75 /* 76 * Parse a range of AS identifiers as in 3.2.3.8. 77 * Returns zero on failure, non-zero on success. 78 */ 79 int 80 sbgp_as_range(const char *fn, struct cert_as *ases, size_t *num_ases, 81 const ASRange *range) 82 { 83 struct cert_as as; 84 85 memset(&as, 0, sizeof(struct cert_as)); 86 as.type = CERT_AS_RANGE; 87 88 if (!as_id_parse(range->min, &as.range.min)) { 89 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): " 90 "malformed AS identifier", fn); 91 return 0; 92 } 93 94 if (!as_id_parse(range->max, &as.range.max)) { 95 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): " 96 "malformed AS identifier", fn); 97 return 0; 98 } 99 100 if (as.range.max == as.range.min) { 101 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: " 102 "range is singular", fn); 103 return 0; 104 } else if (as.range.max < as.range.min) { 105 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: " 106 "range is out of order", fn); 107 return 0; 108 } 109 110 return append_as(fn, ases, num_ases, &as); 111 } 112 113 /* 114 * Parse an entire 3.2.3.10 integer type. 115 */ 116 int 117 sbgp_as_id(const char *fn, struct cert_as *ases, size_t *num_ases, 118 const ASN1_INTEGER *i) 119 { 120 struct cert_as as; 121 122 memset(&as, 0, sizeof(struct cert_as)); 123 as.type = CERT_AS_ID; 124 125 if (!as_id_parse(i, &as.id)) { 126 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): " 127 "malformed AS identifier", fn); 128 return 0; 129 } 130 if (as.id == 0) { 131 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): " 132 "AS identifier zero is reserved", fn); 133 return 0; 134 } 135 136 return append_as(fn, ases, num_ases, &as); 137 } 138 139 static int 140 sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *num_ases) 141 { 142 struct cert_as as; 143 144 memset(&as, 0, sizeof(struct cert_as)); 145 as.type = CERT_AS_INHERIT; 146 147 return append_as(fn, ases, num_ases, &as); 148 } 149 150 int 151 sbgp_parse_assysnum(const char *fn, const ASIdentifiers *asidentifiers, 152 struct cert_as **out_as, size_t *out_num_ases) 153 { 154 const ASIdOrRanges *aors = NULL; 155 struct cert_as *as = NULL; 156 size_t num_ases = 0, num; 157 int i; 158 159 assert(*out_as == NULL && *out_num_ases == 0); 160 161 if (asidentifiers->rdi != NULL) { 162 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " 163 "should not have RDI values", fn); 164 goto out; 165 } 166 167 if (asidentifiers->asnum == NULL) { 168 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " 169 "no AS number resource set", fn); 170 goto out; 171 } 172 173 switch (asidentifiers->asnum->type) { 174 case ASIdentifierChoice_inherit: 175 num = 1; 176 break; 177 case ASIdentifierChoice_asIdsOrRanges: 178 aors = asidentifiers->asnum->u.asIdsOrRanges; 179 num = sk_ASIdOrRange_num(aors); 180 break; 181 default: 182 warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: " 183 "unknown type %d", fn, asidentifiers->asnum->type); 184 goto out; 185 } 186 187 if (num == 0) { 188 warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn); 189 goto out; 190 } 191 if (num >= MAX_AS_SIZE) { 192 warnx("%s: too many AS number entries: limit %d", 193 fn, MAX_AS_SIZE); 194 goto out; 195 } 196 as = calloc(num, sizeof(struct cert_as)); 197 if (as == NULL) 198 err(1, NULL); 199 200 if (aors == NULL) { 201 if (!sbgp_as_inherit(fn, as, &num_ases)) 202 goto out; 203 } 204 205 for (i = 0; i < sk_ASIdOrRange_num(aors); i++) { 206 const ASIdOrRange *aor; 207 208 aor = sk_ASIdOrRange_value(aors, i); 209 switch (aor->type) { 210 case ASIdOrRange_id: 211 if (!sbgp_as_id(fn, as, &num_ases, aor->u.id)) 212 goto out; 213 break; 214 case ASIdOrRange_range: 215 if (!sbgp_as_range(fn, as, &num_ases, aor->u.range)) 216 goto out; 217 break; 218 default: 219 warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: " 220 "unknown type %d", fn, aor->type); 221 goto out; 222 } 223 } 224 225 *out_as = as; 226 *out_num_ases = num_ases; 227 228 return 1; 229 230 out: 231 free(as); 232 233 return 0; 234 } 235 236 /* 237 * Parse RFC 6487 4.8.11 X509v3 extension, with syntax documented in RFC 238 * 3779 starting in section 3.2. 239 * Returns zero on failure, non-zero on success. 240 */ 241 static int 242 sbgp_assysnum(const char *fn, struct cert *cert, X509_EXTENSION *ext) 243 { 244 ASIdentifiers *asidentifiers = NULL; 245 int rc = 0; 246 247 if (!X509_EXTENSION_get_critical(ext)) { 248 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " 249 "extension not critical", fn); 250 goto out; 251 } 252 253 if ((asidentifiers = X509V3_EXT_d2i(ext)) == NULL) { 254 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: " 255 "failed extension parse", fn); 256 goto out; 257 } 258 259 if (!sbgp_parse_assysnum(fn, asidentifiers, &cert->ases, 260 &cert->num_ases)) 261 goto out; 262 263 rc = 1; 264 out: 265 ASIdentifiers_free(asidentifiers); 266 return rc; 267 } 268 269 /* 270 * Construct a RFC 3779 2.2.3.8 range from its bit string. 271 * Returns zero on failure, non-zero on success. 272 */ 273 int 274 sbgp_addr(const char *fn, struct cert_ip *ips, size_t *num_ips, enum afi afi, 275 const ASN1_BIT_STRING *bs) 276 { 277 struct cert_ip ip; 278 279 memset(&ip, 0, sizeof(struct cert_ip)); 280 281 ip.afi = afi; 282 ip.type = CERT_IP_ADDR; 283 284 if (!ip_addr_parse(bs, afi, fn, &ip.ip)) { 285 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: " 286 "invalid IP address", fn); 287 return 0; 288 } 289 290 if (!ip_cert_compose_ranges(&ip)) { 291 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: " 292 "IP address range reversed", fn); 293 return 0; 294 } 295 296 return append_ip(fn, ips, num_ips, &ip); 297 } 298 299 /* 300 * Parse RFC 3779 2.2.3.9 range of addresses. 301 * Returns zero on failure, non-zero on success. 302 */ 303 int 304 sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *num_ips, 305 enum afi afi, const IPAddressRange *range) 306 { 307 struct cert_ip ip; 308 309 memset(&ip, 0, sizeof(struct cert_ip)); 310 311 ip.afi = afi; 312 ip.type = CERT_IP_RANGE; 313 314 if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) { 315 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 316 "invalid IP address", fn); 317 return 0; 318 } 319 320 if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) { 321 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 322 "invalid IP address", fn); 323 return 0; 324 } 325 326 if (!ip_cert_compose_ranges(&ip)) { 327 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 328 "IP address range reversed", fn); 329 return 0; 330 } 331 332 return append_ip(fn, ips, num_ips, &ip); 333 } 334 335 static int 336 sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *num_ips, 337 enum afi afi) 338 { 339 struct cert_ip ip; 340 341 memset(&ip, 0, sizeof(struct cert_ip)); 342 343 ip.afi = afi; 344 ip.type = CERT_IP_INHERIT; 345 346 return append_ip(fn, ips, num_ips, &ip); 347 } 348 349 int 350 sbgp_parse_ipaddrblk(const char *fn, const IPAddrBlocks *addrblk, 351 struct cert_ip **out_ips, size_t *out_num_ips) 352 { 353 const IPAddressFamily *af; 354 const IPAddressOrRanges *aors; 355 const IPAddressOrRange *aor; 356 enum afi afi; 357 struct cert_ip *ips = NULL; 358 size_t num_ips = 0, num; 359 int ipv4_seen = 0, ipv6_seen = 0; 360 int i, j, ipaddrblocksz; 361 362 assert(*out_ips == NULL && *out_num_ips == 0); 363 364 ipaddrblocksz = sk_IPAddressFamily_num(addrblk); 365 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) { 366 warnx("%s: RFC 6487 section 4.8.10: unexpected number of " 367 "ipAddrBlocks (got %d, expected 1 or 2)", 368 fn, ipaddrblocksz); 369 goto out; 370 } 371 372 for (i = 0; i < ipaddrblocksz; i++) { 373 af = sk_IPAddressFamily_value(addrblk, i); 374 375 switch (af->ipAddressChoice->type) { 376 case IPAddressChoice_inherit: 377 aors = NULL; 378 num = num_ips + 1; 379 break; 380 case IPAddressChoice_addressesOrRanges: 381 aors = af->ipAddressChoice->u.addressesOrRanges; 382 num = num_ips + sk_IPAddressOrRange_num(aors); 383 break; 384 default: 385 warnx("%s: RFC 3779: IPAddressChoice: unknown type %d", 386 fn, af->ipAddressChoice->type); 387 goto out; 388 } 389 if (num == num_ips) { 390 warnx("%s: RFC 6487 section 4.8.10: " 391 "empty ipAddressesOrRanges", fn); 392 goto out; 393 } 394 395 if (num >= MAX_IP_SIZE) 396 goto out; 397 ips = recallocarray(ips, num_ips, num, sizeof(struct cert_ip)); 398 if (ips == NULL) 399 err(1, NULL); 400 401 if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) { 402 warnx("%s: RFC 3779: invalid AFI", fn); 403 goto out; 404 } 405 406 switch (afi) { 407 case AFI_IPV4: 408 if (ipv4_seen++ > 0) { 409 warnx("%s: RFC 6487 section 4.8.10: " 410 "IPv4 appears twice", fn); 411 goto out; 412 } 413 break; 414 case AFI_IPV6: 415 if (ipv6_seen++ > 0) { 416 warnx("%s: RFC 6487 section 4.8.10: " 417 "IPv6 appears twice", fn); 418 goto out; 419 } 420 break; 421 } 422 423 if (aors == NULL) { 424 if (!sbgp_addr_inherit(fn, ips, &num_ips, afi)) 425 goto out; 426 continue; 427 } 428 429 for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) { 430 aor = sk_IPAddressOrRange_value(aors, j); 431 switch (aor->type) { 432 case IPAddressOrRange_addressPrefix: 433 if (!sbgp_addr(fn, ips, &num_ips, afi, 434 aor->u.addressPrefix)) 435 goto out; 436 break; 437 case IPAddressOrRange_addressRange: 438 if (!sbgp_addr_range(fn, ips, &num_ips, afi, 439 aor->u.addressRange)) 440 goto out; 441 break; 442 default: 443 warnx("%s: RFC 3779: IPAddressOrRange: " 444 "unknown type %d", fn, aor->type); 445 goto out; 446 } 447 } 448 } 449 450 *out_ips = ips; 451 *out_num_ips = num_ips; 452 453 return 1; 454 455 out: 456 free(ips); 457 458 return 0; 459 } 460 461 /* 462 * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with 463 * syntax documented in RFC 3779 starting in section 2.2. 464 * Returns zero on failure, non-zero on success. 465 */ 466 static int 467 sbgp_ipaddrblk(const char *fn, struct cert *cert, X509_EXTENSION *ext) 468 { 469 IPAddrBlocks *addrblk = NULL; 470 int rc = 0; 471 472 if (!X509_EXTENSION_get_critical(ext)) { 473 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " 474 "extension not critical", fn); 475 goto out; 476 } 477 478 if ((addrblk = X509V3_EXT_d2i(ext)) == NULL) { 479 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " 480 "failed extension parse", fn); 481 goto out; 482 } 483 484 if (!sbgp_parse_ipaddrblk(fn, addrblk, &cert->ips, &cert->num_ips)) 485 goto out; 486 487 if (cert->num_ips == 0) { 488 warnx("%s: RFC 6487 section 4.8.10: empty ipAddrBlock", fn); 489 goto out; 490 } 491 492 rc = 1; 493 out: 494 IPAddrBlocks_free(addrblk); 495 return rc; 496 } 497 498 /* 499 * Parse "Subject Information Access" extension for a CA cert, 500 * RFC 6487, section 4.8.8.1 and RFC 8182, section 3.2. 501 * Returns zero on failure, non-zero on success. 502 */ 503 static int 504 sbgp_sia(const char *fn, struct cert *cert, X509_EXTENSION *ext) 505 { 506 AUTHORITY_INFO_ACCESS *sia = NULL; 507 ACCESS_DESCRIPTION *ad; 508 ASN1_OBJECT *oid; 509 const char *mftfilename; 510 char *carepo = NULL, *rpkimft = NULL, *notify = NULL; 511 int i, rc = 0; 512 513 assert(cert->repo == NULL && cert->mft == NULL && cert->notify == NULL); 514 515 if (X509_EXTENSION_get_critical(ext)) { 516 warnx("%s: RFC 6487 section 4.8.8: SIA: " 517 "extension not non-critical", fn); 518 goto out; 519 } 520 521 if ((sia = X509V3_EXT_d2i(ext)) == NULL) { 522 warnx("%s: RFC 6487 section 4.8.8: SIA: failed extension parse", 523 fn); 524 goto out; 525 } 526 527 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) { 528 ad = sk_ACCESS_DESCRIPTION_value(sia, i); 529 530 oid = ad->method; 531 532 if (OBJ_cmp(oid, carepo_oid) == 0) { 533 if (!x509_location(fn, "SIA: caRepository", 534 ad->location, &carepo)) 535 goto out; 536 if (cert->repo == NULL && strncasecmp(carepo, 537 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) { 538 if (carepo[strlen(carepo) - 1] != '/') { 539 char *carepo_tmp; 540 541 if (asprintf(&carepo_tmp, "%s/", 542 carepo) == -1) 543 errx(1, NULL); 544 free(carepo); 545 carepo = carepo_tmp; 546 } 547 548 cert->repo = carepo; 549 carepo = NULL; 550 continue; 551 } 552 if (verbose) 553 warnx("%s: RFC 6487 section 4.8.8: SIA: " 554 "ignoring location %s", fn, carepo); 555 free(carepo); 556 carepo = NULL; 557 } else if (OBJ_cmp(oid, manifest_oid) == 0) { 558 if (!x509_location(fn, "SIA: rpkiManifest", 559 ad->location, &rpkimft)) 560 goto out; 561 if (cert->mft == NULL && strncasecmp(rpkimft, 562 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) { 563 cert->mft = rpkimft; 564 rpkimft = NULL; 565 continue; 566 } 567 if (verbose) 568 warnx("%s: RFC 6487 section 4.8.8: SIA: " 569 "ignoring location %s", fn, rpkimft); 570 free(rpkimft); 571 rpkimft = NULL; 572 } else if (OBJ_cmp(oid, notify_oid) == 0) { 573 if (!x509_location(fn, "SIA: rpkiNotify", 574 ad->location, ¬ify)) 575 goto out; 576 if (strncasecmp(notify, HTTPS_PROTO, 577 HTTPS_PROTO_LEN) != 0) { 578 warnx("%s: non-https uri in rpkiNotify: %s", 579 fn, cert->notify); 580 free(notify); 581 goto out; 582 } 583 if (cert->notify != NULL) { 584 warnx("%s: unexpected rpkiNotify accessMethod", 585 fn); 586 free(notify); 587 goto out; 588 } 589 cert->notify = notify; 590 notify = NULL; 591 } else { 592 char buf[128]; 593 594 OBJ_obj2txt(buf, sizeof(buf), oid, 0); 595 warnx("%s: RFC 6487 section 4.8.8.1: unexpected" 596 " accessMethod: %s", fn, buf); 597 goto out; 598 } 599 } 600 601 if (cert->mft == NULL || cert->repo == NULL) { 602 warnx("%s: RFC 6487 section 4.8.8: SIA: missing caRepository " 603 "or rpkiManifest", fn); 604 goto out; 605 } 606 607 mftfilename = strrchr(cert->mft, '/'); 608 if (mftfilename == NULL) { 609 warnx("%s: SIA: invalid rpkiManifest entry", fn); 610 goto out; 611 } 612 mftfilename++; 613 if (!valid_filename(mftfilename, strlen(mftfilename))) { 614 warnx("%s: SIA: rpkiManifest filename contains invalid " 615 "characters", fn); 616 goto out; 617 } 618 619 if (strstr(cert->mft, cert->repo) != cert->mft || 620 cert->mft + strlen(cert->repo) != mftfilename) { 621 warnx("%s: RFC 6487 section 4.8.8: SIA: " 622 "conflicting URIs for caRepository and rpkiManifest", fn); 623 goto out; 624 } 625 626 if (rtype_from_file_extension(cert->mft) != RTYPE_MFT) { 627 warnx("%s: RFC 6487 section 4.8.8: SIA: not an MFT file", fn); 628 goto out; 629 } 630 631 rc = 1; 632 out: 633 AUTHORITY_INFO_ACCESS_free(sia); 634 return rc; 635 } 636 637 /* 638 * Parse the certificate policies extension and check that it follows RFC 7318. 639 * Returns zero on failure, non-zero on success. 640 */ 641 static int 642 certificate_policies(const char *fn, struct cert *cert, X509_EXTENSION *ext) 643 { 644 STACK_OF(POLICYINFO) *policies = NULL; 645 POLICYINFO *policy; 646 STACK_OF(POLICYQUALINFO) *qualifiers; 647 POLICYQUALINFO *qualifier; 648 int nid; 649 int rc = 0; 650 651 if (!X509_EXTENSION_get_critical(ext)) { 652 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 653 "extension not critical", fn); 654 goto out; 655 } 656 657 if ((policies = X509V3_EXT_d2i(ext)) == NULL) { 658 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 659 "failed extension parse", fn); 660 goto out; 661 } 662 663 if (sk_POLICYINFO_num(policies) != 1) { 664 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 665 "want 1 policy, got %d", fn, sk_POLICYINFO_num(policies)); 666 goto out; 667 } 668 669 policy = sk_POLICYINFO_value(policies, 0); 670 assert(policy != NULL && policy->policyid != NULL); 671 672 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) { 673 char pbuf[128], cbuf[128]; 674 675 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1); 676 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1); 677 warnx("%s: RFC 7318 section 2: certificatePolicies: " 678 "unexpected OID: %s, want %s", fn, pbuf, cbuf); 679 goto out; 680 } 681 682 /* Policy qualifiers are optional. If they're absent, we're done. */ 683 if ((qualifiers = policy->qualifiers) == NULL) { 684 rc = 1; 685 goto out; 686 } 687 688 if (sk_POLICYQUALINFO_num(qualifiers) != 1) { 689 warnx("%s: RFC 7318 section 2: certificatePolicies: " 690 "want 1 policy qualifier, got %d", fn, 691 sk_POLICYQUALINFO_num(qualifiers)); 692 goto out; 693 } 694 695 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0); 696 assert(qualifier != NULL && qualifier->pqualid != NULL); 697 698 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) { 699 warnx("%s: RFC 7318 section 2: certificatePolicies: " 700 "want CPS, got %s", fn, nid2str(nid)); 701 goto out; 702 } 703 704 if (verbose > 1 && !filemode) 705 warnx("%s: CPS %.*s", fn, qualifier->d.cpsuri->length, 706 qualifier->d.cpsuri->data); 707 708 rc = 1; 709 out: 710 sk_POLICYINFO_pop_free(policies, POLICYINFO_free); 711 return rc; 712 } 713 714 static int 715 cert_check_subject_and_issuer(const char *fn, const X509 *x) 716 { 717 const X509_NAME *name; 718 719 if ((name = X509_get_subject_name(x)) == NULL) { 720 warnx("%s: X509_get_subject_name", fn); 721 return 0; 722 } 723 if (!x509_valid_name(fn, "subject", name)) 724 return 0; 725 726 if ((name = X509_get_issuer_name(x)) == NULL) { 727 warnx("%s: X509_get_issuer_name", fn); 728 return 0; 729 } 730 if (!x509_valid_name(fn, "issuer", name)) 731 return 0; 732 733 return 1; 734 } 735 736 /* 737 * Lightweight version of cert_parse_pre() for EE certs. 738 * Parses the two RFC 3779 extensions, and performs some sanity checks. 739 * Returns cert on success and NULL on failure. 740 */ 741 struct cert * 742 cert_parse_ee_cert(const char *fn, int talid, X509 *x) 743 { 744 struct cert *cert; 745 X509_EXTENSION *ext; 746 int index; 747 748 if ((cert = calloc(1, sizeof(struct cert))) == NULL) 749 err(1, NULL); 750 751 if (X509_get_version(x) != 2) { 752 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn); 753 goto out; 754 } 755 756 if (!cert_check_subject_and_issuer(fn, x)) 757 goto out; 758 759 if (!x509_cache_extensions(x, fn)) 760 goto out; 761 762 if ((cert->purpose = x509_get_purpose(x, fn)) != CERT_PURPOSE_EE) { 763 warnx("%s: expected EE cert, got %s", fn, 764 purpose2str(cert->purpose)); 765 goto out; 766 } 767 768 index = X509_get_ext_by_NID(x, NID_sbgp_ipAddrBlock, -1); 769 if ((ext = X509_get_ext(x, index)) != NULL) { 770 if (!sbgp_ipaddrblk(fn, cert, ext)) 771 goto out; 772 } 773 774 index = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1); 775 if ((ext = X509_get_ext(x, index)) != NULL) { 776 if (!sbgp_assysnum(fn, cert, ext)) 777 goto out; 778 } 779 780 if (!X509_up_ref(x)) { 781 warnx("%s: X509_up_ref failed", fn); 782 goto out; 783 } 784 785 cert->x509 = x; 786 cert->talid = talid; 787 788 if (!constraints_validate(fn, cert)) 789 goto out; 790 791 return cert; 792 793 out: 794 cert_free(cert); 795 return NULL; 796 } 797 798 /* 799 * Parse and partially validate an RPKI X509 certificate (either a trust 800 * anchor or a certificate) as defined in RFC 6487. 801 * Returns the parse results or NULL on failure. 802 */ 803 struct cert * 804 cert_parse_pre(const char *fn, const unsigned char *der, size_t len) 805 { 806 struct cert *cert; 807 const unsigned char *oder; 808 size_t j; 809 int i, extsz; 810 X509 *x = NULL; 811 X509_EXTENSION *ext = NULL; 812 const ASN1_BIT_STRING *issuer_uid = NULL, *subject_uid = NULL; 813 ASN1_OBJECT *obj; 814 EVP_PKEY *pkey; 815 int nid, ip, as, sia, cp, crldp, aia, aki, ski, 816 eku, bc, ku; 817 818 nid = ip = as = sia = cp = crldp = aia = aki = ski = eku = bc = ku = 0; 819 820 /* just fail for empty buffers, the warning was printed elsewhere */ 821 if (der == NULL) 822 return NULL; 823 824 if ((cert = calloc(1, sizeof(struct cert))) == NULL) 825 err(1, NULL); 826 827 oder = der; 828 if ((x = d2i_X509(NULL, &der, len)) == NULL) { 829 warnx("%s: d2i_X509", fn); 830 goto out; 831 } 832 if (der != oder + len) { 833 warnx("%s: %td bytes trailing garbage", fn, oder + len - der); 834 goto out; 835 } 836 837 if (!x509_cache_extensions(x, fn)) 838 goto out; 839 840 if (X509_get_version(x) != 2) { 841 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn); 842 goto out; 843 } 844 845 if ((nid = X509_get_signature_nid(x)) == NID_undef) { 846 warnx("%s: unknown signature type", fn); 847 goto out; 848 } 849 if (experimental && nid == NID_ecdsa_with_SHA256) { 850 if (verbose) 851 warnx("%s: P-256 support is experimental", fn); 852 } else if (nid != NID_sha256WithRSAEncryption) { 853 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s", 854 fn, nid2str(nid), LN_sha256WithRSAEncryption); 855 goto out; 856 } 857 858 X509_get0_uids(x, &issuer_uid, &subject_uid); 859 if (issuer_uid != NULL || subject_uid != NULL) { 860 warnx("%s: issuer or subject unique identifiers not allowed", 861 fn); 862 goto out; 863 } 864 865 if (!cert_check_subject_and_issuer(fn, x)) 866 goto out; 867 868 /* Look for X509v3 extensions. */ 869 if ((extsz = X509_get_ext_count(x)) <= 0) { 870 warnx("%s: certificate without X.509v3 extensions", fn); 871 goto out; 872 } 873 874 for (i = 0; i < extsz; i++) { 875 ext = X509_get_ext(x, i); 876 assert(ext != NULL); 877 obj = X509_EXTENSION_get_object(ext); 878 assert(obj != NULL); 879 880 switch (nid = OBJ_obj2nid(obj)) { 881 case NID_sbgp_ipAddrBlock: 882 if (ip++ > 0) 883 goto dup; 884 if (!sbgp_ipaddrblk(fn, cert, ext)) 885 goto out; 886 break; 887 case NID_sbgp_autonomousSysNum: 888 if (as++ > 0) 889 goto dup; 890 if (!sbgp_assysnum(fn, cert, ext)) 891 goto out; 892 break; 893 case NID_sinfo_access: 894 if (sia++ > 0) 895 goto dup; 896 /* 897 * This will fail for BGPsec certs, but they must omit 898 * this extension anyway (RFC 8209, section 3.1.3.3). 899 */ 900 if (!sbgp_sia(fn, cert, ext)) 901 goto out; 902 break; 903 case NID_certificate_policies: 904 if (cp++ > 0) 905 goto dup; 906 if (!certificate_policies(fn, cert, ext)) 907 goto out; 908 break; 909 case NID_crl_distribution_points: 910 if (crldp++ > 0) 911 goto dup; 912 break; 913 case NID_info_access: 914 if (aia++ > 0) 915 goto dup; 916 break; 917 case NID_authority_key_identifier: 918 if (aki++ > 0) 919 goto dup; 920 break; 921 case NID_subject_key_identifier: 922 if (ski++ > 0) 923 goto dup; 924 break; 925 case NID_ext_key_usage: 926 if (eku++ > 0) 927 goto dup; 928 break; 929 case NID_basic_constraints: 930 if (bc++ > 0) 931 goto dup; 932 break; 933 case NID_key_usage: 934 if (ku++ > 0) 935 goto dup; 936 break; 937 default: 938 /* unexpected extensions warrant investigation */ 939 { 940 char objn[64]; 941 OBJ_obj2txt(objn, sizeof(objn), obj, 0); 942 warnx("%s: ignoring %s (NID %d)", 943 fn, objn, OBJ_obj2nid(obj)); 944 } 945 break; 946 } 947 } 948 949 if (!x509_get_aki(x, fn, &cert->aki)) 950 goto out; 951 if (!x509_get_ski(x, fn, &cert->ski)) 952 goto out; 953 if (!x509_get_aia(x, fn, &cert->aia)) 954 goto out; 955 if (!x509_get_crl(x, fn, &cert->crl)) 956 goto out; 957 if (!x509_get_notbefore(x, fn, &cert->notbefore)) 958 goto out; 959 if (!x509_get_notafter(x, fn, &cert->notafter)) 960 goto out; 961 962 /* Validation on required fields. */ 963 cert->purpose = x509_get_purpose(x, fn); 964 switch (cert->purpose) { 965 case CERT_PURPOSE_TA: 966 /* XXX - caller should indicate if it expects TA or CA cert */ 967 case CERT_PURPOSE_CA: 968 if ((pkey = X509_get0_pubkey(x)) == NULL) { 969 warnx("%s: X509_get0_pubkey failed", fn); 970 goto out; 971 } 972 if (!valid_ca_pkey(fn, pkey)) 973 goto out; 974 975 if (cert->mft == NULL) { 976 warnx("%s: RFC 6487 section 4.8.8: missing SIA", fn); 977 goto out; 978 } 979 if (cert->num_ases == 0 && cert->num_ips == 0) { 980 warnx("%s: missing IP or AS resources", fn); 981 goto out; 982 } 983 break; 984 case CERT_PURPOSE_BGPSEC_ROUTER: 985 cert->pubkey = x509_get_pubkey(x, fn); 986 if (cert->pubkey == NULL) { 987 warnx("%s: x509_get_pubkey failed", fn); 988 goto out; 989 } 990 if (cert->num_ips > 0) { 991 warnx("%s: unexpected IP resources in BGPsec cert", fn); 992 goto out; 993 } 994 for (j = 0; j < cert->num_ases; j++) { 995 if (cert->ases[j].type == CERT_AS_INHERIT) { 996 warnx("%s: inherit elements not allowed in EE" 997 " cert", fn); 998 goto out; 999 } 1000 } 1001 if (sia) { 1002 warnx("%s: unexpected SIA extension in BGPsec cert", 1003 fn); 1004 goto out; 1005 } 1006 break; 1007 case CERT_PURPOSE_EE: 1008 warn("%s: unexpected EE cert", fn); 1009 goto out; 1010 default: 1011 warnx("%s: x509_get_purpose failed in %s", fn, __func__); 1012 goto out; 1013 } 1014 1015 if (cert->ski == NULL) { 1016 warnx("%s: RFC 6487 section 8.4.2: missing SKI", fn); 1017 goto out; 1018 } 1019 1020 cert->x509 = x; 1021 return cert; 1022 1023 dup: 1024 warnx("%s: RFC 5280 section 4.2: duplicate extension: %s", fn, 1025 nid2str(nid)); 1026 out: 1027 cert_free(cert); 1028 X509_free(x); 1029 return NULL; 1030 } 1031 1032 struct cert * 1033 cert_parse(const char *fn, struct cert *p) 1034 { 1035 if (p == NULL) 1036 return NULL; 1037 1038 if (p->aki == NULL) { 1039 warnx("%s: RFC 6487 section 8.4.2: " 1040 "non-trust anchor missing AKI", fn); 1041 goto badcert; 1042 } 1043 if (strcmp(p->aki, p->ski) == 0) { 1044 warnx("%s: RFC 6487 section 8.4.2: " 1045 "non-trust anchor AKI may not match SKI", fn); 1046 goto badcert; 1047 } 1048 if (p->aia == NULL) { 1049 warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn); 1050 goto badcert; 1051 } 1052 if (p->crl == NULL) { 1053 warnx("%s: RFC 6487 section 4.8.6: CRL: " 1054 "no CRL distribution point extension", fn); 1055 goto badcert; 1056 } 1057 return p; 1058 1059 badcert: 1060 cert_free(p); 1061 return NULL; 1062 } 1063 1064 /* 1065 * Reject TA certificates with an overly long validity period. 1066 * 1067 * The schedule is as follows: 1068 * Before February 2nd, 2026, warn on TA certs valid for longer than 15 years. 1069 * After February 2nd, 2026, reject TA certs valid for longer than 15 years. 1070 * Before March 3rd, 2027, warn on TA certs valid for longer than 3 years. 1071 * After March 3rd, 2027, reject TA certs valid for longer than 3 years. 1072 * 1073 * Return 1 if the validity period is acceptable and 0 otherwise. 1074 */ 1075 static int 1076 ta_check_validity(const char *fn, const struct cert *p, time_t now) 1077 { 1078 time_t validity = p->notafter - p->notbefore; 1079 time_t cutoff_15y = 1769990400; /* 2026-02-02T00:00:00Z */ 1080 time_t cutoff_3y = 1804032000; /* 2027-03-03T00:00:00Z */ 1081 time_t cutoff = cutoff_3y; 1082 int warn_years = 3; 1083 int exceeds_15y = 0, exceeds_3y = 0; 1084 int complain = 0, acceptable = 1; 1085 1086 if (validity >= 15 * 365 * 86400) 1087 exceeds_15y = 1; 1088 if (validity >= 3 * 365 * 86400) 1089 exceeds_3y = 1; 1090 1091 if (now < cutoff_15y) { 1092 warn_years = 15; 1093 cutoff = cutoff_15y; 1094 if (exceeds_15y) 1095 complain = 1; 1096 } else if (now < cutoff_3y) { 1097 if (exceeds_15y) 1098 acceptable = 0; 1099 if (exceeds_3y) 1100 complain = 1; 1101 } else if (exceeds_3y) { 1102 acceptable = 0; 1103 complain = 1; 1104 } 1105 1106 /* 1107 * Suppress warnings for previously fetched TA certs. 1108 */ 1109 if (verbose == 0 && strncmp(fn, "ta/", strlen("ta/")) == 0) 1110 goto out; 1111 1112 if (!acceptable) { 1113 warnx("%s: TA cert rejected: validity period exceeds %d years. " 1114 "Ask the TA operator to reissue their TA cert with a " 1115 "shorter validity period.", fn, warn_years); 1116 goto out; 1117 } 1118 1119 if (complain) { 1120 warnx("%s: TA validity period exceeds %d years. After %s this " 1121 "certificate will be rejected.", fn, warn_years, 1122 time2str(cutoff)); 1123 goto out; 1124 } 1125 1126 out: 1127 return acceptable; 1128 } 1129 1130 struct cert * 1131 ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, 1132 size_t pkeysz) 1133 { 1134 EVP_PKEY *pk, *opk; 1135 time_t now = get_current_time(); 1136 1137 if (p == NULL) 1138 return NULL; 1139 1140 /* first check pubkey against the one from the TAL */ 1141 pk = d2i_PUBKEY(NULL, &pkey, pkeysz); 1142 if (pk == NULL) { 1143 warnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn); 1144 goto badcert; 1145 } 1146 if ((opk = X509_get0_pubkey(p->x509)) == NULL) { 1147 warnx("%s: RFC 6487 (trust anchor): missing pubkey", fn); 1148 goto badcert; 1149 } 1150 if (EVP_PKEY_cmp(pk, opk) != 1) { 1151 warnx("%s: RFC 6487 (trust anchor): " 1152 "pubkey does not match TAL pubkey", fn); 1153 goto badcert; 1154 } 1155 1156 if (p->notbefore > now) { 1157 warnx("%s: certificate not yet valid", fn); 1158 goto badcert; 1159 } 1160 if (p->notafter < now) { 1161 warnx("%s: certificate has expired", fn); 1162 goto badcert; 1163 } 1164 if (!ta_check_validity(fn, p, now)) 1165 goto badcert; 1166 1167 if (p->aki != NULL && strcmp(p->aki, p->ski)) { 1168 warnx("%s: RFC 6487 section 4.8.3: " 1169 "trust anchor AKI, if specified, must match SKI", fn); 1170 goto badcert; 1171 } 1172 if (p->aia != NULL) { 1173 warnx("%s: RFC 6487 section 4.8.7: " 1174 "trust anchor must not have AIA", fn); 1175 goto badcert; 1176 } 1177 if (p->crl != NULL) { 1178 warnx("%s: RFC 6487 section 4.8.6: " 1179 "trust anchor may not specify CRL resource", fn); 1180 goto badcert; 1181 } 1182 if (p->purpose != CERT_PURPOSE_TA) { 1183 warnx("%s: expected trust anchor purpose, got %s", fn, 1184 purpose2str(p->purpose)); 1185 goto badcert; 1186 } 1187 /* 1188 * Do not replace with a <= 0 check since OpenSSL 3 broke that: 1189 * https://github.com/openssl/openssl/issues/24575 1190 */ 1191 if (X509_verify(p->x509, pk) != 1) { 1192 warnx("%s: failed to verify signature", fn); 1193 goto badcert; 1194 } 1195 if (x509_any_inherits(p->x509)) { 1196 warnx("%s: Trust anchor IP/AS resources may not inherit", fn); 1197 goto badcert; 1198 } 1199 1200 EVP_PKEY_free(pk); 1201 return p; 1202 1203 badcert: 1204 EVP_PKEY_free(pk); 1205 cert_free(p); 1206 return NULL; 1207 } 1208 1209 /* 1210 * Free parsed certificate contents. 1211 * Passing NULL is a noop. 1212 */ 1213 void 1214 cert_free(struct cert *p) 1215 { 1216 if (p == NULL) 1217 return; 1218 1219 free(p->crl); 1220 free(p->repo); 1221 free(p->mft); 1222 free(p->notify); 1223 free(p->ips); 1224 free(p->ases); 1225 free(p->aia); 1226 free(p->aki); 1227 free(p->ski); 1228 free(p->pubkey); 1229 X509_free(p->x509); 1230 free(p); 1231 } 1232 1233 /* 1234 * Write certificate parsed content into buffer. 1235 * See cert_read() for the other side of the pipe. 1236 */ 1237 void 1238 cert_buffer(struct ibuf *b, const struct cert *p) 1239 { 1240 io_simple_buffer(b, &p->notafter, sizeof(p->notafter)); 1241 io_simple_buffer(b, &p->purpose, sizeof(p->purpose)); 1242 io_simple_buffer(b, &p->talid, sizeof(p->talid)); 1243 io_simple_buffer(b, &p->certid, sizeof(p->certid)); 1244 io_simple_buffer(b, &p->repoid, sizeof(p->repoid)); 1245 io_simple_buffer(b, &p->num_ips, sizeof(p->num_ips)); 1246 io_simple_buffer(b, &p->num_ases, sizeof(p->num_ases)); 1247 1248 io_simple_buffer(b, p->ips, p->num_ips * sizeof(p->ips[0])); 1249 io_simple_buffer(b, p->ases, p->num_ases * sizeof(p->ases[0])); 1250 1251 io_str_buffer(b, p->mft); 1252 io_str_buffer(b, p->notify); 1253 io_str_buffer(b, p->repo); 1254 io_str_buffer(b, p->crl); 1255 io_str_buffer(b, p->aia); 1256 io_str_buffer(b, p->aki); 1257 io_str_buffer(b, p->ski); 1258 io_str_buffer(b, p->pubkey); 1259 } 1260 1261 /* 1262 * Allocate and read parsed certificate content from descriptor. 1263 * The pointer must be freed with cert_free(). 1264 * Always returns a valid pointer. 1265 */ 1266 struct cert * 1267 cert_read(struct ibuf *b) 1268 { 1269 struct cert *p; 1270 1271 if ((p = calloc(1, sizeof(struct cert))) == NULL) 1272 err(1, NULL); 1273 1274 io_read_buf(b, &p->notafter, sizeof(p->notafter)); 1275 io_read_buf(b, &p->purpose, sizeof(p->purpose)); 1276 io_read_buf(b, &p->talid, sizeof(p->talid)); 1277 io_read_buf(b, &p->certid, sizeof(p->certid)); 1278 io_read_buf(b, &p->repoid, sizeof(p->repoid)); 1279 io_read_buf(b, &p->num_ips, sizeof(p->num_ips)); 1280 io_read_buf(b, &p->num_ases, sizeof(p->num_ases)); 1281 1282 if (p->num_ips > 0) { 1283 if ((p->ips = calloc(p->num_ips, sizeof(p->ips[0]))) == NULL) 1284 err(1, NULL); 1285 io_read_buf(b, p->ips, p->num_ips * sizeof(p->ips[0])); 1286 } 1287 1288 if (p->num_ases > 0) { 1289 if ((p->ases = calloc(p->num_ases, sizeof(p->ases[0]))) == NULL) 1290 err(1, NULL); 1291 io_read_buf(b, p->ases, p->num_ases * sizeof(p->ases[0])); 1292 } 1293 1294 io_read_str(b, &p->mft); 1295 io_read_str(b, &p->notify); 1296 io_read_str(b, &p->repo); 1297 io_read_str(b, &p->crl); 1298 io_read_str(b, &p->aia); 1299 io_read_str(b, &p->aki); 1300 io_read_str(b, &p->ski); 1301 io_read_str(b, &p->pubkey); 1302 1303 assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER); 1304 assert(p->ski); 1305 return p; 1306 } 1307 1308 static inline int 1309 authcmp(struct auth *a, struct auth *b) 1310 { 1311 if (a->cert->certid > b->cert->certid) 1312 return 1; 1313 if (a->cert->certid < b->cert->certid) 1314 return -1; 1315 return 0; 1316 } 1317 1318 RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp); 1319 1320 void 1321 auth_tree_free(struct auth_tree *auths) 1322 { 1323 struct auth *auth, *tauth; 1324 1325 RB_FOREACH_SAFE(auth, auth_tree, auths, tauth) { 1326 RB_REMOVE(auth_tree, auths, auth); 1327 cert_free(auth->cert); 1328 free(auth); 1329 } 1330 } 1331 1332 struct auth * 1333 auth_find(struct auth_tree *auths, int id) 1334 { 1335 struct auth a; 1336 struct cert c; 1337 1338 c.certid = id; 1339 a.cert = &c; 1340 1341 return RB_FIND(auth_tree, auths, &a); 1342 } 1343 1344 struct auth * 1345 auth_insert(const char *fn, struct auth_tree *auths, struct cert *cert, 1346 struct auth *issuer) 1347 { 1348 struct auth *na; 1349 1350 na = calloc(1, sizeof(*na)); 1351 if (na == NULL) 1352 err(1, NULL); 1353 1354 if (issuer == NULL) { 1355 cert->certid = cert->talid; 1356 } else { 1357 cert->certid = ++certid; 1358 if (certid > CERTID_MAX) { 1359 if (certid == CERTID_MAX + 1) 1360 warnx("%s: too many certificates in store", fn); 1361 free(na); 1362 return NULL; 1363 } 1364 na->depth = issuer->depth + 1; 1365 } 1366 1367 if (na->depth >= MAX_CERT_DEPTH) { 1368 warnx("%s: maximum certificate chain depth exhausted", fn); 1369 free(na); 1370 return NULL; 1371 } 1372 1373 na->issuer = issuer; 1374 na->cert = cert; 1375 na->any_inherits = x509_any_inherits(cert->x509); 1376 1377 if (RB_INSERT(auth_tree, auths, na) != NULL) 1378 errx(1, "auth tree corrupted"); 1379 1380 return na; 1381 } 1382 1383 static void 1384 insert_brk(struct brk_tree *tree, struct cert *cert, int asid) 1385 { 1386 struct brk *b, *found; 1387 1388 if ((b = calloc(1, sizeof(*b))) == NULL) 1389 err(1, NULL); 1390 1391 b->asid = asid; 1392 b->expires = cert->notafter; 1393 b->talid = cert->talid; 1394 if ((b->ski = strdup(cert->ski)) == NULL) 1395 err(1, NULL); 1396 if ((b->pubkey = strdup(cert->pubkey)) == NULL) 1397 err(1, NULL); 1398 1399 /* 1400 * Check if a similar BRK already exists in the tree. If the found BRK 1401 * expires sooner, update it to this BRK's later expiry moment. 1402 */ 1403 if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) { 1404 if (found->expires < b->expires) { 1405 found->expires = b->expires; 1406 found->talid = b->talid; 1407 } 1408 free(b->ski); 1409 free(b->pubkey); 1410 free(b); 1411 } 1412 } 1413 1414 /* 1415 * Add each BGPsec Router Key into the BRK tree. 1416 */ 1417 void 1418 cert_insert_brks(struct brk_tree *tree, struct cert *cert) 1419 { 1420 size_t i, asid; 1421 1422 for (i = 0; i < cert->num_ases; i++) { 1423 switch (cert->ases[i].type) { 1424 case CERT_AS_ID: 1425 insert_brk(tree, cert, cert->ases[i].id); 1426 break; 1427 case CERT_AS_RANGE: 1428 for (asid = cert->ases[i].range.min; 1429 asid <= cert->ases[i].range.max; asid++) 1430 insert_brk(tree, cert, asid); 1431 break; 1432 default: 1433 warnx("invalid AS identifier type"); 1434 continue; 1435 } 1436 } 1437 } 1438 1439 static inline int 1440 brkcmp(struct brk *a, struct brk *b) 1441 { 1442 int rv; 1443 1444 if (a->asid > b->asid) 1445 return 1; 1446 if (a->asid < b->asid) 1447 return -1; 1448 1449 rv = strcmp(a->ski, b->ski); 1450 if (rv > 0) 1451 return 1; 1452 if (rv < 0) 1453 return -1; 1454 1455 return strcmp(a->pubkey, b->pubkey); 1456 } 1457 1458 RB_GENERATE(brk_tree, brk, entry, brkcmp); 1459