1 /* $OpenBSD: x509.c,v 1.105 2024/12/03 14:51:09 job 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 31 ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */ 32 ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */ 33 ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */ 34 ASN1_OBJECT *signedobj_oid; /* 1.3.6.1.5.5.7.48.11 (signedObject) */ 35 ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */ 36 ASN1_OBJECT *roa_oid; /* id-ct-routeOriginAuthz CMS content type */ 37 ASN1_OBJECT *mft_oid; /* id-ct-rpkiManifest CMS content type */ 38 ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */ 39 ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */ 40 ASN1_OBJECT *cnt_type_oid; /* pkcs-9 id-contentType */ 41 ASN1_OBJECT *msg_dgst_oid; /* pkcs-9 id-messageDigest */ 42 ASN1_OBJECT *sign_time_oid; /* pkcs-9 id-signingTime */ 43 ASN1_OBJECT *rsc_oid; /* id-ct-signedChecklist */ 44 ASN1_OBJECT *aspa_oid; /* id-ct-ASPA */ 45 ASN1_OBJECT *tak_oid; /* id-ct-SignedTAL */ 46 ASN1_OBJECT *geofeed_oid; /* id-ct-geofeedCSVwithCRLF */ 47 ASN1_OBJECT *spl_oid; /* id-ct-signedPrefixList */ 48 49 static 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 123 void 124 x509_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 */ 145 int 146 x509_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 */ 160 int 161 x509_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; 209 out: 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 */ 220 int 221 x509_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 */ 274 enum cert_purpose 275 x509_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 */ 412 char * 413 x509_get_pubkey(X509 *x, const char *fn) 414 { 415 EVP_PKEY *pkey; 416 const EC_KEY *eckey; 417 const EC_GROUP *ecg; 418 int nid; 419 const char *cname; 420 uint8_t *pubkey = NULL; 421 char *res = NULL; 422 int len; 423 424 pkey = X509_get0_pubkey(x); 425 if (pkey == NULL) { 426 warnx("%s: X509_get0_pubkey failed in %s", fn, __func__); 427 goto out; 428 } 429 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { 430 warnx("%s: Expected EVP_PKEY_EC, got %d", fn, 431 EVP_PKEY_base_id(pkey)); 432 goto out; 433 } 434 435 eckey = EVP_PKEY_get0_EC_KEY(pkey); 436 if (eckey == NULL) { 437 warnx("%s: Incorrect key type", fn); 438 goto out; 439 } 440 441 if ((ecg = EC_KEY_get0_group(eckey)) == NULL) { 442 warnx("%s: EC_KEY_get0_group failed", fn); 443 goto out; 444 } 445 446 if (EC_GROUP_get_asn1_flag(ecg) != OPENSSL_EC_NAMED_CURVE) { 447 warnx("%s: curve encoding issue", fn); 448 goto out; 449 } 450 451 if (EC_GROUP_get_point_conversion_form(ecg) != 452 POINT_CONVERSION_UNCOMPRESSED) 453 warnx("%s: unconventional point encoding", fn); 454 455 nid = EC_GROUP_get_curve_name(ecg); 456 if (nid != NID_X9_62_prime256v1) { 457 if ((cname = EC_curve_nid2nist(nid)) == NULL) 458 cname = nid2str(nid); 459 warnx("%s: Expected P-256, got %s", fn, cname); 460 goto out; 461 } 462 463 if (!EC_KEY_check_key(eckey)) { 464 warnx("%s: EC_KEY_check_key failed in %s", fn, __func__); 465 goto out; 466 } 467 468 len = i2d_PUBKEY(pkey, &pubkey); 469 if (len <= 0) { 470 warnx("%s: i2d_PUBKEY failed in %s", fn, __func__); 471 goto out; 472 } 473 474 if (base64_encode(pubkey, len, &res) == -1) 475 errx(1, "base64_encode failed in %s", __func__); 476 477 out: 478 free(pubkey); 479 return res; 480 } 481 482 /* 483 * Compute the SKI of an RSA public key in an X509_PUBKEY using SHA-1. 484 * Returns allocated hex-encoded SKI on success, NULL on failure. 485 */ 486 char * 487 x509_pubkey_get_ski(X509_PUBKEY *pubkey, const char *fn) 488 { 489 ASN1_OBJECT *obj; 490 const unsigned char *der; 491 int der_len, nid; 492 unsigned char md[EVP_MAX_MD_SIZE]; 493 unsigned int md_len = EVP_MAX_MD_SIZE; 494 495 if (!X509_PUBKEY_get0_param(&obj, &der, &der_len, NULL, pubkey)) { 496 warnx("%s: X509_PUBKEY_get0_param failed", fn); 497 return NULL; 498 } 499 500 /* XXX - should allow other keys as well. */ 501 if ((nid = OBJ_obj2nid(obj)) != NID_rsaEncryption) { 502 warnx("%s: RFC 7935: wrong signature algorithm %s, want %s", 503 fn, nid2str(nid), LN_rsaEncryption); 504 return NULL; 505 } 506 507 if (!EVP_Digest(der, der_len, md, &md_len, EVP_sha1(), NULL)) { 508 warnx("%s: EVP_Digest failed", fn); 509 return NULL; 510 } 511 512 return hex_encode(md, md_len); 513 } 514 515 /* 516 * Parse the Authority Information Access (AIA) extension 517 * See RFC 6487, section 4.8.7 for details. 518 * Returns NULL on failure, on success returns the AIA URI 519 * (which has to be freed after use). 520 */ 521 int 522 x509_get_aia(X509 *x, const char *fn, char **out_aia) 523 { 524 ACCESS_DESCRIPTION *ad; 525 AUTHORITY_INFO_ACCESS *info; 526 int crit, rc = 0; 527 528 assert(*out_aia == NULL); 529 530 info = X509_get_ext_d2i(x, NID_info_access, &crit, NULL); 531 if (info == NULL) { 532 if (crit != -1) { 533 warnx("%s: RFC 6487 section 4.8.7: error parsing AIA", 534 fn); 535 return 0; 536 } 537 return 1; 538 } 539 540 if (crit != 0) { 541 warnx("%s: RFC 6487 section 4.8.7: " 542 "AIA: extension not non-critical", fn); 543 goto out; 544 } 545 546 if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0) { 547 warnx("%s: RFC 6487 section 4.8.7: AIA must be absent from " 548 "a self-signed certificate", fn); 549 goto out; 550 } 551 552 if (sk_ACCESS_DESCRIPTION_num(info) != 1) { 553 warnx("%s: RFC 6487 section 4.8.7: AIA: " 554 "want 1 element, have %d", fn, 555 sk_ACCESS_DESCRIPTION_num(info)); 556 goto out; 557 } 558 559 ad = sk_ACCESS_DESCRIPTION_value(info, 0); 560 if (OBJ_obj2nid(ad->method) != NID_ad_ca_issuers) { 561 warnx("%s: RFC 6487 section 4.8.7: AIA: " 562 "expected caIssuers, have %d", fn, OBJ_obj2nid(ad->method)); 563 goto out; 564 } 565 566 if (!x509_location(fn, "AIA: caIssuers", ad->location, out_aia)) 567 goto out; 568 569 rc = 1; 570 571 out: 572 AUTHORITY_INFO_ACCESS_free(info); 573 return rc; 574 } 575 576 /* 577 * Parse the Subject Information Access (SIA) extension for an EE cert. 578 * See RFC 6487, section 4.8.8.2 for details. 579 * Returns NULL on failure, on success returns the SIA signedObject URI 580 * (which has to be freed after use). 581 */ 582 int 583 x509_get_sia(X509 *x, const char *fn, char **out_sia) 584 { 585 ACCESS_DESCRIPTION *ad; 586 AUTHORITY_INFO_ACCESS *info; 587 ASN1_OBJECT *oid; 588 int i, crit, rc = 0; 589 590 assert(*out_sia == NULL); 591 592 info = X509_get_ext_d2i(x, NID_sinfo_access, &crit, NULL); 593 if (info == NULL) { 594 if (crit != -1) { 595 warnx("%s: error parsing SIA", fn); 596 return 0; 597 } 598 return 1; 599 } 600 601 if (crit != 0) { 602 warnx("%s: RFC 6487 section 4.8.8: " 603 "SIA: extension not non-critical", fn); 604 goto out; 605 } 606 607 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { 608 char *sia; 609 610 ad = sk_ACCESS_DESCRIPTION_value(info, i); 611 oid = ad->method; 612 613 /* 614 * XXX: RFC 6487 4.8.8.2 states that the accessMethod MUST be 615 * signedObject. However, rpkiNotify accessMethods currently 616 * exist in the wild. Consider removing this special case. 617 * See also https://www.rfc-editor.org/errata/eid7239. 618 */ 619 if (OBJ_cmp(oid, notify_oid) == 0) { 620 if (verbose > 1) 621 warnx("%s: RFC 6487 section 4.8.8.2: SIA should" 622 " not contain rpkiNotify accessMethod", fn); 623 continue; 624 } 625 if (OBJ_cmp(oid, signedobj_oid) != 0) { 626 char buf[128]; 627 628 OBJ_obj2txt(buf, sizeof(buf), oid, 0); 629 warnx("%s: RFC 6487 section 4.8.8.2: unexpected" 630 " accessMethod: %s", fn, buf); 631 goto out; 632 } 633 634 sia = NULL; 635 if (!x509_location(fn, "SIA: signedObject", ad->location, &sia)) 636 goto out; 637 638 if (*out_sia == NULL && strncasecmp(sia, RSYNC_PROTO, 639 RSYNC_PROTO_LEN) == 0) { 640 const char *p = sia + RSYNC_PROTO_LEN; 641 size_t fnlen, plen; 642 643 if (filemode) { 644 *out_sia = sia; 645 continue; 646 } 647 648 fnlen = strlen(fn); 649 plen = strlen(p); 650 651 if (fnlen < plen || strcmp(p, fn + fnlen - plen) != 0) { 652 warnx("%s: mismatch between pathname and SIA " 653 "(%s)", fn, sia); 654 free(sia); 655 goto out; 656 } 657 658 *out_sia = sia; 659 continue; 660 } 661 if (verbose) 662 warnx("%s: RFC 6487 section 4.8.8: SIA: " 663 "ignoring location %s", fn, sia); 664 free(sia); 665 } 666 667 if (*out_sia == NULL) { 668 warnx("%s: RFC 6487 section 4.8.8.2: " 669 "SIA without rsync accessLocation", fn); 670 goto out; 671 } 672 673 rc = 1; 674 675 out: 676 AUTHORITY_INFO_ACCESS_free(info); 677 return rc; 678 } 679 680 /* 681 * Extract the notBefore of a certificate. 682 */ 683 int 684 x509_get_notbefore(X509 *x, const char *fn, time_t *tt) 685 { 686 const ASN1_TIME *at; 687 688 at = X509_get0_notBefore(x); 689 if (at == NULL) { 690 warnx("%s: X509_get0_notBefore failed", fn); 691 return 0; 692 } 693 if (!x509_get_time(at, tt)) { 694 warnx("%s: ASN1_TIME_to_tm failed", fn); 695 return 0; 696 } 697 return 1; 698 } 699 700 /* 701 * Extract the notAfter from a certificate. 702 */ 703 int 704 x509_get_notafter(X509 *x, const char *fn, time_t *tt) 705 { 706 const ASN1_TIME *at; 707 708 at = X509_get0_notAfter(x); 709 if (at == NULL) { 710 warnx("%s: X509_get0_notafter failed", fn); 711 return 0; 712 } 713 if (!x509_get_time(at, tt)) { 714 warnx("%s: ASN1_TIME_to_tm failed", fn); 715 return 0; 716 } 717 return 1; 718 } 719 720 /* 721 * Check whether all RFC 3779 extensions are set to inherit. 722 * Return 1 if both AS & IP are set to inherit. 723 * Return 0 on failure (such as missing extensions or no inheritance). 724 */ 725 int 726 x509_inherits(X509 *x) 727 { 728 STACK_OF(IPAddressFamily) *addrblk = NULL; 729 ASIdentifiers *asidentifiers = NULL; 730 const IPAddressFamily *af; 731 int crit, i, rc = 0; 732 733 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL); 734 if (addrblk == NULL) { 735 if (crit != -1) 736 warnx("error parsing ipAddrBlock"); 737 goto out; 738 } 739 740 /* 741 * Check by hand, since X509v3_addr_inherits() success only means that 742 * at least one address family inherits, not all of them. 743 */ 744 for (i = 0; i < sk_IPAddressFamily_num(addrblk); i++) { 745 af = sk_IPAddressFamily_value(addrblk, i); 746 if (af->ipAddressChoice->type != IPAddressChoice_inherit) 747 goto out; 748 } 749 750 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, NULL, 751 NULL); 752 if (asidentifiers == NULL) { 753 if (crit != -1) 754 warnx("error parsing asIdentifiers"); 755 goto out; 756 } 757 758 /* We need to have AS numbers and don't want RDIs. */ 759 if (asidentifiers->asnum == NULL || asidentifiers->rdi != NULL) 760 goto out; 761 if (!X509v3_asid_inherits(asidentifiers)) 762 goto out; 763 764 rc = 1; 765 out: 766 ASIdentifiers_free(asidentifiers); 767 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free); 768 return rc; 769 } 770 771 /* 772 * Check whether at least one RFC 3779 extension is set to inherit. 773 * Return 1 if an inherit element is encountered in AS or IP. 774 * Return 0 otherwise. 775 */ 776 int 777 x509_any_inherits(X509 *x) 778 { 779 STACK_OF(IPAddressFamily) *addrblk = NULL; 780 ASIdentifiers *asidentifiers = NULL; 781 int crit, rc = 0; 782 783 addrblk = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL); 784 if (addrblk == NULL && crit != -1) 785 warnx("error parsing ipAddrBlock"); 786 if (X509v3_addr_inherits(addrblk)) 787 rc = 1; 788 789 asidentifiers = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &crit, 790 NULL); 791 if (asidentifiers == NULL && crit != -1) 792 warnx("error parsing asIdentifiers"); 793 if (X509v3_asid_inherits(asidentifiers)) 794 rc = 1; 795 796 ASIdentifiers_free(asidentifiers); 797 sk_IPAddressFamily_pop_free(addrblk, IPAddressFamily_free); 798 return rc; 799 } 800 801 /* 802 * Parse the very specific subset of information in the CRL distribution 803 * point extension. 804 * See RFC 6487, section 4.8.6 for details. 805 * Returns NULL on failure, the crl URI on success which has to be freed 806 * after use. 807 */ 808 int 809 x509_get_crl(X509 *x, const char *fn, char **out_crl) 810 { 811 CRL_DIST_POINTS *crldp; 812 DIST_POINT *dp; 813 GENERAL_NAMES *names; 814 GENERAL_NAME *name; 815 int i, crit, rc = 0; 816 817 assert(*out_crl == NULL); 818 819 crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &crit, NULL); 820 if (crldp == NULL) { 821 if (crit != -1) { 822 warnx("%s: RFC 6487 section 4.8.6: failed to parse " 823 "CRL distribution points", fn); 824 return 0; 825 } 826 return 1; 827 } 828 829 if (crit != 0) { 830 warnx("%s: RFC 6487 section 4.8.6: " 831 "CRL distribution point: extension not non-critical", fn); 832 goto out; 833 } 834 835 if (sk_DIST_POINT_num(crldp) != 1) { 836 warnx("%s: RFC 6487 section 4.8.6: CRL: " 837 "want 1 element, have %d", fn, 838 sk_DIST_POINT_num(crldp)); 839 goto out; 840 } 841 842 dp = sk_DIST_POINT_value(crldp, 0); 843 if (dp->CRLissuer != NULL) { 844 warnx("%s: RFC 6487 section 4.8.6: CRL CRLIssuer field" 845 " disallowed", fn); 846 goto out; 847 } 848 if (dp->reasons != NULL) { 849 warnx("%s: RFC 6487 section 4.8.6: CRL Reasons field" 850 " disallowed", fn); 851 goto out; 852 } 853 if (dp->distpoint == NULL) { 854 warnx("%s: RFC 6487 section 4.8.6: CRL: " 855 "no distribution point name", fn); 856 goto out; 857 } 858 if (dp->distpoint->dpname != NULL) { 859 warnx("%s: RFC 6487 section 4.8.6: nameRelativeToCRLIssuer" 860 " disallowed", fn); 861 goto out; 862 } 863 /* Need to hardcode the alternative 0 due to missing macros or enum. */ 864 if (dp->distpoint->type != 0) { 865 warnx("%s: RFC 6487 section 4.8.6: CRL DistributionPointName:" 866 " expected fullName, have %d", fn, dp->distpoint->type); 867 goto out; 868 } 869 870 names = dp->distpoint->name.fullname; 871 for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { 872 char *crl = NULL; 873 874 name = sk_GENERAL_NAME_value(names, i); 875 876 if (!x509_location(fn, "CRL distribution point", name, &crl)) 877 goto out; 878 879 if (*out_crl == NULL && strncasecmp(crl, RSYNC_PROTO, 880 RSYNC_PROTO_LEN) == 0) { 881 *out_crl = crl; 882 continue; 883 } 884 if (verbose) 885 warnx("%s: ignoring CRL distribution point %s", 886 fn, crl); 887 free(crl); 888 } 889 890 if (*out_crl == NULL) { 891 warnx("%s: RFC 6487 section 4.8.6: no rsync URI " 892 "in CRL distributionPoint", fn); 893 goto out; 894 } 895 896 rc = 1; 897 898 out: 899 CRL_DIST_POINTS_free(crldp); 900 return rc; 901 } 902 903 /* 904 * Convert passed ASN1_TIME to time_t *t. 905 * Returns 1 on success and 0 on failure. 906 */ 907 int 908 x509_get_time(const ASN1_TIME *at, time_t *t) 909 { 910 struct tm tm; 911 912 *t = 0; 913 memset(&tm, 0, sizeof(tm)); 914 /* Fail instead of silently falling back to the current time. */ 915 if (at == NULL) 916 return 0; 917 if (!ASN1_TIME_to_tm(at, &tm)) 918 return 0; 919 if ((*t = timegm(&tm)) == -1) 920 errx(1, "timegm failed"); 921 return 1; 922 } 923 924 /* 925 * Extract and validate an accessLocation, RFC 6487, 4.8 and RFC 8182, 3.2. 926 * Returns 0 on failure and 1 on success. 927 */ 928 int 929 x509_location(const char *fn, const char *descr, GENERAL_NAME *location, 930 char **out) 931 { 932 ASN1_IA5STRING *uri; 933 934 assert(*out == NULL); 935 936 if (location->type != GEN_URI) { 937 warnx("%s: RFC 6487 section 4.8: %s not URI", fn, descr); 938 return 0; 939 } 940 941 uri = location->d.uniformResourceIdentifier; 942 943 if (!valid_uri(uri->data, uri->length, NULL)) { 944 warnx("%s: RFC 6487 section 4.8: %s bad location", fn, descr); 945 return 0; 946 } 947 948 if ((*out = strndup(uri->data, uri->length)) == NULL) 949 err(1, NULL); 950 951 return 1; 952 } 953 954 /* 955 * Check that subject or issuer only contain commonName and serialNumber. 956 * Return 0 on failure. 957 */ 958 int 959 x509_valid_name(const char *fn, const char *descr, const X509_NAME *xn) 960 { 961 const X509_NAME_ENTRY *ne; 962 const ASN1_OBJECT *ao; 963 const ASN1_STRING *as; 964 int cn = 0, sn = 0; 965 int i, nid; 966 967 for (i = 0; i < X509_NAME_entry_count(xn); i++) { 968 if ((ne = X509_NAME_get_entry(xn, i)) == NULL) { 969 warnx("%s: X509_NAME_get_entry", fn); 970 return 0; 971 } 972 if ((ao = X509_NAME_ENTRY_get_object(ne)) == NULL) { 973 warnx("%s: X509_NAME_ENTRY_get_object", fn); 974 return 0; 975 } 976 977 nid = OBJ_obj2nid(ao); 978 switch (nid) { 979 case NID_commonName: 980 if (cn++ > 0) { 981 warnx("%s: duplicate commonName in %s", 982 fn, descr); 983 return 0; 984 } 985 if ((as = X509_NAME_ENTRY_get_data(ne)) == NULL) { 986 warnx("%s: X509_NAME_ENTRY_get_data failed", 987 fn); 988 return 0; 989 } 990 /* 991 * The following check can be enabled after AFRINIC re-issues CA certs. 992 * https://lists.afrinic.net/pipermail/dbwg/2023-March/000436.html 993 */ 994 #if 0 995 /* 996 * XXX - For some reason RFC 8209, section 3.1.1 decided 997 * to allow UTF8String for BGPsec Router Certificates. 998 */ 999 if (ASN1_STRING_type(as) != V_ASN1_PRINTABLESTRING) { 1000 warnx("%s: RFC 6487 section 4.5: commonName is" 1001 " not PrintableString", fn); 1002 return 0; 1003 } 1004 #endif 1005 break; 1006 case NID_serialNumber: 1007 if (sn++ > 0) { 1008 warnx("%s: duplicate serialNumber in %s", 1009 fn, descr); 1010 return 0; 1011 } 1012 break; 1013 case NID_undef: 1014 warnx("%s: OBJ_obj2nid failed", fn); 1015 return 0; 1016 default: 1017 warnx("%s: RFC 6487 section 4.5: unexpected attribute" 1018 " %s in %s", fn, nid2str(nid), descr); 1019 return 0; 1020 } 1021 } 1022 1023 if (cn == 0) { 1024 warnx("%s: RFC 6487 section 4.5: %s missing commonName", 1025 fn, descr); 1026 return 0; 1027 } 1028 1029 return 1; 1030 } 1031 1032 /* 1033 * Check ASN1_INTEGER is non-negative and fits in 20 octets. 1034 * Returns allocated BIGNUM if true, NULL otherwise. 1035 */ 1036 static BIGNUM * 1037 x509_seqnum_to_bn(const char *fn, const char *descr, const ASN1_INTEGER *i) 1038 { 1039 BIGNUM *bn = NULL; 1040 1041 if ((bn = ASN1_INTEGER_to_BN(i, NULL)) == NULL) { 1042 warnx("%s: %s: ASN1_INTEGER_to_BN error", fn, descr); 1043 goto out; 1044 } 1045 1046 if (BN_is_negative(bn)) { 1047 warnx("%s: %s should be non-negative", fn, descr); 1048 goto out; 1049 } 1050 1051 /* Reject values larger than or equal to 2^159. */ 1052 if (BN_num_bytes(bn) > 20 || BN_is_bit_set(bn, 159)) { 1053 warnx("%s: %s should fit in 20 octets", fn, descr); 1054 goto out; 1055 } 1056 1057 return bn; 1058 1059 out: 1060 BN_free(bn); 1061 return NULL; 1062 } 1063 1064 /* 1065 * Convert an ASN1_INTEGER into a hexstring, enforcing that it is non-negative 1066 * and representable by at most 20 octets (RFC 5280, section 4.1.2.2). 1067 * Returned string needs to be freed by the caller. 1068 */ 1069 char * 1070 x509_convert_seqnum(const char *fn, const char *descr, const ASN1_INTEGER *i) 1071 { 1072 BIGNUM *bn = NULL; 1073 char *s = NULL; 1074 1075 if (i == NULL) 1076 goto out; 1077 1078 if ((bn = x509_seqnum_to_bn(fn, descr, i)) == NULL) 1079 goto out; 1080 1081 if ((s = BN_bn2hex(bn)) == NULL) 1082 warnx("%s: %s: BN_bn2hex error", fn, descr); 1083 1084 out: 1085 BN_free(bn); 1086 return s; 1087 } 1088 1089 int 1090 x509_valid_seqnum(const char *fn, const char *descr, const ASN1_INTEGER *i) 1091 { 1092 BIGNUM *bn; 1093 1094 if ((bn = x509_seqnum_to_bn(fn, descr, i)) == NULL) 1095 return 0; 1096 1097 BN_free(bn); 1098 return 1; 1099 } 1100 1101 /* 1102 * Find the closest expiry moment by walking the chain of authorities. 1103 */ 1104 time_t 1105 x509_find_expires(time_t notafter, struct auth *a, struct crl_tree *crlt) 1106 { 1107 struct crl *crl; 1108 time_t expires; 1109 1110 expires = notafter; 1111 1112 for (; a != NULL; a = a->issuer) { 1113 if (expires > a->cert->notafter) 1114 expires = a->cert->notafter; 1115 crl = crl_get(crlt, a); 1116 if (crl != NULL && expires > crl->nextupdate) 1117 expires = crl->nextupdate; 1118 } 1119 1120 return expires; 1121 } 1122