1 /* $OpenBSD: validate.c,v 1.72 2024/02/22 12:49:42 job Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <arpa/inet.h> 19 #include <assert.h> 20 #include <ctype.h> 21 #include <err.h> 22 #include <fcntl.h> 23 #include <inttypes.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "extern.h" 29 30 extern ASN1_OBJECT *certpol_oid; 31 32 /* 33 * Walk up the chain of certificates trying to match our AS number to 34 * one of the allocations in that chain. 35 * Returns 1 if covered or 0 if not. 36 */ 37 static int 38 valid_as(struct auth *a, uint32_t min, uint32_t max) 39 { 40 int c; 41 42 if (a == NULL) 43 return 0; 44 45 /* Does this certificate cover our AS number? */ 46 c = as_check_covered(min, max, a->cert->as, a->cert->asz); 47 if (c > 0) 48 return 1; 49 else if (c < 0) 50 return 0; 51 52 /* If it inherits, walk up the chain. */ 53 return valid_as(a->parent, min, max); 54 } 55 56 /* 57 * Walk up the chain of certificates (really just the last one, but in 58 * the case of inheritance, the ones before) making sure that our IP 59 * prefix is covered in the first non-inheriting specification. 60 * Returns 1 if covered or 0 if not. 61 */ 62 static int 63 valid_ip(struct auth *a, enum afi afi, 64 const unsigned char *min, const unsigned char *max) 65 { 66 int c; 67 68 if (a == NULL) 69 return 0; 70 71 /* Does this certificate cover our IP prefix? */ 72 c = ip_addr_check_covered(afi, min, max, a->cert->ips, a->cert->ipsz); 73 if (c > 0) 74 return 1; 75 else if (c < 0) 76 return 0; 77 78 /* If it inherits, walk up the chain. */ 79 return valid_ip(a->parent, afi, min, max); 80 } 81 82 /* 83 * Make sure the AKI is the same as the AKI listed on the Manifest, 84 * and that the SKI doesn't already exist. 85 * Return the parent by its AKI, or NULL on failure. 86 */ 87 struct auth * 88 valid_ski_aki(const char *fn, struct auth_tree *auths, 89 const char *ski, const char *aki, const char *mftaki) 90 { 91 struct auth *a; 92 93 if (mftaki != NULL) { 94 if (strcmp(aki, mftaki) != 0) { 95 warnx("%s: AKI doesn't match Manifest AKI", fn); 96 return NULL; 97 } 98 } 99 100 if (auth_find(auths, ski) != NULL) { 101 warnx("%s: RFC 6487: duplicate SKI", fn); 102 return NULL; 103 } 104 105 a = auth_find(auths, aki); 106 if (a == NULL) 107 warnx("%s: RFC 6487: unknown AKI", fn); 108 109 return a; 110 } 111 112 /* 113 * Validate a trust anchor by making sure that the SKI is unique. 114 * Returns 1 if valid, 0 otherwise. 115 */ 116 int 117 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert) 118 { 119 /* SKI must not be a dupe. */ 120 if (auth_find(auths, cert->ski) != NULL) { 121 warnx("%s: RFC 6487: duplicate SKI", fn); 122 return 0; 123 } 124 125 return 1; 126 } 127 128 /* 129 * Validate a non-TA certificate: make sure its IP and AS resources are 130 * fully covered by those in the authority key (which must exist). 131 * Returns 1 if valid, 0 otherwise. 132 */ 133 int 134 valid_cert(const char *fn, struct auth *a, const struct cert *cert) 135 { 136 size_t i; 137 uint32_t min, max; 138 139 for (i = 0; i < cert->asz; i++) { 140 if (cert->as[i].type == CERT_AS_INHERIT) 141 continue; 142 143 if (cert->as[i].type == CERT_AS_ID) { 144 min = cert->as[i].id; 145 max = cert->as[i].id; 146 } else { 147 min = cert->as[i].range.min; 148 max = cert->as[i].range.max; 149 } 150 151 if (valid_as(a, min, max)) 152 continue; 153 154 as_warn(fn, "RFC 6487: uncovered resource", &cert->as[i]); 155 return 0; 156 } 157 158 for (i = 0; i < cert->ipsz; i++) { 159 if (cert->ips[i].type == CERT_IP_INHERIT) 160 continue; 161 162 if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, 163 cert->ips[i].max)) 164 continue; 165 166 ip_warn(fn, "RFC 6487: uncovered resource", &cert->ips[i]); 167 return 0; 168 } 169 170 return 1; 171 } 172 173 /* 174 * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained. 175 * Returns 1 if valid, 0 otherwise. 176 */ 177 int 178 valid_roa(const char *fn, struct cert *cert, struct roa *roa) 179 { 180 size_t i; 181 char buf[64]; 182 183 for (i = 0; i < roa->ipsz; i++) { 184 if (ip_addr_check_covered(roa->ips[i].afi, roa->ips[i].min, 185 roa->ips[i].max, cert->ips, cert->ipsz) > 0) 186 continue; 187 188 ip_addr_print(&roa->ips[i].addr, roa->ips[i].afi, buf, 189 sizeof(buf)); 190 warnx("%s: RFC 6482: uncovered IP: %s", fn, buf); 191 return 0; 192 } 193 194 return 1; 195 } 196 197 /* 198 * Validate our SPL: check that the asID is contained in the end-entity 199 * certificate's resources. 200 * Returns 1 if valid, 0 otherwise. 201 */ 202 int 203 valid_spl(const char *fn, struct cert *cert, struct spl *spl) 204 { 205 if (as_check_covered(spl->asid, spl->asid, cert->as, cert->asz) > 0) 206 return 1; 207 208 warnx("%s: SPL: uncovered ASID: %u", fn, spl->asid); 209 210 return 0; 211 } 212 213 /* 214 * Validate a file by verifying the SHA256 hash of that file. 215 * The file to check is passed as a file descriptor. 216 * Returns 1 if hash matched, 0 otherwise. Closes fd when done. 217 */ 218 int 219 valid_filehash(int fd, const char *hash, size_t hlen) 220 { 221 SHA256_CTX ctx; 222 char filehash[SHA256_DIGEST_LENGTH]; 223 char buffer[8192]; 224 ssize_t nr; 225 226 if (hlen != sizeof(filehash)) 227 errx(1, "bad hash size"); 228 229 if (fd == -1) 230 return 0; 231 232 SHA256_Init(&ctx); 233 while ((nr = read(fd, buffer, sizeof(buffer))) > 0) 234 SHA256_Update(&ctx, buffer, nr); 235 close(fd); 236 SHA256_Final(filehash, &ctx); 237 238 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 239 return 0; 240 return 1; 241 } 242 243 /* 244 * Same as above but with a buffer instead of a fd. 245 */ 246 int 247 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen) 248 { 249 char filehash[SHA256_DIGEST_LENGTH]; 250 251 if (hlen != sizeof(filehash)) 252 errx(1, "bad hash size"); 253 254 if (buf == NULL || len == 0) 255 return 0; 256 257 if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL)) 258 errx(1, "EVP_Digest failed"); 259 260 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 261 return 0; 262 return 1; 263 } 264 265 /* 266 * Validate that a filename only contains characters from the POSIX portable 267 * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278. 268 */ 269 int 270 valid_filename(const char *fn, size_t len) 271 { 272 const unsigned char *c; 273 size_t i; 274 275 for (c = fn, i = 0; i < len; i++, c++) 276 if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.') 277 return 0; 278 return 1; 279 } 280 281 /* 282 * Validate a URI to make sure it is pure ASCII and does not point backwards 283 * or doing some other silly tricks. To enforce the protocol pass either 284 * https:// or rsync:// as proto, if NULL is passed no protocol is enforced. 285 * Returns 1 if valid, 0 otherwise. 286 */ 287 int 288 valid_uri(const char *uri, size_t usz, const char *proto) 289 { 290 size_t s; 291 292 if (usz > MAX_URI_LENGTH) 293 return 0; 294 295 for (s = 0; s < usz; s++) 296 if (!isalnum((unsigned char)uri[s]) && 297 !ispunct((unsigned char)uri[s])) 298 return 0; 299 300 if (proto != NULL) { 301 s = strlen(proto); 302 if (s >= usz) 303 return 0; 304 if (strncasecmp(uri, proto, s) != 0) 305 return 0; 306 } 307 308 /* do not allow files or directories to start with a '.' */ 309 if (strstr(uri, "/.") != NULL) 310 return 0; 311 312 return 1; 313 } 314 315 /* 316 * Validate that a URI has the same host as the URI passed in proto. 317 * Returns 1 if valid, 0 otherwise. 318 */ 319 int 320 valid_origin(const char *uri, const char *proto) 321 { 322 const char *to; 323 324 /* extract end of host from proto URI */ 325 to = strstr(proto, "://"); 326 if (to == NULL) 327 return 0; 328 to += strlen("://"); 329 if ((to = strchr(to, '/')) == NULL) 330 return 0; 331 332 /* compare hosts including the / for the start of the path section */ 333 if (strncasecmp(uri, proto, to - proto + 1) != 0) 334 return 0; 335 336 return 1; 337 } 338 339 /* 340 * Walk the tree of known valid CA certificates until we find a certificate that 341 * doesn't inherit. Build a chain of intermediates and use the non-inheriting 342 * certificate as a trusted root by virtue of X509_V_FLAG_PARTIAL_CHAIN. The 343 * RFC 3779 path validation needs a non-inheriting trust root to ensure that 344 * all delegated resources are covered. 345 */ 346 static void 347 build_chain(const struct auth *a, STACK_OF(X509) **intermediates, 348 STACK_OF(X509) **root) 349 { 350 *intermediates = NULL; 351 *root = NULL; 352 353 if (a == NULL) 354 return; 355 356 if ((*intermediates = sk_X509_new_null()) == NULL) 357 err(1, "sk_X509_new_null"); 358 if ((*root = sk_X509_new_null()) == NULL) 359 err(1, "sk_X509_new_null"); 360 for (; a != NULL; a = a->parent) { 361 assert(a->cert->x509 != NULL); 362 if (!a->any_inherits) { 363 if (!sk_X509_push(*root, a->cert->x509)) 364 errx(1, "sk_X509_push"); 365 break; 366 } 367 if (!sk_X509_push(*intermediates, a->cert->x509)) 368 errx(1, "sk_X509_push"); 369 } 370 assert(sk_X509_num(*root) == 1); 371 } 372 373 /* 374 * Add the CRL based on the certs SKI value. 375 * No need to insert any other CRL since those were already checked. 376 */ 377 static void 378 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls) 379 { 380 *crls = NULL; 381 382 if (crl == NULL) 383 return; 384 if ((*crls = sk_X509_CRL_new_null()) == NULL) 385 errx(1, "sk_X509_CRL_new_null"); 386 if (!sk_X509_CRL_push(*crls, crl->x509_crl)) 387 err(1, "sk_X509_CRL_push"); 388 } 389 390 /* 391 * Attempt to upgrade the generic 'certificate revoked' message to include 392 * a timestamp. 393 */ 394 static void 395 pretty_revocation_time(X509 *x509, X509_CRL *crl, const char **errstr) 396 { 397 static char buf[64]; 398 X509_REVOKED *revoked; 399 const ASN1_TIME *atime; 400 time_t t; 401 402 if (X509_CRL_get0_by_cert(crl, &revoked, x509) != 1) 403 return; 404 if ((atime = X509_REVOKED_get0_revocationDate(revoked)) == NULL) 405 return; 406 if (!x509_get_time(atime, &t)) 407 return; 408 409 snprintf(buf, sizeof(buf), "certificate revoked on %s", time2str(t)); 410 *errstr = buf; 411 } 412 413 /* 414 * Validate the X509 certificate. Returns 1 for valid certificates, 415 * returns 0 if there is a verify error and sets *errstr to the error 416 * returned by X509_verify_cert_error_string(). 417 */ 418 int 419 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a, 420 struct crl *crl, const char **errstr) 421 { 422 X509_VERIFY_PARAM *params; 423 ASN1_OBJECT *cp_oid; 424 STACK_OF(X509) *intermediates, *root; 425 STACK_OF(X509_CRL) *crls = NULL; 426 unsigned long flags; 427 int error; 428 429 *errstr = NULL; 430 build_chain(a, &intermediates, &root); 431 build_crls(crl, &crls); 432 433 assert(store_ctx != NULL); 434 assert(x509 != NULL); 435 if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL)) 436 err(1, "X509_STORE_CTX_init"); 437 438 if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL) 439 errx(1, "X509_STORE_CTX_get0_param"); 440 if ((cp_oid = OBJ_dup(certpol_oid)) == NULL) 441 err(1, "OBJ_dup"); 442 if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid)) 443 err(1, "X509_VERIFY_PARAM_add0_policy"); 444 X509_VERIFY_PARAM_set_time(params, get_current_time()); 445 446 flags = X509_V_FLAG_CRL_CHECK; 447 flags |= X509_V_FLAG_PARTIAL_CHAIN; 448 flags |= X509_V_FLAG_POLICY_CHECK; 449 flags |= X509_V_FLAG_EXPLICIT_POLICY; 450 flags |= X509_V_FLAG_INHIBIT_MAP; 451 X509_STORE_CTX_set_flags(store_ctx, flags); 452 X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH); 453 /* 454 * See the comment above build_chain() for details on what's happening 455 * here. The nomenclature in this API is dubious and poorly documented. 456 */ 457 X509_STORE_CTX_set0_untrusted(store_ctx, intermediates); 458 X509_STORE_CTX_set0_trusted_stack(store_ctx, root); 459 X509_STORE_CTX_set0_crls(store_ctx, crls); 460 461 if (X509_verify_cert(store_ctx) <= 0) { 462 error = X509_STORE_CTX_get_error(store_ctx); 463 *errstr = X509_verify_cert_error_string(error); 464 if (filemode && error == X509_V_ERR_CERT_REVOKED) 465 pretty_revocation_time(x509, crl->x509_crl, errstr); 466 X509_STORE_CTX_cleanup(store_ctx); 467 sk_X509_free(intermediates); 468 sk_X509_free(root); 469 sk_X509_CRL_free(crls); 470 return 0; 471 } 472 473 X509_STORE_CTX_cleanup(store_ctx); 474 sk_X509_free(intermediates); 475 sk_X509_free(root); 476 sk_X509_CRL_free(crls); 477 return 1; 478 } 479 480 /* 481 * Validate our RSC: check that all items in the ResourceBlock are contained. 482 * Returns 1 if valid, 0 otherwise. 483 */ 484 int 485 valid_rsc(const char *fn, struct cert *cert, struct rsc *rsc) 486 { 487 size_t i; 488 uint32_t min, max; 489 490 for (i = 0; i < rsc->asz; i++) { 491 if (rsc->as[i].type == CERT_AS_ID) { 492 min = rsc->as[i].id; 493 max = rsc->as[i].id; 494 } else { 495 min = rsc->as[i].range.min; 496 max = rsc->as[i].range.max; 497 } 498 499 if (as_check_covered(min, max, cert->as, cert->asz) > 0) 500 continue; 501 502 as_warn(fn, "RSC ResourceBlock uncovered", &rsc->as[i]); 503 return 0; 504 } 505 506 for (i = 0; i < rsc->ipsz; i++) { 507 if (ip_addr_check_covered(rsc->ips[i].afi, rsc->ips[i].min, 508 rsc->ips[i].max, cert->ips, cert->ipsz) > 0) 509 continue; 510 511 ip_warn(fn, "RSC ResourceBlock uncovered", &rsc->ips[i]); 512 return 0; 513 } 514 515 return 1; 516 } 517 518 int 519 valid_econtent_version(const char *fn, const ASN1_INTEGER *aint, 520 uint64_t expected) 521 { 522 uint64_t version; 523 524 if (aint == NULL) { 525 if (expected == 0) 526 return 1; 527 warnx("%s: unexpected version 0", fn); 528 return 0; 529 } 530 531 if (!ASN1_INTEGER_get_uint64(&version, aint)) { 532 warnx("%s: ASN1_INTEGER_get_uint64 failed", fn); 533 return 0; 534 } 535 536 if (version == 0) { 537 warnx("%s: incorrect encoding for version 0", fn); 538 return 0; 539 } 540 541 if (version != expected) { 542 warnx("%s: unexpected version (expected %llu, got %llu)", fn, 543 (unsigned long long)expected, (unsigned long long)version); 544 return 0; 545 } 546 547 return 1; 548 } 549 550 /* 551 * Validate the ASPA: check that the customerASID is contained. 552 * Returns 1 if valid, 0 otherwise. 553 */ 554 int 555 valid_aspa(const char *fn, struct cert *cert, struct aspa *aspa) 556 { 557 558 if (as_check_covered(aspa->custasid, aspa->custasid, 559 cert->as, cert->asz) > 0) 560 return 1; 561 562 warnx("%s: ASPA: uncovered Customer ASID: %u", fn, aspa->custasid); 563 564 return 0; 565 } 566 567 /* 568 * Validate Geofeed prefixes: check that the prefixes are contained. 569 * Returns 1 if valid, 0 otherwise. 570 */ 571 int 572 valid_geofeed(const char *fn, struct cert *cert, struct geofeed *g) 573 { 574 size_t i; 575 char buf[64]; 576 577 for (i = 0; i < g->geoipsz; i++) { 578 if (ip_addr_check_covered(g->geoips[i].ip->afi, 579 g->geoips[i].ip->min, g->geoips[i].ip->max, cert->ips, 580 cert->ipsz) > 0) 581 continue; 582 583 ip_addr_print(&g->geoips[i].ip->ip, g->geoips[i].ip->afi, buf, 584 sizeof(buf)); 585 warnx("%s: Geofeed: uncovered IP: %s", fn, buf); 586 return 0; 587 } 588 589 return 1; 590 } 591 592 /* 593 * Validate whether a given string is a valid UUID. 594 * Returns 1 if valid, 0 otherwise. 595 */ 596 int 597 valid_uuid(const char *s) 598 { 599 int n = 0; 600 601 while (1) { 602 switch (n) { 603 case 8: 604 case 13: 605 case 18: 606 case 23: 607 if (s[n] != '-') 608 return 0; 609 break; 610 /* Check UUID is version 4 */ 611 case 14: 612 if (s[n] != '4') 613 return 0; 614 break; 615 /* Check UUID variant is 1 */ 616 case 19: 617 if (s[n] != '8' && s[n] != '9' && s[n] != 'a' && 618 s[n] != 'A' && s[n] != 'b' && s[n] != 'B') 619 return 0; 620 break; 621 case 36: 622 return s[n] == '\0'; 623 default: 624 if (!isxdigit((unsigned char)s[n])) 625 return 0; 626 break; 627 } 628 n++; 629 } 630 } 631 632 static int 633 valid_ca_pkey_rsa(const char *fn, EVP_PKEY *pkey) 634 { 635 RSA *rsa; 636 const BIGNUM *rsa_e; 637 int key_bits; 638 639 if ((key_bits = EVP_PKEY_bits(pkey)) != 2048) { 640 warnx("%s: RFC 7935: expected 2048-bit modulus, got %d bits", 641 fn, key_bits); 642 return 0; 643 } 644 645 if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { 646 warnx("%s: failed to extract RSA public key", fn); 647 return 0; 648 } 649 650 if ((rsa_e = RSA_get0_e(rsa)) == NULL) { 651 warnx("%s: failed to get RSA exponent", fn); 652 return 0; 653 } 654 655 if (!BN_is_word(rsa_e, 65537)) { 656 warnx("%s: incorrect exponent (e) in RSA public key", fn); 657 return 0; 658 } 659 660 return 1; 661 } 662 663 static int 664 valid_ca_pkey_ec(const char *fn, EVP_PKEY *pkey) 665 { 666 EC_KEY *ec; 667 const EC_GROUP *group; 668 int nid; 669 const char *cname; 670 671 if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { 672 warnx("%s: failed to extract ECDSA public key", fn); 673 return 0; 674 } 675 676 if ((group = EC_KEY_get0_group(ec)) == NULL) { 677 warnx("%s: EC_KEY_get0_group failed", fn); 678 return 0; 679 } 680 681 nid = EC_GROUP_get_curve_name(group); 682 if (nid != NID_X9_62_prime256v1) { 683 if ((cname = EC_curve_nid2nist(nid)) == NULL) 684 cname = nid2str(nid); 685 warnx("%s: Expected P-256, got %s", fn, cname); 686 return 0; 687 } 688 689 if (!EC_KEY_check_key(ec)) { 690 warnx("%s: EC_KEY_check_key failed", fn); 691 return 0; 692 } 693 694 return 1; 695 } 696 697 int 698 valid_ca_pkey(const char *fn, EVP_PKEY *pkey) 699 { 700 if (pkey == NULL) { 701 warnx("%s: failure, pkey is NULL", fn); 702 return 0; 703 } 704 705 if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) 706 return valid_ca_pkey_rsa(fn, pkey); 707 708 if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) 709 return valid_ca_pkey_ec(fn, pkey); 710 711 warnx("%s: unsupported public key algorithm", fn); 712 return 0; 713 } 714