1/* $OpenBSD: x509.c,v 1.99 2024/06/10 12:44:06 tb Exp $ */ 2/* 3 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2021 Claudio Jeker <claudio@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/evp.h> 27#include <openssl/x509v3.h> 28 29#include "extern.h" 30 31ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ 32ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ 33ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ 34ASN1_OBJECT *signedobj_oid; /* 1.3.6.1.5.5.7.48.11 (signedObject) */ 35ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ 36ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */ 37ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */ 38ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */ 39ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */ 40ASN1_OBJECT *cnt_type_oid; /* pkcs-9 id-contentType */ 41ASN1_OBJECT *msg_dgst_oid; /* pkcs-9 id-messageDigest */ 42ASN1_OBJECT *sign_time_oid; /* pkcs-9 id-signingTime */ 43ASN1_OBJECT *rsc_oid; /* id-ct-signedChecklist */ 44ASN1_OBJECT *aspa_oid; /* id-ct-ASPA */ 45ASN1_OBJECT *tak_oid; /* id-ct-SignedTAL */ 46ASN1_OBJECT *geofeed_oid; /* id-ct-geofeedCSVwithCRLF */ 47ASN1_OBJECT *spl_oid; /* id-ct-signedPrefixList */ 48 49static const struct { 50 const char *oid; 51 ASN1_OBJECT **ptr; 52} oid_table[] = { 53 { 54 .oid = "1.3.6.1.5.5.7.14.2", 55 .ptr = &certpol_oid, 56 }, 57 { 58 .oid = "1.3.6.1.5.5.7.48.5", 59 .ptr = &carepo_oid, 60 }, 61 { 62 .oid = "1.3.6.1.5.5.7.48.10", 63 .ptr = &manifest_oid, 64 }, 65 { 66 .oid = "1.3.6.1.5.5.7.48.11", 67 .ptr = &signedobj_oid, 68 }, 69 { 70 .oid = "1.3.6.1.5.5.7.48.13", 71 .ptr = ¬ify_oid, 72 }, 73 { 74 .oid = "1.2.840.113549.1.9.16.1.24", 75 .ptr = &roa_oid, 76 }, 77 { 78 .oid = "1.2.840.113549.1.9.16.1.26", 79 .ptr = &mft_oid, 80 }, 81 { 82 .oid = "1.2.840.113549.1.9.16.1.35", 83 .ptr = &gbr_oid, 84 }, 85 { 86 .oid = "1.3.6.1.5.5.7.3.30", 87 .ptr = &bgpsec_oid, 88 }, 89 { 90 .oid = "1.2.840.113549.1.9.3", 91 .ptr = &cnt_type_oid, 92 }, 93 { 94 .oid = "1.2.840.113549.1.9.4", 95 .ptr = &msg_dgst_oid, 96 }, 97 { 98 .oid = "1.2.840.113549.1.9.5", 99 .ptr = &sign_time_oid, 100 }, 101 { 102 .oid = "1.2.840.113549.1.9.16.1.47", 103 .ptr = &geofeed_oid, 104 }, 105 { 106 .oid = "1.2.840.113549.1.9.16.1.48", 107 .ptr = &rsc_oid, 108 }, 109 { 110 .oid = "1.2.840.113549.1.9.16.1.49", 111 .ptr = &aspa_oid, 112 }, 113 { 114 .oid = "1.2.840.113549.1.9.16.1.50", 115 .ptr = &tak_oid, 116 }, 117 { 118 .oid = "1.2.840.113549.1.9.16.1.51", 119 .ptr = &spl_oid, 120 }, 121}; 122 123void 124x509_init_oid(void) 125{ 126 size_t i; 127 128 for (i = 0; i < sizeof(oid_table) / sizeof(oid_table[0]); i++) { 129 *oid_table[i].ptr = OBJ_txt2obj(oid_table[i].oid, 1); 130 if (*oid_table[i].ptr == NULL) 131 errx(1, "OBJ_txt2obj for %s failed", oid_table[i].oid); 132 } 133} 134 135/* 136 * A number of critical OpenSSL API functions can't properly indicate failure 137 * and are unreliable if the extensions aren't already cached. An old trick is 138 * to cache the extensions using an error-checked call to X509_check_purpose() 139 * with a purpose of -1. This way functions such as X509_check_ca(), X509_cmp(), 140 * X509_get_key_usage(), X509_get_extended_key_usage() won't lie. 141 * 142 * Should be called right after deserialization and is essentially free to call 143 * multiple times. 144 */ 145int 146x509_cache_extensions(X509 *x509, const char *fn) 147{ 148 if (X509_check_purpose(x509, -1, 0) <= 0) { 149 warnx("%s: could not cache X509v3 extensions", fn); 150 return 0; 151 } 152 return 1; 153} 154 155/* 156 * Parse X509v3 authority key identifier (AKI), RFC 6487 sec. 4.8.3. 157 * Returns the AKI or NULL if it could not be parsed. 158 * The AKI is formatted as a hex string. 159 */ 160int 161x509_get_aki(X509 *x, const char *fn, char **aki) 162{ 163 const unsigned char *d; 164 AUTHORITY_KEYID *akid; 165 ASN1_OCTET_STRING *os; 166 int dsz, crit, rc = 0; 167 168 *aki = NULL; 169 akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &crit, NULL); 170 if (akid == NULL) { 171 if (crit != -1) { 172 warnx("%s: RFC 6487 section 4.8.3: error parsing AKI", 173 fn); 174 return 0; 175 } 176 return 1; 177 } 178 if (crit != 0) { 179 warnx("%s: RFC 6487 section 4.8.3: " 180 "AKI: extension not non-critical", fn); 181 goto out; 182 } 183 if (akid->issuer != NULL || akid->serial != NULL) { 184 warnx("%s: RFC 6487 section 4.8.3: AKI: " 185 "authorityCertIssuer or authorityCertSerialNumber present", 186 fn); 187 goto out; 188 } 189 190 os = akid->keyid; 191 if (os == NULL) { 192 warnx("%s: RFC 6487 section 4.8.3: AKI: " 193 "Key Identifier missing", fn); 194 goto out; 195 } 196 197 d = os->data; 198 dsz = os->length; 199 200 if (dsz != SHA_DIGEST_LENGTH) { 201 warnx("%s: RFC 6487 section 4.8.2: AKI: " 202 "want %d bytes SHA1 hash, have %d bytes", 203 fn, SHA_DIGEST_LENGTH, dsz); 204 goto out; 205 } 206 207 *aki = hex_encode(d, dsz); 208 rc = 1; 209out: 210 AUTHORITY_KEYID_free(akid); 211 return rc; 212} 213 214/* 215 * Validate the X509v3 subject key identifier (SKI), RFC 6487 section 4.8.2: 216 * "The SKI is a SHA-1 hash of the value of the DER-encoded ASN.1 BIT STRING of 217 * the Subject Public Key, as described in Section 4.2.1.2 of RFC 5280." 218 * Returns the SKI formatted as hex string, or NULL if it couldn't be parsed. 219 */ 220int 221x509_get_ski(X509 *x, const char *fn, char **ski) 222{ 223 ASN1_OCTET_STRING *os; 224 unsigned char md[EVP_MAX_MD_SIZE]; 225 unsigned int md_len = EVP_MAX_MD_SIZE; 226 int crit, rc = 0; 227 228 *ski = NULL; 229 os = X509_get_ext_d2i(x, NID_subject_key_identifier, &crit, NULL); 230 if (os == NULL) { 231 if (crit != -1) { 232 warnx("%s: RFC 6487 section 4.8.2: error parsing SKI", 233 fn); 234 return 0; 235 } 236 return 1; 237 } 238 if (crit != 0) { 239 warnx("%s: RFC 6487 section 4.8.2: " 240 "SKI: extension not non-critical", fn); 241 goto out; 242 } 243 244 if (!X509_pubkey_digest(x, EVP_sha1(), md, &md_len)) { 245 warnx("%s: X509_pubkey_digest", fn); 246 goto out; 247 } 248 249 if (os->length < 0 || md_len != (size_t)os->length) { 250 warnx("%s: RFC 6487 section 4.8.2: SKI: " 251 "want %u bytes SHA1 hash, have %d bytes", 252 fn, md_len, os->length); 253 goto out; 254 } 255 256 if (memcmp(os->data, md, md_len) != 0) { 257 warnx("%s: SKI does not match SHA1 hash of SPK", fn); 258 goto out; 259 } 260 261 *ski = hex_encode(md, md_len); 262 rc = 1; 263 out: 264 ASN1_OCTET_STRING_free(os); 265 return rc; 266} 267 268/* 269 * Check the cert's purpose: the cA bit in basic constraints distinguishes 270 * between TA/CA and EE/BGPsec router and the key usage bits must match. 271 * TAs are self-signed, CAs not self-issued, EEs have no extended key usage, 272 * BGPsec router have id-kp-bgpsec-router OID. 273 */ 274enum cert_purpose 275x509_get_purpose(X509 *x, const char *fn) 276{ 277 BASIC_CONSTRAINTS *bc = NULL; 278 EXTENDED_KEY_USAGE *eku = NULL; 279 const X509_EXTENSION *ku; 280 int crit, ext_flags, i, is_ca, ku_idx; 281 enum cert_purpose purpose = CERT_PURPOSE_INVALID; 282 283 if (!x509_cache_extensions(x, fn)) 284 goto out; 285 286 ext_flags = X509_get_extension_flags(x); 287 288 /* Key usage must be present and critical. KU bits are checked below. */ 289 if ((ku_idx = X509_get_ext_by_NID(x, NID_key_usage, -1)) < 0) { 290 warnx("%s: RFC 6487, section 4.8.4: missing KeyUsage", fn); 291 goto out; 292 } 293 if ((ku = X509_get_ext(x, ku_idx)) == NULL) { 294 warnx("%s: RFC 6487, section 4.8.4: missing KeyUsage", fn); 295 goto out; 296 } 297 if (!X509_EXTENSION_get_critical(ku)) { 298 warnx("%s: RFC 6487, section 4.8.4: KeyUsage not critical", fn); 299 goto out; 300 } 301 302 /* This weird API can return 0, 1, 2, 4, 5 but can't error... */ 303 if ((is_ca = X509_check_ca(x)) > 1) { 304 if (is_ca == 4) 305 warnx("%s: RFC 6487: sections 4.8.1 and 4.8.4: " 306 "no basic constraints, but keyCertSign set", fn); 307 else 308 warnx("%s: unexpected legacy certificate", fn); 309 goto out; 310 } 311 312 if (is_ca) { 313 bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL); 314 if (bc == NULL) { 315 if (crit != -1) 316 warnx("%s: RFC 6487 section 4.8.1: " 317 "error parsing basic constraints", fn); 318 else 319 warnx("%s: RFC 6487 section 4.8.1: " 320 "missing basic constraints", fn); 321 goto out; 322 } 323 if (crit != 1) { 324 warnx("%s: RFC 6487 section 4.8.1: Basic Constraints " 325 "must be marked critical", fn); 326 goto out; 327 } 328 if (bc->pathlen != NULL) { 329 warnx("%s: RFC 6487 section 4.8.1: Path Length " 330 "Constraint must be absent", fn); 331 goto out; 332 } 333 334 if (X509_get_key_usage(x) != (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) { 335 warnx("%s: RFC 6487 section 4.8.4: key usage violation", 336 fn); 337 goto out; 338 } 339 340 if (X509_get_extended_key_usage(x) != UINT32_MAX) { 341 warnx("%s: RFC 6487 section 4.8.5: EKU not allowed", 342 fn); 343 goto out; 344 } 345 346 /* 347 * EXFLAG_SI means that issuer and subject are identical. 348 * EXFLAG_SS is SI plus the AKI is absent or matches the SKI. 349 * Thus, exactly the trust anchors should have EXFLAG_SS set 350 * and we should never see EXFLAG_SI without EXFLAG_SS. 351 */ 352 if ((ext_flags & EXFLAG_SS) != 0) 353 purpose = CERT_PURPOSE_TA; 354 else if ((ext_flags & EXFLAG_SI) == 0) 355 purpose = CERT_PURPOSE_CA; 356 else 357 warnx("%s: RFC 6487, section 4.8.3: " 358 "self-issued cert with AKI-SKI mismatch", fn); 359 goto out; 360 } 361 362 if ((ext_flags & EXFLAG_BCONS) != 0) { 363 warnx("%s: Basic Constraints ext in non-CA cert", fn); 364 goto out; 365 } 366 367 if (X509_get_key_usage(x) != KU_DIGITAL_SIGNATURE) { 368 warnx("%s: RFC 6487 section 4.8.4: KU must be digitalSignature", 369 fn); 370 goto out; 371 } 372 373 /* 374 * EKU is only defined for BGPsec Router certs and must be absent from 375 * EE certs. 376 */ 377 eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL); 378 if (eku == NULL) { 379 if (crit != -1) 380 warnx("%s: error parsing EKU", fn); 381 else 382 purpose = CERT_PURPOSE_EE; /* EKU absent */ 383 goto out; 384 } 385 if (crit != 0) { 386 warnx("%s: EKU: extension must not be marked critical", fn); 387 goto out; 388 } 389 390 /* 391 * Per RFC 8209, section 3.1.3.2 the id-kp-bgpsec-router OID must be 392 * present and others are allowed, which we don't need to recognize. 393 * This matches RFC 5280, section 4.2.1.12. 394 */ 395 for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) { 396 if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, i)) == 0) { 397 purpose = CERT_PURPOSE_BGPSEC_ROUTER; 398 break; 399 } 400 } 401 402 out: 403 BASIC_CONSTRAINTS_free(bc); 404 EXTENDED_KEY_USAGE_free(eku); 405 return purpose; 406} 407 408/* 409 * Extract Subject Public Key Info (SPKI) from BGPsec X.509 Certificate. 410 * Returns NULL on failure, on success return the SPKI as base64 encoded pubkey 411 */ 412char * 413x509_get_pubkey(X509 *x, const char *fn) 414{ 415 EVP_PKEY *pkey; 416 EC_KEY *eckey; 417 int nid; 418 const char *cname; 419 uint8_t *pubkey = NULL; 420 char *res = NULL; 421 int len; 422 423 pkey = X509_get0_pubkey(x); 424 if (pkey == NULL) { 425 warnx("%s: X509_get0_pubkey failed in %s", fn, __func__); 426 goto out; 427 } 428 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { 429 warnx("%s: Expected EVP_PKEY_EC, got %d", fn, 430 EVP_PKEY_base_id(pkey)); 431 goto out; 432 } 433 434 eckey = EVP_PKEY_get0_EC_KEY(pkey); 435 if (eckey == NULL) { 436 warnx("%s: Incorrect key type", fn); 437 goto out; 438 } 439 440 nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)); 441 if (nid != NID_X9_62_prime256v1) { 442 if ((cname = EC_curve_nid2nist(nid)) == NULL) 443 cname = nid2str(nid); 444 warnx("%s: Expected P-256, got %s", fn, cname); 445 goto out; 446 } 447 448 if (!EC_KEY_check_key(eckey)) { 449 warnx("%s: EC_KEY_check_key failed in %s", fn, __func__); 450 goto out; 451 } 452 453 len = i2d_PUBKEY(pkey, &pubkey); 454 if (len <= 0) { 455 warnx("%s: i2d_PUBKEY failed in %s", fn, __func__); 456 goto out; 457 } 458 459 if (base64_encode(pubkey, len, &res) == -1) 460 errx(1, "base64_encode failed in %s", __func__); 461 462 out: 463 free(pubkey); 464 return res; 465} 466 467/* 468 * Compute the SKI of an RSA public key in an X509_PUBKEY using SHA-1. 469 * Returns allocated hex-encoded SKI on success, NULL on failure. 470 */ 471char * 472x509_pubkey_get_ski(X509_PUBKEY *pubkey, const char *fn) 473{ 474 ASN1_OBJECT *obj; 475 const unsigned char *der; 476 int der_len, nid; 477 unsigned char md[EVP_MAX_MD_SIZE]; 478 unsigned int md_len = EVP_MAX_MD_SIZE; 479 480 if (!X509_PUBKEY_get0_param(&obj, &der, &der_len, NULL, pubkey)) { 481 warnx("%s: X509_PUBKEY_get0_param failed", fn); 482 return NULL; 483 } 484 485 if ((nid = OBJ_obj2nid(obj)) != NID_rsaEncryption) { 486 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s", 487 fn, nid2str(nid), LN_rsaEncryption); 488 return NULL; 489 } 490 491 if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha1(), NULL)) { 492 warnx("%s: EVP_Digest failed", fn); 493 return NULL; 494 } 495 496 return hex_encode(md, md_len); 497} 498 499/* 500 * Parse the Authority Information Access (AIA) extension 501 * See RFC 6487, section 4.8.7 for details. 502 * Returns NULL on failure, on success returns the AIA URI 503 * (which has to be freed after use). 504 */ 505int 506x509_get_aia(X509 *x, const char *fn, char **out_aia) 507{ 508 ACCESS_DESCRIPTION *ad; 509 AUTHORITY_INFO_ACCESS *info; 510 int crit, rc = 0; 511 512 assert(*out_aia == NULL); 513 514 info = X509_get_ext_d2i(x, NID_info_access, &crit, NULL); 515 if (info == NULL) { 516 if (crit != -1) { 517 warnx("%s: RFC 6487 section 4.8.7: error parsing AIA", 518 fn); 519 return 0; 520 } 521 return 1; 522 } 523 524 if (crit != 0) { 525 warnx("%s: RFC 6487 section 4.8.7: " 526 "AIA: extension not non-critical", fn); 527 goto out; 528 } 529 530 if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) { 531 warnx("%s: RFC 6487 section 4.8.7: AIA must be absent from " 532 "a self-signed certificate", fn); 533 goto out; 534 } 535 536 if (sk_ACCESS_DESCRIPTION_num(info) != 1) { 537 warnx("%s: RFC 6487 section 4.8.7: AIA: " 538 "want 1 element, have %d", fn, 539 sk_ACCESS_DESCRIPTION_num(info)); 540 goto out; 541 } 542 543 ad = sk_ACCESS_DESCRIPTION_value(info, 0); 544 if (OBJ_obj2nid(ad->method) != NID_ad_ca_issuers) { 545 warnx("%s: RFC 6487 section 4.8.7: AIA: " 546 "expected caIssuers, have %d", fn, OBJ_obj2nid(ad->method)); 547 goto out; 548 } 549 550 if (!x509_location(fn, "AIA: caIssuers", ad->location, out_aia)) 551 goto out; 552 553 rc = 1; 554 555 out: 556 AUTHORITY_INFO_ACCESS_free(info); 557 return rc; 558} 559 560/* 561 * Parse the Subject Information Access (SIA) extension for an EE cert. 562 * See RFC 6487, section 4.8.8.2 for details. 563 * Returns NULL on failure, on success returns the SIA signedObject URI 564 * (which has to be freed after use). 565 */ 566int 567x509_get_sia(X509 *x, const char *fn, char **out_sia) 568{ 569 ACCESS_DESCRIPTION *ad; 570 AUTHORITY_INFO_ACCESS *info; 571 ASN1_OBJECT *oid; 572 int i, crit, rc = 0; 573 574 assert(*out_sia == NULL); 575 576 info = X509_get_ext_d2i(x, NID_sinfo_access, &crit, NULL); 577 if (info == NULL) { 578 if (crit != -1) { 579 warnx("%s: error parsing SIA", fn); 580 return 0; 581 } 582 return 1; 583 } 584 585 if (crit != 0) { 586 warnx("%s: RFC 6487 section 4.8.8: " 587 "SIA: extension not non-critical", fn); 588 goto out; 589 } 590 591 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { 592 char *sia; 593 594 ad = sk_ACCESS_DESCRIPTION_value(info, i); 595 oid = ad->method; 596 597 /* 598 * XXX: RFC 6487 4.8.8.2 states that the accessMethod MUST be 599 * signedObject. However, rpkiNotify accessMethods currently 600 * exist in the wild. Consider removing this special case. 601 * See also https://www.rfc-editor.org/errata/eid7239. 602 */ 603 if (OBJ_cmp(oid, notify_oid) == 0) { 604 if (verbose > 1) 605 warnx("%s: RFC 6487 section 4.8.8.2: SIA should" 606 " not contain rpkiNotify accessMethod", fn); 607 continue; 608 } 609 if (OBJ_cmp(oid, signedobj_oid) != 0) { 610 char buf[128]; 611 612 OBJ_obj2txt(buf, sizeof(buf), oid, 0); 613 warnx("%s: RFC 6487 section 4.8.8.2: unexpected" 614 " accessMethod: %s", fn, buf); 615 goto out; 616 } 617 618 sia = NULL; 619 if (!x509_location(fn, "SIA: signedObject", ad->location, &sia)) 620 goto out; 621 622 if (*out_sia == NULL && strncasecmp(sia, RSYNC_PROTO, 623 RSYNC_PROTO_LEN) == 0) { 624 const char *p = sia + RSYNC_PROTO_LEN; 625 size_t fnlen, plen; 626 627 if (filemode) { 628 *out_sia = sia; 629 continue; 630 } 631 632 fnlen = strlen(fn); 633 plen = strlen(p); 634 635 if (fnlen < plen || strcmp(p, fn + fnlen - plen) != 0) { 636 warnx("%s: mismatch between pathname and SIA " 637 "(%s)", fn, sia); 638 free(sia); 639 goto out; 640 } 641 642 *out_sia = sia; 643 continue; 644 } 645 if (verbose) 646 warnx("%s: RFC 6487 section 4.8.8: SIA: " 647 "ignoring location %s", fn, sia); 648 free(sia); 649 } 650 651 if (*out_sia == NULL) { 652 warnx("%s: RFC 6487 section 4.8.8.2: " 653 "SIA without rsync accessLocation", fn); 654 goto out; 655 } 656 657 rc = 1; 658 659 out: 660 AUTHORITY_INFO_ACCESS_free(info); 661 return rc; 662} 663 664/* 665 * Extract the notBefore of a certificate. 666 */ 667int 668x509_get_notbefore(X509 *x, const char *fn, time_t *tt) 669{ 670 const ASN1_TIME *at; 671 672 at = X509_get0_notBefore(x); 673 if (at == NULL) { 674 warnx("%s: X509_get0_notBefore failed", fn); 675 return 0; 676 } 677 if (!x509_get_time(at, tt)) { 678 warnx("%s: ASN1_TIME_to_tm failed", fn); 679 return 0; 680 } 681 return 1; 682} 683 684/* 685 * Extract the notAfter from a certificate. 686 */ 687int 688x509_get_notafter(X509 *x, const char *fn, time_t *tt) 689{ 690 const ASN1_TIME *at; 691 692 at = X509_get0_notAfter(x); 693 if (at == NULL) { 694 warnx("%s: X509_get0_notafter failed", fn); 695 return 0; 696 } 697 if (!x509_get_time(at, tt)) { 698 warnx("%s: ASN1_TIME_to_tm failed", fn); 699 return 0; 700 } 701 return 1; 702} 703 704/* 705 * Check whether all RFC 3779 extensions are set to inherit. 706 * Return 1 if both AS & IP are set to inherit. 707 * Return 0 on failure (such as missing extensions or no inheritance). 708 */ 709int 710x509_inherits(X509 *x) 711{ 712 STACK_OF(IPAddressFamily) *addrblk = NULL; 713 ASIdentifiers *asidentifiers = NULL; 714 const IPAddressFamily *af; 715 int crit, i, rc = 0; 716 717 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL); 718 if (addrblk == NULL) { 719 if (crit != -1) 720 warnx("error parsing ipAddrBlock"); 721 goto out; 722 } 723 724 /* 725 * Check by hand, since X509v3_addr_inherits() success only means that 726 * at least one address family inherits, not all of them. 727 */ 728 for (i = 0; i < sk_IPAddressFamily_num(addrblk); i++) { 729 af = sk_IPAddressFamily_value(addrblk, i); 730 if (af->ipAddressChoice->type != IPAddressChoice_inherit) 731 goto out; 732 } 733 734 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, NULL, 735 NULL); 736 if (asidentifiers == NULL) { 737 if (crit != -1) 738 warnx("error parsing asIdentifiers"); 739 goto out; 740 } 741 742 /* We need to have AS numbers and don't want RDIs. */ 743 if (asidentifiers->asnum == NULL || asidentifiers->rdi != NULL) 744 goto out; 745 if (!X509v3_asid_inherits(asidentifiers)) 746 goto out; 747 748 rc = 1; 749 out: 750 ASIdentifiers_free(asidentifiers); 751 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free); 752 return rc; 753} 754 755/* 756 * Check whether at least one RFC 3779 extension is set to inherit. 757 * Return 1 if an inherit element is encountered in AS or IP. 758 * Return 0 otherwise. 759 */ 760int 761x509_any_inherits(X509 *x) 762{ 763 STACK_OF(IPAddressFamily) *addrblk = NULL; 764 ASIdentifiers *asidentifiers = NULL; 765 int crit, rc = 0; 766 767 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL); 768 if (addrblk == NULL && crit != -1) 769 warnx("error parsing ipAddrBlock"); 770 if (X509v3_addr_inherits(addrblk)) 771 rc = 1; 772 773 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &crit, 774 NULL); 775 if (asidentifiers == NULL && crit != -1) 776 warnx("error parsing asIdentifiers"); 777 if (X509v3_asid_inherits(asidentifiers)) 778 rc = 1; 779 780 ASIdentifiers_free(asidentifiers); 781 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free); 782 return rc; 783} 784 785/* 786 * Parse the very specific subset of information in the CRL distribution 787 * point extension. 788 * See RFC 6487, section 4.8.6 for details. 789 * Returns NULL on failure, the crl URI on success which has to be freed 790 * after use. 791 */ 792int 793x509_get_crl(X509 *x, const char *fn, char **out_crl) 794{ 795 CRL_DIST_POINTS *crldp; 796 DIST_POINT *dp; 797 GENERAL_NAMES *names; 798 GENERAL_NAME *name; 799 int i, crit, rc = 0; 800 801 assert(*out_crl == NULL); 802 803 crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &crit, NULL); 804 if (crldp == NULL) { 805 if (crit != -1) { 806 warnx("%s: RFC 6487 section 4.8.6: failed to parse " 807 "CRL distribution points", fn); 808 return 0; 809 } 810 return 1; 811 } 812 813 if (crit != 0) { 814 warnx("%s: RFC 6487 section 4.8.6: " 815 "CRL distribution point: extension not non-critical", fn); 816 goto out; 817 } 818 819 if (sk_DIST_POINT_num(crldp) != 1) { 820 warnx("%s: RFC 6487 section 4.8.6: CRL: " 821 "want 1 element, have %d", fn, 822 sk_DIST_POINT_num(crldp)); 823 goto out; 824 } 825 826 dp = sk_DIST_POINT_value(crldp, 0); 827 if (dp->CRLissuer != NULL) { 828 warnx("%s: RFC 6487 section 4.8.6: CRL CRLIssuer field" 829 " disallowed", fn); 830 goto out; 831 } 832 if (dp->reasons != NULL) { 833 warnx("%s: RFC 6487 section 4.8.6: CRL Reasons field" 834 " disallowed", fn); 835 goto out; 836 } 837 if (dp->distpoint == NULL) { 838 warnx("%s: RFC 6487 section 4.8.6: CRL: " 839 "no distribution point name", fn); 840 goto out; 841 } 842 if (dp->distpoint->dpname != NULL) { 843 warnx("%s: RFC 6487 section 4.8.6: nameRelativeToCRLIssuer" 844 " disallowed", fn); 845 goto out; 846 } 847 /* Need to hardcode the alternative 0 due to missing macros or enum. */ 848 if (dp->distpoint->type != 0) { 849 warnx("%s: RFC 6487 section 4.8.6: CRL DistributionPointName:" 850 " expected fullName, have %d", fn, dp->distpoint->type); 851 goto out; 852 } 853 854 names = dp->distpoint->name.fullname; 855 for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { 856 char *crl = NULL; 857 858 name = sk_GENERAL_NAME_value(names, i); 859 860 if (!x509_location(fn, "CRL distribution point", name, &crl)) 861 goto out; 862 863 if (*out_crl == NULL && strncasecmp(crl, RSYNC_PROTO, 864 RSYNC_PROTO_LEN) == 0) { 865 *out_crl = crl; 866 continue; 867 } 868 if (verbose) 869 warnx("%s: ignoring CRL distribution point %s", 870 fn, crl); 871 free(crl); 872 } 873 874 if (*out_crl == NULL) { 875 warnx("%s: RFC 6487 section 4.8.6: no rsync URI " 876 "in CRL distributionPoint", fn); 877 goto out; 878 } 879 880 rc = 1; 881 882 out: 883 CRL_DIST_POINTS_free(crldp); 884 return rc; 885} 886 887/* 888 * Convert passed ASN1_TIME to time_t *t. 889 * Returns 1 on success and 0 on failure. 890 */ 891int 892x509_get_time(const ASN1_TIME *at, time_t *t) 893{ 894 struct tm tm; 895 896 *t = 0; 897 memset(&tm, 0, sizeof(tm)); 898 /* Fail instead of silently falling back to the current time. */ 899 if (at == NULL) 900 return 0; 901 if (!ASN1_TIME_to_tm(at, &tm)) 902 return 0; 903 if ((*t = timegm(&tm)) == -1) 904 errx(1, "timegm failed"); 905 return 1; 906} 907 908/* 909 * Extract and validate an accessLocation, RFC 6487, 4.8 and RFC 8182, 3.2. 910 * Returns 0 on failure and 1 on success. 911 */ 912int 913x509_location(const char *fn, const char *descr, GENERAL_NAME *location, 914 char **out) 915{ 916 ASN1_IA5STRING *uri; 917 918 assert(*out == NULL); 919 920 if (location->type != GEN_URI) { 921 warnx("%s: RFC 6487 section 4.8: %s not URI", fn, descr); 922 return 0; 923 } 924 925 uri = location->d.uniformResourceIdentifier; 926 927 if (!valid_uri(uri->data, uri->length, NULL)) { 928 warnx("%s: RFC 6487 section 4.8: %s bad location", fn, descr); 929 return 0; 930 } 931 932 if ((*out = strndup(uri->data, uri->length)) == NULL) 933 err(1, NULL); 934 935 return 1; 936} 937 938/* 939 * Check that subject or issuer only contain commonName and serialNumber. 940 * Return 0 on failure. 941 */ 942int 943x509_valid_name(const char *fn, const char *descr, const X509_NAME *xn) 944{ 945 const X509_NAME_ENTRY *ne; 946 const ASN1_OBJECT *ao; 947 const ASN1_STRING *as; 948 int cn = 0, sn = 0; 949 int i, nid; 950 951 for (i = 0; i < X509_NAME_entry_count(xn); i++) { 952 if ((ne = X509_NAME_get_entry(xn, i)) == NULL) { 953 warnx("%s: X509_NAME_get_entry", fn); 954 return 0; 955 } 956 if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) { 957 warnx("%s: X509_NAME_ENTRY_get_object", fn); 958 return 0; 959 } 960 961 nid = OBJ_obj2nid(ao); 962 switch (nid) { 963 case NID_commonName: 964 if (cn++ > 0) { 965 warnx("%s: duplicate commonName in %s", 966 fn, descr); 967 return 0; 968 } 969 if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) { 970 warnx("%s: X509_NAME_ENTRY_get_data failed", 971 fn); 972 return 0; 973 } 974/* 975 * The following check can be enabled after AFRINIC re-issues CA certs. 976 * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html 977 */ 978#if 0 979 /* 980 * XXX - For some reason RFC 8209, section 3.1.1 decided 981 * to allow UTF8String for BGPsec Router Certificates. 982 */ 983 if (ASN1_STRING_type(as) != V_ASN1_PRINTABLESTRING) { 984 warnx("%s: RFC 6487 section 4.5: commonName is" 985 " not PrintableString", fn); 986 return 0; 987 } 988#endif 989 break; 990 case NID_serialNumber: 991 if (sn++ > 0) { 992 warnx("%s: duplicate serialNumber in %s", 993 fn, descr); 994 return 0; 995 } 996 break; 997 case NID_undef: 998 warnx("%s: OBJ_obj2nid failed", fn); 999 return 0; 1000 default: 1001 warnx("%s: RFC 6487 section 4.5: unexpected attribute" 1002 " %s in %s", fn, nid2str(nid), descr); 1003 return 0; 1004 } 1005 } 1006 1007 if (cn == 0) { 1008 warnx("%s: RFC 6487 section 4.5: %s missing commonName", 1009 fn, descr); 1010 return 0; 1011 } 1012 1013 return 1; 1014} 1015 1016/* 1017 * Convert an ASN1_INTEGER into a hexstring, enforcing that it is non-negative 1018 * and representable by at most 20 octets (RFC 5280, section 4.1.2.2). 1019 * Returned string needs to be freed by the caller. 1020 */ 1021char * 1022x509_convert_seqnum(const char *fn, const ASN1_INTEGER *i) 1023{ 1024 BIGNUM *seqnum = NULL; 1025 char *s = NULL; 1026 1027 if (i == NULL) 1028 goto out; 1029 1030 if (ASN1_STRING_length(i) > 20) { 1031 warnx("%s: %s: want 20 octets or fewer, have more.", 1032 __func__, fn); 1033 goto out; 1034 } 1035 1036 seqnum = ASN1_INTEGER_to_BN(i, NULL); 1037 if (seqnum == NULL) { 1038 warnx("%s: ASN1_INTEGER_to_BN error", fn); 1039 goto out; 1040 } 1041 1042 if (BN_is_negative(seqnum)) { 1043 warnx("%s: %s: want positive integer, have negative.", 1044 __func__, fn); 1045 goto out; 1046 } 1047 1048 s = BN_bn2hex(seqnum); 1049 if (s == NULL) 1050 warnx("%s: BN_bn2hex error", fn); 1051 1052 out: 1053 BN_free(seqnum); 1054 return s; 1055} 1056 1057/* 1058 * Find the closest expiry moment by walking the chain of authorities. 1059 */ 1060time_t 1061x509_find_expires(time_t notafter, struct auth *a, struct crl_tree *crlt) 1062{ 1063 struct crl *crl; 1064 time_t expires; 1065 1066 expires = notafter; 1067 1068 for (; a != NULL; a = a->issuer) { 1069 if (expires > a->cert->notafter) 1070 expires = a->cert->notafter; 1071 crl = crl_get(crlt, a); 1072 if (crl != NULL && expires > crl->nextupdate) 1073 expires = crl->nextupdate; 1074 } 1075 1076 return expires; 1077} 1078