1/* $OpenBSD: cert.c,v 1.148 2024/06/12 10:03:09 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 32extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ 33extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ 34extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ 35extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ 36 37int 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 */ 50static int 51append_ip(const char *fn, struct cert_ip *ips, size_t *ipsz, 52 const struct cert_ip *ip) 53{ 54 if (!ip_addr_check_overlap(ip, fn, ips, *ipsz, 0)) 55 return 0; 56 ips[(*ipsz)++] = *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 */ 65static int 66append_as(const char *fn, struct cert_as *ases, size_t *asz, 67 const struct cert_as *as) 68{ 69 if (!as_check_overlap(as, fn, ases, *asz, 0)) 70 return 0; 71 ases[(*asz)++] = *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 */ 79int 80sbgp_as_range(const char *fn, struct cert_as *ases, size_t *asz, 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, asz, &as); 111} 112 113/* 114 * Parse an entire 3.2.3.10 integer type. 115 */ 116int 117sbgp_as_id(const char *fn, struct cert_as *ases, size_t *asz, 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, asz, &as); 137} 138 139static int 140sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *asz) 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, asz, &as); 148} 149 150int 151sbgp_parse_assysnum(const char *fn, const ASIdentifiers *asidentifiers, 152 struct cert_as **out_as, size_t *out_asz) 153{ 154 const ASIdOrRanges *aors = NULL; 155 struct cert_as *as = NULL; 156 size_t asz = 0, sz; 157 int i; 158 159 assert(*out_as == NULL && *out_asz == 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 sz = 1; 176 break; 177 case ASIdentifierChoice_asIdsOrRanges: 178 aors = asidentifiers->asnum->u.asIdsOrRanges; 179 sz = 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 (sz == 0) { 188 warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn); 189 goto out; 190 } 191 if (sz >= 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(sz, sizeof(struct cert_as)); 197 if (as == NULL) 198 err(1, NULL); 199 200 if (aors == NULL) { 201 if (!sbgp_as_inherit(fn, as, &asz)) 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, &asz, aor->u.id)) 212 goto out; 213 break; 214 case ASIdOrRange_range: 215 if (!sbgp_as_range(fn, as, &asz, 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_asz = asz; 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 */ 241static int 242sbgp_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->as, &cert->asz)) 260 goto out; 261 262 rc = 1; 263 out: 264 ASIdentifiers_free(asidentifiers); 265 return rc; 266} 267 268/* 269 * Construct a RFC 3779 2.2.3.8 range from its bit string. 270 * Returns zero on failure, non-zero on success. 271 */ 272int 273sbgp_addr(const char *fn, struct cert_ip *ips, size_t *ipsz, enum afi afi, 274 const ASN1_BIT_STRING *bs) 275{ 276 struct cert_ip ip; 277 278 memset(&ip, 0, sizeof(struct cert_ip)); 279 280 ip.afi = afi; 281 ip.type = CERT_IP_ADDR; 282 283 if (!ip_addr_parse(bs, afi, fn, &ip.ip)) { 284 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: " 285 "invalid IP address", fn); 286 return 0; 287 } 288 289 if (!ip_cert_compose_ranges(&ip)) { 290 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: " 291 "IP address range reversed", fn); 292 return 0; 293 } 294 295 return append_ip(fn, ips, ipsz, &ip); 296} 297 298/* 299 * Parse RFC 3779 2.2.3.9 range of addresses. 300 * Returns zero on failure, non-zero on success. 301 */ 302int 303sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *ipsz, 304 enum afi afi, const IPAddressRange *range) 305{ 306 struct cert_ip ip; 307 308 memset(&ip, 0, sizeof(struct cert_ip)); 309 310 ip.afi = afi; 311 ip.type = CERT_IP_RANGE; 312 313 if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) { 314 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 315 "invalid IP address", fn); 316 return 0; 317 } 318 319 if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) { 320 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 321 "invalid IP address", fn); 322 return 0; 323 } 324 325 if (!ip_cert_compose_ranges(&ip)) { 326 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: " 327 "IP address range reversed", fn); 328 return 0; 329 } 330 331 return append_ip(fn, ips, ipsz, &ip); 332} 333 334static int 335sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *ipsz, 336 enum afi afi) 337{ 338 struct cert_ip ip; 339 340 memset(&ip, 0, sizeof(struct cert_ip)); 341 342 ip.afi = afi; 343 ip.type = CERT_IP_INHERIT; 344 345 return append_ip(fn, ips, ipsz, &ip); 346} 347 348int 349sbgp_parse_ipaddrblk(const char *fn, const IPAddrBlocks *addrblk, 350 struct cert_ip **out_ips, size_t *out_ipsz) 351{ 352 const IPAddressFamily *af; 353 const IPAddressOrRanges *aors; 354 const IPAddressOrRange *aor; 355 enum afi afi; 356 struct cert_ip *ips = NULL; 357 size_t ipsz = 0, sz; 358 int ipv4_seen = 0, ipv6_seen = 0; 359 int i, j, ipaddrblocksz; 360 361 assert(*out_ips == NULL && *out_ipsz == 0); 362 363 ipaddrblocksz = sk_IPAddressFamily_num(addrblk); 364 if (ipaddrblocksz != 1 && ipaddrblocksz != 2) { 365 warnx("%s: RFC 6487 section 4.8.10: unexpected number of " 366 "ipAddrBlocks (got %d, expected 1 or 2)", 367 fn, ipaddrblocksz); 368 goto out; 369 } 370 371 for (i = 0; i < ipaddrblocksz; i++) { 372 af = sk_IPAddressFamily_value(addrblk, i); 373 374 switch (af->ipAddressChoice->type) { 375 case IPAddressChoice_inherit: 376 aors = NULL; 377 sz = ipsz + 1; 378 break; 379 case IPAddressChoice_addressesOrRanges: 380 aors = af->ipAddressChoice->u.addressesOrRanges; 381 sz = ipsz + sk_IPAddressOrRange_num(aors); 382 break; 383 default: 384 warnx("%s: RFC 3779: IPAddressChoice: unknown type %d", 385 fn, af->ipAddressChoice->type); 386 goto out; 387 } 388 if (sz == ipsz) { 389 warnx("%s: RFC 6487 section 4.8.10: " 390 "empty ipAddressesOrRanges", fn); 391 goto out; 392 } 393 394 if (sz >= MAX_IP_SIZE) 395 goto out; 396 ips = recallocarray(ips, ipsz, sz, sizeof(struct cert_ip)); 397 if (ips == NULL) 398 err(1, NULL); 399 400 if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) { 401 warnx("%s: RFC 3779: invalid AFI", fn); 402 goto out; 403 } 404 405 switch (afi) { 406 case AFI_IPV4: 407 if (ipv4_seen++ > 0) { 408 warnx("%s: RFC 6487 section 4.8.10: " 409 "IPv4 appears twice", fn); 410 goto out; 411 } 412 break; 413 case AFI_IPV6: 414 if (ipv6_seen++ > 0) { 415 warnx("%s: RFC 6487 section 4.8.10: " 416 "IPv6 appears twice", fn); 417 goto out; 418 } 419 break; 420 } 421 422 if (aors == NULL) { 423 if (!sbgp_addr_inherit(fn, ips, &ipsz, afi)) 424 goto out; 425 continue; 426 } 427 428 for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) { 429 aor = sk_IPAddressOrRange_value(aors, j); 430 switch (aor->type) { 431 case IPAddressOrRange_addressPrefix: 432 if (!sbgp_addr(fn, ips, &ipsz, afi, 433 aor->u.addressPrefix)) 434 goto out; 435 break; 436 case IPAddressOrRange_addressRange: 437 if (!sbgp_addr_range(fn, ips, &ipsz, afi, 438 aor->u.addressRange)) 439 goto out; 440 break; 441 default: 442 warnx("%s: RFC 3779: IPAddressOrRange: " 443 "unknown type %d", fn, aor->type); 444 goto out; 445 } 446 } 447 } 448 449 *out_ips = ips; 450 *out_ipsz = ipsz; 451 452 return 1; 453 454 out: 455 free(ips); 456 457 return 0; 458} 459 460/* 461 * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with 462 * syntax documented in RFC 3779 starting in section 2.2. 463 * Returns zero on failure, non-zero on success. 464 */ 465static int 466sbgp_ipaddrblk(const char *fn, struct cert *cert, X509_EXTENSION *ext) 467{ 468 IPAddrBlocks *addrblk = NULL; 469 int rc = 0; 470 471 if (!X509_EXTENSION_get_critical(ext)) { 472 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " 473 "extension not critical", fn); 474 goto out; 475 } 476 477 if ((addrblk = X509V3_EXT_d2i(ext)) == NULL) { 478 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: " 479 "failed extension parse", fn); 480 goto out; 481 } 482 483 if (!sbgp_parse_ipaddrblk(fn, addrblk, &cert->ips, &cert->ipsz)) 484 goto out; 485 486 if (cert->ipsz == 0) { 487 warnx("%s: RFC 6487 section 4.8.10: empty ipAddrBlock", fn); 488 goto out; 489 } 490 491 rc = 1; 492 out: 493 IPAddrBlocks_free(addrblk); 494 return rc; 495} 496 497/* 498 * Parse "Subject Information Access" extension for a CA cert, 499 * RFC 6487, section 4.8.8.1 and RFC 8182, section 3.2. 500 * Returns zero on failure, non-zero on success. 501 */ 502static int 503sbgp_sia(const char *fn, struct cert *cert, X509_EXTENSION *ext) 504{ 505 AUTHORITY_INFO_ACCESS *sia = NULL; 506 ACCESS_DESCRIPTION *ad; 507 ASN1_OBJECT *oid; 508 const char *mftfilename; 509 char *carepo = NULL, *rpkimft = NULL, *notify = NULL; 510 int i, rc = 0; 511 512 assert(cert->repo == NULL && cert->mft == NULL && cert->notify == NULL); 513 514 if (X509_EXTENSION_get_critical(ext)) { 515 warnx("%s: RFC 6487 section 4.8.8: SIA: " 516 "extension not non-critical", fn); 517 goto out; 518 } 519 520 if ((sia = X509V3_EXT_d2i(ext)) == NULL) { 521 warnx("%s: RFC 6487 section 4.8.8: SIA: failed extension parse", 522 fn); 523 goto out; 524 } 525 526 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) { 527 ad = sk_ACCESS_DESCRIPTION_value(sia, i); 528 529 oid = ad->method; 530 531 if (OBJ_cmp(oid, carepo_oid) == 0) { 532 if (!x509_location(fn, "SIA: caRepository", 533 ad->location, &carepo)) 534 goto out; 535 if (cert->repo == NULL && strncasecmp(carepo, 536 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) { 537 cert->repo = carepo; 538 carepo = NULL; 539 continue; 540 } 541 if (verbose) 542 warnx("%s: RFC 6487 section 4.8.8: SIA: " 543 "ignoring location %s", fn, carepo); 544 free(carepo); 545 carepo = NULL; 546 } else if (OBJ_cmp(oid, manifest_oid) == 0) { 547 if (!x509_location(fn, "SIA: rpkiManifest", 548 ad->location, &rpkimft)) 549 goto out; 550 if (cert->mft == NULL && strncasecmp(rpkimft, 551 RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) { 552 cert->mft = rpkimft; 553 rpkimft = NULL; 554 continue; 555 } 556 if (verbose) 557 warnx("%s: RFC 6487 section 4.8.8: SIA: " 558 "ignoring location %s", fn, rpkimft); 559 free(rpkimft); 560 rpkimft = NULL; 561 } else if (OBJ_cmp(oid, notify_oid) == 0) { 562 if (!x509_location(fn, "SIA: rpkiNotify", 563 ad->location, ¬ify)) 564 goto out; 565 if (strncasecmp(notify, HTTPS_PROTO, 566 HTTPS_PROTO_LEN) != 0) { 567 warnx("%s: non-https uri in rpkiNotify: %s", 568 fn, cert->notify); 569 free(notify); 570 goto out; 571 } 572 if (cert->notify != NULL) { 573 warnx("%s: unexpected rpkiNotify accessMethod", 574 fn); 575 free(notify); 576 goto out; 577 } 578 cert->notify = notify; 579 notify = NULL; 580 } else { 581 char buf[128]; 582 583 OBJ_obj2txt(buf, sizeof(buf), oid, 0); 584 warnx("%s: RFC 6487 section 4.8.8.1: unexpected" 585 " accessMethod: %s", fn, buf); 586 goto out; 587 } 588 } 589 590 if (cert->mft == NULL || cert->repo == NULL) { 591 warnx("%s: RFC 6487 section 4.8.8: SIA: missing caRepository " 592 "or rpkiManifest", fn); 593 goto out; 594 } 595 596 mftfilename = strrchr(cert->mft, '/'); 597 if (mftfilename == NULL) { 598 warnx("%s: SIA: invalid rpkiManifest entry", fn); 599 goto out; 600 } 601 mftfilename++; 602 if (!valid_filename(mftfilename, strlen(mftfilename))) { 603 warnx("%s: SIA: rpkiManifest filename contains invalid " 604 "characters", fn); 605 goto out; 606 } 607 608 if (strstr(cert->mft, cert->repo) != cert->mft) { 609 warnx("%s: RFC 6487 section 4.8.8: SIA: " 610 "conflicting URIs for caRepository and rpkiManifest", fn); 611 goto out; 612 } 613 614 if (rtype_from_file_extension(cert->mft) != RTYPE_MFT) { 615 warnx("%s: RFC 6487 section 4.8.8: SIA: not an MFT file", fn); 616 goto out; 617 } 618 619 rc = 1; 620 out: 621 AUTHORITY_INFO_ACCESS_free(sia); 622 return rc; 623} 624 625/* 626 * Parse the certificate policies extension and check that it follows RFC 7318. 627 * Returns zero on failure, non-zero on success. 628 */ 629static int 630certificate_policies(const char *fn, struct cert *cert, X509_EXTENSION *ext) 631{ 632 STACK_OF(POLICYINFO) *policies = NULL; 633 POLICYINFO *policy; 634 STACK_OF(POLICYQUALINFO) *qualifiers; 635 POLICYQUALINFO *qualifier; 636 int nid; 637 int rc = 0; 638 639 if (!X509_EXTENSION_get_critical(ext)) { 640 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 641 "extension not critical", fn); 642 goto out; 643 } 644 645 if ((policies = X509V3_EXT_d2i(ext)) == NULL) { 646 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 647 "failed extension parse", fn); 648 goto out; 649 } 650 651 if (sk_POLICYINFO_num(policies) != 1) { 652 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: " 653 "want 1 policy, got %d", fn, sk_POLICYINFO_num(policies)); 654 goto out; 655 } 656 657 policy = sk_POLICYINFO_value(policies, 0); 658 assert(policy != NULL && policy->policyid != NULL); 659 660 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) { 661 char pbuf[128], cbuf[128]; 662 663 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1); 664 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1); 665 warnx("%s: RFC 7318 section 2: certificatePolicies: " 666 "unexpected OID: %s, want %s", fn, pbuf, cbuf); 667 goto out; 668 } 669 670 /* Policy qualifiers are optional. If they're absent, we're done. */ 671 if ((qualifiers = policy->qualifiers) == NULL) { 672 rc = 1; 673 goto out; 674 } 675 676 if (sk_POLICYQUALINFO_num(qualifiers) != 1) { 677 warnx("%s: RFC 7318 section 2: certificatePolicies: " 678 "want 1 policy qualifier, got %d", fn, 679 sk_POLICYQUALINFO_num(qualifiers)); 680 goto out; 681 } 682 683 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0); 684 assert(qualifier != NULL && qualifier->pqualid != NULL); 685 686 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) { 687 warnx("%s: RFC 7318 section 2: certificatePolicies: " 688 "want CPS, got %s", fn, nid2str(nid)); 689 goto out; 690 } 691 692 if (verbose > 1 && !filemode) 693 warnx("%s: CPS %.*s", fn, qualifier->d.cpsuri->length, 694 qualifier->d.cpsuri->data); 695 696 rc = 1; 697 out: 698 sk_POLICYINFO_pop_free(policies, POLICYINFO_free); 699 return rc; 700} 701 702static int 703cert_check_subject_and_issuer(const char *fn, const X509 *x) 704{ 705 const X509_NAME *name; 706 707 if ((name = X509_get_subject_name(x)) == NULL) { 708 warnx("%s: X509_get_subject_name", fn); 709 return 0; 710 } 711 if (!x509_valid_name(fn, "subject", name)) 712 return 0; 713 714 if ((name = X509_get_issuer_name(x)) == NULL) { 715 warnx("%s: X509_get_issuer_name", fn); 716 return 0; 717 } 718 if (!x509_valid_name(fn, "issuer", name)) 719 return 0; 720 721 return 1; 722} 723 724/* 725 * Lightweight version of cert_parse_pre() for EE certs. 726 * Parses the two RFC 3779 extensions, and performs some sanity checks. 727 * Returns cert on success and NULL on failure. 728 */ 729struct cert * 730cert_parse_ee_cert(const char *fn, int talid, X509 *x) 731{ 732 struct cert *cert; 733 X509_EXTENSION *ext; 734 int index; 735 736 if ((cert = calloc(1, sizeof(struct cert))) == NULL) 737 err(1, NULL); 738 739 if (X509_get_version(x) != 2) { 740 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn); 741 goto out; 742 } 743 744 if (!cert_check_subject_and_issuer(fn, x)) 745 goto out; 746 747 if (!x509_cache_extensions(x, fn)) 748 goto out; 749 750 if ((cert->purpose = x509_get_purpose(x, fn)) != CERT_PURPOSE_EE) { 751 warnx("%s: expected EE cert, got %s", fn, 752 purpose2str(cert->purpose)); 753 goto out; 754 } 755 756 index = X509_get_ext_by_NID(x, NID_sbgp_ipAddrBlock, -1); 757 if ((ext = X509_get_ext(x, index)) != NULL) { 758 if (!sbgp_ipaddrblk(fn, cert, ext)) 759 goto out; 760 } 761 762 index = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1); 763 if ((ext = X509_get_ext(x, index)) != NULL) { 764 if (!sbgp_assysnum(fn, cert, ext)) 765 goto out; 766 } 767 768 if (!X509_up_ref(x)) { 769 warnx("%s: X509_up_ref failed", fn); 770 goto out; 771 } 772 773 cert->x509 = x; 774 cert->talid = talid; 775 776 if (!constraints_validate(fn, cert)) 777 goto out; 778 779 return cert; 780 781 out: 782 cert_free(cert); 783 return NULL; 784} 785 786/* 787 * Parse and partially validate an RPKI X509 certificate (either a trust 788 * anchor or a certificate) as defined in RFC 6487. 789 * Returns the parse results or NULL on failure. 790 */ 791struct cert * 792cert_parse_pre(const char *fn, const unsigned char *der, size_t len) 793{ 794 struct cert *cert; 795 const unsigned char *oder; 796 size_t j; 797 int i, extsz; 798 X509 *x = NULL; 799 X509_EXTENSION *ext = NULL; 800 const ASN1_BIT_STRING *issuer_uid = NULL, *subject_uid = NULL; 801 ASN1_OBJECT *obj; 802 EVP_PKEY *pkey; 803 int nid, ip, as, sia, cp, crldp, aia, aki, ski, 804 eku, bc, ku; 805 806 nid = ip = as = sia = cp = crldp = aia = aki = ski = eku = bc = ku = 0; 807 808 /* just fail for empty buffers, the warning was printed elsewhere */ 809 if (der == NULL) 810 return NULL; 811 812 if ((cert = calloc(1, sizeof(struct cert))) == NULL) 813 err(1, NULL); 814 815 oder = der; 816 if ((x = d2i_X509(NULL, &der, len)) == NULL) { 817 warnx("%s: d2i_X509", fn); 818 goto out; 819 } 820 if (der != oder + len) { 821 warnx("%s: %td bytes trailing garbage", fn, oder + len - der); 822 goto out; 823 } 824 825 if (!x509_cache_extensions(x, fn)) 826 goto out; 827 828 if (X509_get_version(x) != 2) { 829 warnx("%s: RFC 6487 4.1: X.509 version must be v3", fn); 830 goto out; 831 } 832 833 if ((nid = X509_get_signature_nid(x)) == NID_undef) { 834 warnx("%s: unknown signature type", fn); 835 goto out; 836 } 837 if (experimental && nid == NID_ecdsa_with_SHA256) { 838 if (verbose) 839 warnx("%s: P-256 support is experimental", fn); 840 } else if (nid != NID_sha256WithRSAEncryption) { 841 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s", 842 fn, nid2str(nid), LN_sha256WithRSAEncryption); 843 goto out; 844 } 845 846 X509_get0_uids(x, &issuer_uid, &subject_uid); 847 if (issuer_uid != NULL || subject_uid != NULL) { 848 warnx("%s: issuer or subject unique identifiers not allowed", 849 fn); 850 goto out; 851 } 852 853 if (!cert_check_subject_and_issuer(fn, x)) 854 goto out; 855 856 /* Look for X509v3 extensions. */ 857 if ((extsz = X509_get_ext_count(x)) <= 0) { 858 warnx("%s: certificate without X.509v3 extensions", fn); 859 goto out; 860 } 861 862 for (i = 0; i < extsz; i++) { 863 ext = X509_get_ext(x, i); 864 assert(ext != NULL); 865 obj = X509_EXTENSION_get_object(ext); 866 assert(obj != NULL); 867 868 switch (nid = OBJ_obj2nid(obj)) { 869 case NID_sbgp_ipAddrBlock: 870 if (ip++ > 0) 871 goto dup; 872 if (!sbgp_ipaddrblk(fn, cert, ext)) 873 goto out; 874 break; 875 case NID_sbgp_autonomousSysNum: 876 if (as++ > 0) 877 goto dup; 878 if (!sbgp_assysnum(fn, cert, ext)) 879 goto out; 880 break; 881 case NID_sinfo_access: 882 if (sia++ > 0) 883 goto dup; 884 /* 885 * This will fail for BGPsec certs, but they must omit 886 * this extension anyway (RFC 8209, section 3.1.3.3). 887 */ 888 if (!sbgp_sia(fn, cert, ext)) 889 goto out; 890 break; 891 case NID_certificate_policies: 892 if (cp++ > 0) 893 goto dup; 894 if (!certificate_policies(fn, cert, ext)) 895 goto out; 896 break; 897 case NID_crl_distribution_points: 898 if (crldp++ > 0) 899 goto dup; 900 break; 901 case NID_info_access: 902 if (aia++ > 0) 903 goto dup; 904 break; 905 case NID_authority_key_identifier: 906 if (aki++ > 0) 907 goto dup; 908 break; 909 case NID_subject_key_identifier: 910 if (ski++ > 0) 911 goto dup; 912 break; 913 case NID_ext_key_usage: 914 if (eku++ > 0) 915 goto dup; 916 break; 917 case NID_basic_constraints: 918 if (bc++ > 0) 919 goto dup; 920 break; 921 case NID_key_usage: 922 if (ku++ > 0) 923 goto dup; 924 break; 925 default: 926 /* unexpected extensions warrant investigation */ 927 { 928 char objn[64]; 929 OBJ_obj2txt(objn, sizeof(objn), obj, 0); 930 warnx("%s: ignoring %s (NID %d)", 931 fn, objn, OBJ_obj2nid(obj)); 932 } 933 break; 934 } 935 } 936 937 if (!x509_get_aki(x, fn, &cert->aki)) 938 goto out; 939 if (!x509_get_ski(x, fn, &cert->ski)) 940 goto out; 941 if (!x509_get_aia(x, fn, &cert->aia)) 942 goto out; 943 if (!x509_get_crl(x, fn, &cert->crl)) 944 goto out; 945 if (!x509_get_notbefore(x, fn, &cert->notbefore)) 946 goto out; 947 if (!x509_get_notafter(x, fn, &cert->notafter)) 948 goto out; 949 950 /* Validation on required fields. */ 951 cert->purpose = x509_get_purpose(x, fn); 952 switch (cert->purpose) { 953 case CERT_PURPOSE_TA: 954 /* XXX - caller should indicate if it expects TA or CA cert */ 955 case CERT_PURPOSE_CA: 956 if ((pkey = X509_get0_pubkey(x)) == NULL) { 957 warnx("%s: X509_get0_pubkey failed", fn); 958 goto out; 959 } 960 if (!valid_ca_pkey(fn, pkey)) 961 goto out; 962 963 if (cert->mft == NULL) { 964 warnx("%s: RFC 6487 section 4.8.8: missing SIA", fn); 965 goto out; 966 } 967 if (cert->asz == 0 && cert->ipsz == 0) { 968 warnx("%s: missing IP or AS resources", fn); 969 goto out; 970 } 971 break; 972 case CERT_PURPOSE_BGPSEC_ROUTER: 973 cert->pubkey = x509_get_pubkey(x, fn); 974 if (cert->pubkey == NULL) { 975 warnx("%s: x509_get_pubkey failed", fn); 976 goto out; 977 } 978 if (cert->ipsz > 0) { 979 warnx("%s: unexpected IP resources in BGPsec cert", fn); 980 goto out; 981 } 982 for (j = 0; j < cert->asz; j++) { 983 if (cert->as[j].type == CERT_AS_INHERIT) { 984 warnx("%s: inherit elements not allowed in EE" 985 " cert", fn); 986 goto out; 987 } 988 } 989 if (sia) { 990 warnx("%s: unexpected SIA extension in BGPsec cert", 991 fn); 992 goto out; 993 } 994 break; 995 case CERT_PURPOSE_EE: 996 warn("%s: unexpected EE cert", fn); 997 goto out; 998 default: 999 warnx("%s: x509_get_purpose failed in %s", fn, __func__); 1000 goto out; 1001 } 1002 1003 if (cert->ski == NULL) { 1004 warnx("%s: RFC 6487 section 8.4.2: missing SKI", fn); 1005 goto out; 1006 } 1007 1008 cert->x509 = x; 1009 return cert; 1010 1011 dup: 1012 warnx("%s: RFC 5280 section 4.2: duplicate extension: %s", fn, 1013 nid2str(nid)); 1014 out: 1015 cert_free(cert); 1016 X509_free(x); 1017 return NULL; 1018} 1019 1020struct cert * 1021cert_parse(const char *fn, struct cert *p) 1022{ 1023 if (p == NULL) 1024 return NULL; 1025 1026 if (p->aki == NULL) { 1027 warnx("%s: RFC 6487 section 8.4.2: " 1028 "non-trust anchor missing AKI", fn); 1029 goto badcert; 1030 } 1031 if (strcmp(p->aki, p->ski) == 0) { 1032 warnx("%s: RFC 6487 section 8.4.2: " 1033 "non-trust anchor AKI may not match SKI", fn); 1034 goto badcert; 1035 } 1036 if (p->aia == NULL) { 1037 warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn); 1038 goto badcert; 1039 } 1040 if (p->crl == NULL) { 1041 warnx("%s: RFC 6487 section 4.8.6: CRL: " 1042 "no CRL distribution point extension", fn); 1043 goto badcert; 1044 } 1045 return p; 1046 1047badcert: 1048 cert_free(p); 1049 return NULL; 1050} 1051 1052struct cert * 1053ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, 1054 size_t pkeysz) 1055{ 1056 EVP_PKEY *pk, *opk; 1057 time_t now = get_current_time(); 1058 1059 if (p == NULL) 1060 return NULL; 1061 1062 /* first check pubkey against the one from the TAL */ 1063 pk = d2i_PUBKEY(NULL, &pkey, pkeysz); 1064 if (pk == NULL) { 1065 warnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn); 1066 goto badcert; 1067 } 1068 if ((opk = X509_get0_pubkey(p->x509)) == NULL) { 1069 warnx("%s: RFC 6487 (trust anchor): missing pubkey", fn); 1070 goto badcert; 1071 } 1072 if (EVP_PKEY_cmp(pk, opk) != 1) { 1073 warnx("%s: RFC 6487 (trust anchor): " 1074 "pubkey does not match TAL pubkey", fn); 1075 goto badcert; 1076 } 1077 if (p->notbefore >= now) { 1078 warnx("%s: certificate not yet valid", fn); 1079 goto badcert; 1080 } 1081 if (p->notafter <= now) { 1082 warnx("%s: certificate has expired", fn); 1083 goto badcert; 1084 } 1085 if (p->aki != NULL && strcmp(p->aki, p->ski)) { 1086 warnx("%s: RFC 6487 section 4.8.3: " 1087 "trust anchor AKI, if specified, must match SKI", fn); 1088 goto badcert; 1089 } 1090 if (p->aia != NULL) { 1091 warnx("%s: RFC 6487 section 4.8.7: " 1092 "trust anchor must not have AIA", fn); 1093 goto badcert; 1094 } 1095 if (p->crl != NULL) { 1096 warnx("%s: RFC 6487 section 4.8.6: " 1097 "trust anchor may not specify CRL resource", fn); 1098 goto badcert; 1099 } 1100 if (p->purpose != CERT_PURPOSE_TA) { 1101 warnx("%s: expected trust anchor purpose, got %s", fn, 1102 purpose2str(p->purpose)); 1103 goto badcert; 1104 } 1105 /* 1106 * Do not replace with a <= 0 check since OpenSSL 3 broke that: 1107 * https://github.com/openssl/openssl/issues/24575 1108 */ 1109 if (X509_verify(p->x509, pk) != 1) { 1110 warnx("%s: failed to verify signature", fn); 1111 goto badcert; 1112 } 1113 if (x509_any_inherits(p->x509)) { 1114 warnx("%s: Trust anchor IP/AS resources may not inherit", fn); 1115 goto badcert; 1116 } 1117 1118 EVP_PKEY_free(pk); 1119 return p; 1120 1121 badcert: 1122 EVP_PKEY_free(pk); 1123 cert_free(p); 1124 return NULL; 1125} 1126 1127/* 1128 * Free parsed certificate contents. 1129 * Passing NULL is a noop. 1130 */ 1131void 1132cert_free(struct cert *p) 1133{ 1134 if (p == NULL) 1135 return; 1136 1137 free(p->crl); 1138 free(p->repo); 1139 free(p->mft); 1140 free(p->notify); 1141 free(p->ips); 1142 free(p->as); 1143 free(p->aia); 1144 free(p->aki); 1145 free(p->ski); 1146 free(p->pubkey); 1147 X509_free(p->x509); 1148 free(p); 1149} 1150 1151/* 1152 * Write certificate parsed content into buffer. 1153 * See cert_read() for the other side of the pipe. 1154 */ 1155void 1156cert_buffer(struct ibuf *b, const struct cert *p) 1157{ 1158 io_simple_buffer(b, &p->notafter, sizeof(p->notafter)); 1159 io_simple_buffer(b, &p->purpose, sizeof(p->purpose)); 1160 io_simple_buffer(b, &p->talid, sizeof(p->talid)); 1161 io_simple_buffer(b, &p->certid, sizeof(p->certid)); 1162 io_simple_buffer(b, &p->repoid, sizeof(p->repoid)); 1163 io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz)); 1164 io_simple_buffer(b, &p->asz, sizeof(p->asz)); 1165 1166 io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0])); 1167 io_simple_buffer(b, p->as, p->asz * sizeof(p->as[0])); 1168 1169 io_str_buffer(b, p->mft); 1170 io_str_buffer(b, p->notify); 1171 io_str_buffer(b, p->repo); 1172 io_str_buffer(b, p->crl); 1173 io_str_buffer(b, p->aia); 1174 io_str_buffer(b, p->aki); 1175 io_str_buffer(b, p->ski); 1176 io_str_buffer(b, p->pubkey); 1177} 1178 1179/* 1180 * Allocate and read parsed certificate content from descriptor. 1181 * The pointer must be freed with cert_free(). 1182 * Always returns a valid pointer. 1183 */ 1184struct cert * 1185cert_read(struct ibuf *b) 1186{ 1187 struct cert *p; 1188 1189 if ((p = calloc(1, sizeof(struct cert))) == NULL) 1190 err(1, NULL); 1191 1192 io_read_buf(b, &p->notafter, sizeof(p->notafter)); 1193 io_read_buf(b, &p->purpose, sizeof(p->purpose)); 1194 io_read_buf(b, &p->talid, sizeof(p->talid)); 1195 io_read_buf(b, &p->certid, sizeof(p->certid)); 1196 io_read_buf(b, &p->repoid, sizeof(p->repoid)); 1197 io_read_buf(b, &p->ipsz, sizeof(p->ipsz)); 1198 io_read_buf(b, &p->asz, sizeof(p->asz)); 1199 1200 p->ips = calloc(p->ipsz, sizeof(struct cert_ip)); 1201 if (p->ips == NULL) 1202 err(1, NULL); 1203 io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0])); 1204 1205 p->as = calloc(p->asz, sizeof(struct cert_as)); 1206 if (p->as == NULL) 1207 err(1, NULL); 1208 io_read_buf(b, p->as, p->asz * sizeof(p->as[0])); 1209 1210 io_read_str(b, &p->mft); 1211 io_read_str(b, &p->notify); 1212 io_read_str(b, &p->repo); 1213 io_read_str(b, &p->crl); 1214 io_read_str(b, &p->aia); 1215 io_read_str(b, &p->aki); 1216 io_read_str(b, &p->ski); 1217 io_read_str(b, &p->pubkey); 1218 1219 assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER); 1220 assert(p->ski); 1221 return p; 1222} 1223 1224static inline int 1225authcmp(struct auth *a, struct auth *b) 1226{ 1227 if (a->cert->certid > b->cert->certid) 1228 return 1; 1229 if (a->cert->certid < b->cert->certid) 1230 return -1; 1231 return 0; 1232} 1233 1234RB_GENERATE_STATIC(auth_tree, auth, entry, authcmp); 1235 1236void 1237auth_tree_free(struct auth_tree *auths) 1238{ 1239 struct auth *auth, *tauth; 1240 1241 RB_FOREACH_SAFE(auth, auth_tree, auths, tauth) { 1242 RB_REMOVE(auth_tree, auths, auth); 1243 cert_free(auth->cert); 1244 free(auth); 1245 } 1246} 1247 1248struct auth * 1249auth_find(struct auth_tree *auths, int id) 1250{ 1251 struct auth a; 1252 struct cert c; 1253 1254 c.certid = id; 1255 a.cert = &c; 1256 1257 return RB_FIND(auth_tree, auths, &a); 1258} 1259 1260struct auth * 1261auth_insert(const char *fn, struct auth_tree *auths, struct cert *cert, 1262 struct auth *issuer) 1263{ 1264 struct auth *na; 1265 1266 na = calloc(1, sizeof(*na)); 1267 if (na == NULL) 1268 err(1, NULL); 1269 1270 if (issuer == NULL) { 1271 cert->certid = cert->talid; 1272 } else { 1273 cert->certid = ++certid; 1274 if (certid > CERTID_MAX) { 1275 if (certid == CERTID_MAX + 1) 1276 warnx("%s: too many certificates in store", fn); 1277 free(na); 1278 return NULL; 1279 } 1280 na->depth = issuer->depth + 1; 1281 } 1282 1283 if (na->depth >= MAX_CERT_DEPTH) { 1284 warnx("%s: maximum certificate chain depth exhausted", fn); 1285 free(na); 1286 return NULL; 1287 } 1288 1289 na->issuer = issuer; 1290 na->cert = cert; 1291 na->any_inherits = x509_any_inherits(cert->x509); 1292 1293 if (RB_INSERT(auth_tree, auths, na) != NULL) 1294 errx(1, "auth tree corrupted"); 1295 1296 return na; 1297} 1298 1299static void 1300insert_brk(struct brk_tree *tree, struct cert *cert, int asid) 1301{ 1302 struct brk *b, *found; 1303 1304 if ((b = calloc(1, sizeof(*b))) == NULL) 1305 err(1, NULL); 1306 1307 b->asid = asid; 1308 b->expires = cert->notafter; 1309 b->talid = cert->talid; 1310 if ((b->ski = strdup(cert->ski)) == NULL) 1311 err(1, NULL); 1312 if ((b->pubkey = strdup(cert->pubkey)) == NULL) 1313 err(1, NULL); 1314 1315 /* 1316 * Check if a similar BRK already exists in the tree. If the found BRK 1317 * expires sooner, update it to this BRK's later expiry moment. 1318 */ 1319 if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) { 1320 if (found->expires < b->expires) { 1321 found->expires = b->expires; 1322 found->talid = b->talid; 1323 } 1324 free(b->ski); 1325 free(b->pubkey); 1326 free(b); 1327 } 1328} 1329 1330/* 1331 * Add each BGPsec Router Key into the BRK tree. 1332 */ 1333void 1334cert_insert_brks(struct brk_tree *tree, struct cert *cert) 1335{ 1336 size_t i, asid; 1337 1338 for (i = 0; i < cert->asz; i++) { 1339 switch (cert->as[i].type) { 1340 case CERT_AS_ID: 1341 insert_brk(tree, cert, cert->as[i].id); 1342 break; 1343 case CERT_AS_RANGE: 1344 for (asid = cert->as[i].range.min; 1345 asid <= cert->as[i].range.max; asid++) 1346 insert_brk(tree, cert, asid); 1347 break; 1348 default: 1349 warnx("invalid AS identifier type"); 1350 continue; 1351 } 1352 } 1353} 1354 1355static inline int 1356brkcmp(struct brk *a, struct brk *b) 1357{ 1358 int rv; 1359 1360 if (a->asid > b->asid) 1361 return 1; 1362 if (a->asid < b->asid) 1363 return -1; 1364 1365 rv = strcmp(a->ski, b->ski); 1366 if (rv > 0) 1367 return 1; 1368 if (rv < 0) 1369 return -1; 1370 1371 return strcmp(a->pubkey, b->pubkey); 1372} 1373 1374RB_GENERATE(brk_tree, brk, entry, brkcmp); 1375