1 /* $OpenBSD: validate.c,v 1.52 2023/01/04 14:22:43 claudio 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 that the SKI doesn't already exist and return the parent by 84 * its AKI. 85 * Returns the parent auth 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) 90 { 91 struct auth *a; 92 93 if (auth_find(auths, ski) != NULL) { 94 warnx("%s: RFC 6487: duplicate SKI", fn); 95 return NULL; 96 } 97 98 a = auth_find(auths, aki); 99 if (a == NULL) 100 warnx("%s: RFC 6487: unknown AKI", fn); 101 102 return a; 103 } 104 105 /* 106 * Validate a trust anchor by making sure that the SKI is unique. 107 * Returns 1 if valid, 0 otherwise. 108 */ 109 int 110 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert) 111 { 112 /* SKI must not be a dupe. */ 113 if (auth_find(auths, cert->ski) != NULL) { 114 warnx("%s: RFC 6487: duplicate SKI", fn); 115 return 0; 116 } 117 118 return 1; 119 } 120 121 /* 122 * Validate a non-TA certificate: make sure its IP and AS resources are 123 * fully covered by those in the authority key (which must exist). 124 * Returns 1 if valid, 0 otherwise. 125 */ 126 int 127 valid_cert(const char *fn, struct auth *a, const struct cert *cert) 128 { 129 size_t i; 130 uint32_t min, max; 131 char buf1[64], buf2[64]; 132 133 for (i = 0; i < cert->asz; i++) { 134 if (cert->as[i].type == CERT_AS_INHERIT) 135 continue; 136 min = cert->as[i].type == CERT_AS_ID ? 137 cert->as[i].id : cert->as[i].range.min; 138 max = cert->as[i].type == CERT_AS_ID ? 139 cert->as[i].id : cert->as[i].range.max; 140 if (valid_as(a, min, max)) 141 continue; 142 warnx("%s: RFC 6487: uncovered AS: " 143 "%u--%u", fn, min, max); 144 return 0; 145 } 146 147 for (i = 0; i < cert->ipsz; i++) { 148 if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, 149 cert->ips[i].max)) 150 continue; 151 switch (cert->ips[i].type) { 152 case CERT_IP_RANGE: 153 ip_addr_print(&cert->ips[i].range.min, 154 cert->ips[i].afi, buf1, sizeof(buf1)); 155 ip_addr_print(&cert->ips[i].range.max, 156 cert->ips[i].afi, buf2, sizeof(buf2)); 157 warnx("%s: RFC 6487: uncovered IP: " 158 "%s--%s", fn, buf1, buf2); 159 break; 160 case CERT_IP_ADDR: 161 ip_addr_print(&cert->ips[i].ip, 162 cert->ips[i].afi, buf1, sizeof(buf1)); 163 warnx("%s: RFC 6487: uncovered IP: " 164 "%s", fn, buf1); 165 break; 166 case CERT_IP_INHERIT: 167 warnx("%s: RFC 6487: uncovered IP: " 168 "(inherit)", fn); 169 break; 170 } 171 return 0; 172 } 173 174 return 1; 175 } 176 177 /* 178 * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained. 179 * Returns 1 if valid, 0 otherwise. 180 */ 181 int 182 valid_roa(const char *fn, struct cert *cert, struct roa *roa) 183 { 184 size_t i; 185 char buf[64]; 186 187 for (i = 0; i < roa->ipsz; i++) { 188 if (ip_addr_check_covered(roa->ips[i].afi, roa->ips[i].min, 189 roa->ips[i].max, cert->ips, cert->ipsz) > 0) 190 continue; 191 192 ip_addr_print(&roa->ips[i].addr, roa->ips[i].afi, buf, 193 sizeof(buf)); 194 warnx("%s: RFC 6482: uncovered IP: %s", fn, buf); 195 return 0; 196 } 197 198 return 1; 199 } 200 201 /* 202 * Validate a file by verifying the SHA256 hash of that file. 203 * The file to check is passed as a file descriptor. 204 * Returns 1 if hash matched, 0 otherwise. Closes fd when done. 205 */ 206 int 207 valid_filehash(int fd, const char *hash, size_t hlen) 208 { 209 SHA256_CTX ctx; 210 char filehash[SHA256_DIGEST_LENGTH]; 211 char buffer[8192]; 212 ssize_t nr; 213 214 if (hlen != sizeof(filehash)) 215 errx(1, "bad hash size"); 216 217 if (fd == -1) 218 return 0; 219 220 SHA256_Init(&ctx); 221 while ((nr = read(fd, buffer, sizeof(buffer))) > 0) 222 SHA256_Update(&ctx, buffer, nr); 223 close(fd); 224 SHA256_Final(filehash, &ctx); 225 226 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 227 return 0; 228 return 1; 229 } 230 231 /* 232 * Same as above but with a buffer instead of a fd. 233 */ 234 int 235 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen) 236 { 237 char filehash[SHA256_DIGEST_LENGTH]; 238 239 if (hlen != sizeof(filehash)) 240 errx(1, "bad hash size"); 241 242 if (buf == NULL || len == 0) 243 return 0; 244 245 if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL)) 246 errx(1, "EVP_Digest failed"); 247 248 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 249 return 0; 250 return 1; 251 } 252 253 /* 254 * Validate that a filename only contains characters from the POSIX portable 255 * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278. 256 */ 257 int 258 valid_filename(const char *fn, size_t len) 259 { 260 const unsigned char *c; 261 size_t i; 262 263 for (c = fn, i = 0; i < len; i++, c++) 264 if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.') 265 return 0; 266 return 1; 267 } 268 269 /* 270 * Validate a URI to make sure it is pure ASCII and does not point backwards 271 * or doing some other silly tricks. To enforce the protocol pass either 272 * https:// or rsync:// as proto, if NULL is passed no protocol is enforced. 273 * Returns 1 if valid, 0 otherwise. 274 */ 275 int 276 valid_uri(const char *uri, size_t usz, const char *proto) 277 { 278 size_t s; 279 280 if (usz > MAX_URI_LENGTH) 281 return 0; 282 283 for (s = 0; s < usz; s++) 284 if (!isalnum((unsigned char)uri[s]) && 285 !ispunct((unsigned char)uri[s])) 286 return 0; 287 288 if (proto != NULL) { 289 s = strlen(proto); 290 if (s >= usz) 291 return 0; 292 if (strncasecmp(uri, proto, s) != 0) 293 return 0; 294 } 295 296 /* do not allow files or directories to start with a '.' */ 297 if (strstr(uri, "/.") != NULL) 298 return 0; 299 300 return 1; 301 } 302 303 /* 304 * Validate that a URI has the same host as the URI passed in proto. 305 * Returns 1 if valid, 0 otherwise. 306 */ 307 int 308 valid_origin(const char *uri, const char *proto) 309 { 310 const char *to; 311 312 /* extract end of host from proto URI */ 313 to = strstr(proto, "://"); 314 if (to == NULL) 315 return 0; 316 to += strlen("://"); 317 if ((to = strchr(to, '/')) == NULL) 318 return 0; 319 320 /* compare hosts including the / for the start of the path section */ 321 if (strncasecmp(uri, proto, to - proto + 1) != 0) 322 return 0; 323 324 return 1; 325 } 326 327 /* 328 * Walk the certificate tree to the root and build a certificate 329 * chain from cert->x509. All certs in the tree are validated and 330 * can be loaded as trusted stack into the validator. 331 */ 332 static void 333 build_chain(const struct auth *a, STACK_OF(X509) **chain) 334 { 335 *chain = NULL; 336 337 if (a == NULL) 338 return; 339 340 if ((*chain = sk_X509_new_null()) == NULL) 341 err(1, "sk_X509_new_null"); 342 for (; a != NULL; a = a->parent) { 343 assert(a->cert->x509 != NULL); 344 if (!sk_X509_push(*chain, a->cert->x509)) 345 errx(1, "sk_X509_push"); 346 } 347 } 348 349 /* 350 * Add the CRL based on the certs SKI value. 351 * No need to insert any other CRL since those were already checked. 352 */ 353 static void 354 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls) 355 { 356 *crls = NULL; 357 358 if (crl == NULL) 359 return; 360 if ((*crls = sk_X509_CRL_new_null()) == NULL) 361 errx(1, "sk_X509_CRL_new_null"); 362 if (!sk_X509_CRL_push(*crls, crl->x509_crl)) 363 err(1, "sk_X509_CRL_push"); 364 } 365 366 /* 367 * Validate the X509 certificate. Returns 1 for valid certificates, 368 * returns 0 if there is a verify error and sets *errstr to the error 369 * returned by X509_verify_cert_error_string(). 370 */ 371 int 372 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a, 373 struct crl *crl, const char **errstr) 374 { 375 X509_VERIFY_PARAM *params; 376 ASN1_OBJECT *cp_oid; 377 STACK_OF(X509) *chain; 378 STACK_OF(X509_CRL) *crls = NULL; 379 unsigned long flags; 380 int error; 381 382 *errstr = NULL; 383 build_chain(a, &chain); 384 build_crls(crl, &crls); 385 386 assert(store_ctx != NULL); 387 assert(x509 != NULL); 388 if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL)) 389 cryptoerrx("X509_STORE_CTX_init"); 390 391 if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL) 392 cryptoerrx("X509_STORE_CTX_get0_param"); 393 if ((cp_oid = OBJ_dup(certpol_oid)) == NULL) 394 cryptoerrx("OBJ_dup"); 395 if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid)) 396 cryptoerrx("X509_VERIFY_PARAM_add0_policy"); 397 398 flags = X509_V_FLAG_CRL_CHECK; 399 flags |= X509_V_FLAG_EXPLICIT_POLICY; 400 flags |= X509_V_FLAG_INHIBIT_MAP; 401 X509_STORE_CTX_set_flags(store_ctx, flags); 402 X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH); 403 X509_STORE_CTX_set0_trusted_stack(store_ctx, chain); 404 X509_STORE_CTX_set0_crls(store_ctx, crls); 405 406 if (X509_verify_cert(store_ctx) <= 0) { 407 error = X509_STORE_CTX_get_error(store_ctx); 408 *errstr = X509_verify_cert_error_string(error); 409 X509_STORE_CTX_cleanup(store_ctx); 410 sk_X509_free(chain); 411 sk_X509_CRL_free(crls); 412 return 0; 413 } 414 415 X509_STORE_CTX_cleanup(store_ctx); 416 sk_X509_free(chain); 417 sk_X509_CRL_free(crls); 418 return 1; 419 } 420 421 /* 422 * Validate our RSC: check that all items in the ResourceBlock are contained. 423 * Returns 1 if valid, 0 otherwise. 424 */ 425 int 426 valid_rsc(const char *fn, struct cert *cert, struct rsc *rsc) 427 { 428 size_t i; 429 uint32_t min, max; 430 char buf1[64], buf2[64]; 431 432 for (i = 0; i < rsc->asz; i++) { 433 min = rsc->as[i].type == CERT_AS_RANGE ? rsc->as[i].range.min 434 : rsc->as[i].id; 435 max = rsc->as[i].type == CERT_AS_RANGE ? rsc->as[i].range.max 436 : rsc->as[i].id; 437 438 if (as_check_covered(min, max, cert->as, cert->asz) > 0) 439 continue; 440 441 switch (rsc->as[i].type) { 442 case CERT_AS_ID: 443 warnx("%s: RSC resourceBlock: uncovered AS Identifier: " 444 "%u", fn, rsc->as[i].id); 445 break; 446 case CERT_AS_RANGE: 447 warnx("%s: RSC resourceBlock: uncovered AS Range: " 448 "%u--%u", fn, min, max); 449 break; 450 default: 451 break; 452 } 453 return 0; 454 } 455 456 for (i = 0; i < rsc->ipsz; i++) { 457 if (ip_addr_check_covered(rsc->ips[i].afi, rsc->ips[i].min, 458 rsc->ips[i].max, cert->ips, cert->ipsz) > 0) 459 continue; 460 461 switch (rsc->ips[i].type) { 462 case CERT_IP_RANGE: 463 ip_addr_print(&rsc->ips[i].range.min, 464 rsc->ips[i].afi, buf1, sizeof(buf1)); 465 ip_addr_print(&rsc->ips[i].range.max, 466 rsc->ips[i].afi, buf2, sizeof(buf2)); 467 warnx("%s: RSC ResourceBlock: uncovered IP Range: " 468 "%s--%s", fn, buf1, buf2); 469 break; 470 case CERT_IP_ADDR: 471 ip_addr_print(&rsc->ips[i].ip, 472 rsc->ips[i].afi, buf1, sizeof(buf1)); 473 warnx("%s: RSC ResourceBlock: uncovered IP: " 474 "%s", fn, buf1); 475 break; 476 default: 477 break; 478 } 479 return 0; 480 } 481 482 return 1; 483 } 484 485 int 486 valid_econtent_version(const char *fn, const ASN1_INTEGER *aint) 487 { 488 long version; 489 490 if (aint == NULL) 491 return 1; 492 493 if ((version = ASN1_INTEGER_get(aint)) < 0) { 494 warnx("%s: ASN1_INTEGER_get failed", fn); 495 return 0; 496 } 497 498 switch (version) { 499 case 0: 500 warnx("%s: incorrect encoding for version 0", fn); 501 return 0; 502 default: 503 warnx("%s: version %ld not supported (yet)", fn, version); 504 return 0; 505 } 506 } 507 508 /* 509 * Validate the ASPA: check that the customerASID is contained. 510 * Returns 1 if valid, 0 otherwise. 511 */ 512 int 513 valid_aspa(const char *fn, struct cert *cert, struct aspa *aspa) 514 { 515 516 if (as_check_covered(aspa->custasid, aspa->custasid, 517 cert->as, cert->asz) > 0) 518 return 1; 519 520 warnx("%s: ASPA: uncovered Customer ASID: %u", fn, aspa->custasid); 521 522 return 0; 523 } 524 525 /* 526 * Validate Geofeed prefixes: check that the prefixes are contained. 527 * Returns 1 if valid, 0 otherwise. 528 */ 529 int 530 valid_geofeed(const char *fn, struct cert *cert, struct geofeed *g) 531 { 532 size_t i; 533 char buf[64]; 534 535 for (i = 0; i < g->geoipsz; i++) { 536 if (ip_addr_check_covered(g->geoips[i].ip->afi, 537 g->geoips[i].ip->min, g->geoips[i].ip->max, cert->ips, 538 cert->ipsz) > 0) 539 continue; 540 541 ip_addr_print(&g->geoips[i].ip->ip, g->geoips[i].ip->afi, buf, 542 sizeof(buf)); 543 warnx("%s: Geofeed: uncovered IP: %s", fn, buf); 544 return 0; 545 } 546 547 return 1; 548 } 549 550 /* 551 * Validate whether a given string is a valid UUID. 552 * Returns 1 if valid, 0 otherwise. 553 */ 554 int 555 valid_uuid(const char *s) 556 { 557 int n = 0; 558 559 while (1) { 560 switch (n) { 561 case 8: 562 case 13: 563 case 18: 564 case 23: 565 if (s[n] != '-') 566 return 0; 567 break; 568 #ifdef NOTYET /* World is not yet ready to enfoce UUID version and variant */ 569 /* Check UUID is version 4 */ 570 case 14: 571 if (s[n] != '4') 572 return 0; 573 break; 574 /* Check UUID variant is 1 */ 575 case 19: 576 if (s[n] != '8' && s[n] != '9' && s[n] != 'a' && 577 s[n] != 'A' && s[n] != 'b' && s[n] != 'B') 578 return 0; 579 break; 580 #endif 581 case 36: 582 return s[n] == '\0'; 583 default: 584 if (!isxdigit((unsigned char)s[n])) 585 return 0; 586 break; 587 } 588 n++; 589 } 590 } 591 592