1 /* $OpenBSD: validate.c,v 1.31 2022/04/21 09:53:07 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 <sys/socket.h> 19 20 #include <arpa/inet.h> 21 #include <assert.h> 22 #include <ctype.h> 23 #include <err.h> 24 #include <fcntl.h> 25 #include <inttypes.h> 26 #include <stdarg.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "extern.h" 32 33 extern ASN1_OBJECT *certpol_oid; 34 35 /* 36 * Walk up the chain of certificates trying to match our AS number to 37 * one of the allocations in that chain. 38 * Returns 1 if covered or 0 if not. 39 */ 40 static int 41 valid_as(struct auth *a, uint32_t min, uint32_t max) 42 { 43 int c; 44 45 if (a == NULL) 46 return 0; 47 48 /* Does this certificate cover our AS number? */ 49 if (a->cert->asz) { 50 c = as_check_covered(min, max, a->cert->as, a->cert->asz); 51 if (c > 0) 52 return 1; 53 else if (c < 0) 54 return 0; 55 } 56 57 /* If it doesn't, walk up the chain. */ 58 return valid_as(a->parent, min, max); 59 } 60 61 /* 62 * Walk up the chain of certificates (really just the last one, but in 63 * the case of inheritance, the ones before) making sure that our IP 64 * prefix is covered in the first non-inheriting specification. 65 * Returns 1 if covered or 0 if not. 66 */ 67 static int 68 valid_ip(struct auth *a, enum afi afi, 69 const unsigned char *min, const unsigned char *max) 70 { 71 int c; 72 73 if (a == NULL) 74 return 0; 75 76 /* Does this certificate cover our IP prefix? */ 77 c = ip_addr_check_covered(afi, min, max, a->cert->ips, a->cert->ipsz); 78 if (c > 0) 79 return 1; 80 else if (c < 0) 81 return 0; 82 83 /* If it doesn't, walk up the chain. */ 84 return valid_ip(a->parent, afi, min, max); 85 } 86 87 /* 88 * Make sure that the SKI doesn't already exist and return the parent by 89 * its AKI. 90 * Returns the parent auth or NULL on failure. 91 */ 92 struct auth * 93 valid_ski_aki(const char *fn, struct auth_tree *auths, 94 const char *ski, const char *aki) 95 { 96 struct auth *a; 97 98 if (auth_find(auths, ski) != NULL) { 99 warnx("%s: RFC 6487: duplicate SKI", fn); 100 return NULL; 101 } 102 103 a = auth_find(auths, aki); 104 if (a == NULL) 105 warnx("%s: RFC 6487: unknown AKI", fn); 106 107 return a; 108 } 109 110 /* 111 * Authenticate a trust anchor by making sure its resources are not 112 * inheriting and that the SKI is unique. 113 * Returns 1 if valid, 0 otherwise. 114 */ 115 int 116 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert) 117 { 118 size_t i; 119 120 /* AS and IP resources must not inherit. */ 121 if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) { 122 warnx("%s: RFC 6487 (trust anchor): " 123 "inheriting AS resources", fn); 124 return 0; 125 } 126 for (i = 0; i < cert->ipsz; i++) 127 if (cert->ips[i].type == CERT_IP_INHERIT) { 128 warnx("%s: RFC 6487 (trust anchor): " 129 "inheriting IP resources", fn); 130 return 0; 131 } 132 133 /* SKI must not be a dupe. */ 134 if (auth_find(auths, cert->ski) != NULL) { 135 warnx("%s: RFC 6487: duplicate SKI", fn); 136 return 0; 137 } 138 139 return 1; 140 } 141 142 /* 143 * Validate a non-TA certificate: make sure its IP and AS resources are 144 * fully covered by those in the authority key (which must exist). 145 * Returns 1 if valid, 0 otherwise. 146 */ 147 int 148 valid_cert(const char *fn, struct auth *a, const struct cert *cert) 149 { 150 size_t i; 151 uint32_t min, max; 152 char buf1[64], buf2[64]; 153 154 for (i = 0; i < cert->asz; i++) { 155 if (cert->as[i].type == CERT_AS_INHERIT) { 156 if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) 157 return 0; /* BGPsec doesn't permit inheriting */ 158 continue; 159 } 160 min = cert->as[i].type == CERT_AS_ID ? 161 cert->as[i].id : cert->as[i].range.min; 162 max = cert->as[i].type == CERT_AS_ID ? 163 cert->as[i].id : cert->as[i].range.max; 164 if (valid_as(a, min, max)) 165 continue; 166 warnx("%s: RFC 6487: uncovered AS: " 167 "%u--%u", fn, min, max); 168 return 0; 169 } 170 171 for (i = 0; i < cert->ipsz; i++) { 172 if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, 173 cert->ips[i].max)) 174 continue; 175 switch (cert->ips[i].type) { 176 case CERT_IP_RANGE: 177 ip_addr_print(&cert->ips[i].range.min, 178 cert->ips[i].afi, buf1, sizeof(buf1)); 179 ip_addr_print(&cert->ips[i].range.max, 180 cert->ips[i].afi, buf2, sizeof(buf2)); 181 warnx("%s: RFC 6487: uncovered IP: " 182 "%s--%s", fn, buf1, buf2); 183 break; 184 case CERT_IP_ADDR: 185 ip_addr_print(&cert->ips[i].ip, 186 cert->ips[i].afi, buf1, sizeof(buf1)); 187 warnx("%s: RFC 6487: uncovered IP: " 188 "%s", fn, buf1); 189 break; 190 case CERT_IP_INHERIT: 191 warnx("%s: RFC 6487: uncovered IP: " 192 "(inherit)", fn); 193 break; 194 } 195 return 0; 196 } 197 198 return 1; 199 } 200 201 /* 202 * Validate our ROA: check that the prefixes (ipAddrBlocks) are contained. 203 * Returns 1 if valid, 0 otherwise. 204 */ 205 int 206 valid_roa(const char *fn, struct auth *a, struct roa *roa) 207 { 208 size_t i; 209 char buf[64]; 210 211 for (i = 0; i < roa->ipsz; i++) { 212 if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min, 213 roa->ips[i].max)) 214 continue; 215 ip_addr_print(&roa->ips[i].addr, 216 roa->ips[i].afi, buf, sizeof(buf)); 217 warnx("%s: RFC 6482: uncovered IP: " 218 "%s", fn, buf); 219 return 0; 220 } 221 222 return 1; 223 } 224 225 /* 226 * Validate a file by verifying the SHA256 hash of that file. 227 * The file to check is passed as a file descriptor. 228 * Returns 1 if hash matched, 0 otherwise. Closes fd when done. 229 */ 230 int 231 valid_filehash(int fd, const char *hash, size_t hlen) 232 { 233 SHA256_CTX ctx; 234 char filehash[SHA256_DIGEST_LENGTH]; 235 char buffer[8192]; 236 ssize_t nr; 237 238 if (hlen != sizeof(filehash)) 239 errx(1, "bad hash size"); 240 241 if (fd == -1) 242 return 0; 243 244 SHA256_Init(&ctx); 245 while ((nr = read(fd, buffer, sizeof(buffer))) > 0) 246 SHA256_Update(&ctx, buffer, nr); 247 close(fd); 248 SHA256_Final(filehash, &ctx); 249 250 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 251 return 0; 252 return 1; 253 } 254 255 /* 256 * Same as above but with a buffer instead of a fd. 257 */ 258 int 259 valid_hash(unsigned char *buf, size_t len, const char *hash, size_t hlen) 260 { 261 char filehash[SHA256_DIGEST_LENGTH]; 262 263 if (hlen != sizeof(filehash)) 264 errx(1, "bad hash size"); 265 266 if (buf == NULL || len == 0) 267 return 0; 268 269 if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL)) 270 errx(1, "EVP_Digest failed"); 271 272 if (memcmp(hash, filehash, sizeof(filehash)) != 0) 273 return 0; 274 return 1; 275 } 276 277 /* 278 * Validate a URI to make sure it is pure ASCII and does not point backwards 279 * or doing some other silly tricks. To enforce the protocol pass either 280 * https:// or rsync:// as proto, if NULL is passed no protocol is enforced. 281 * Returns 1 if valid, 0 otherwise. 282 */ 283 int 284 valid_uri(const char *uri, size_t usz, const char *proto) 285 { 286 size_t s; 287 288 if (usz > MAX_URI_LENGTH) 289 return 0; 290 291 for (s = 0; s < usz; s++) 292 if (!isalnum((unsigned char)uri[s]) && 293 !ispunct((unsigned char)uri[s])) 294 return 0; 295 296 if (proto != NULL) { 297 s = strlen(proto); 298 if (strncasecmp(uri, proto, s) != 0) 299 return 0; 300 } 301 302 /* do not allow files or directories to start with a '.' */ 303 if (strstr(uri, "/.") != NULL) 304 return 0; 305 306 return 1; 307 } 308 309 /* 310 * Validate that a URI has the same host as the URI passed in proto. 311 * Returns 1 if valid, 0 otherwise. 312 */ 313 int 314 valid_origin(const char *uri, const char *proto) 315 { 316 const char *to; 317 318 /* extract end of host from proto URI */ 319 to = strstr(proto, "://"); 320 if (to == NULL) 321 return 0; 322 to += strlen("://"); 323 if ((to = strchr(to, '/')) == NULL) 324 return 0; 325 326 /* compare hosts including the / for the start of the path section */ 327 if (strncasecmp(uri, proto, to - proto + 1) != 0) 328 return 0; 329 330 return 1; 331 } 332 333 /* 334 * Callback for X509_verify_cert() to handle critical extensions in old 335 * LibreSSL libraries or OpenSSL libs without RFC3779 support. 336 */ 337 static int 338 verify_cb(int ok, X509_STORE_CTX *store_ctx) 339 { 340 X509 *cert; 341 const STACK_OF(X509_EXTENSION) *exts; 342 X509_EXTENSION *ext; 343 ASN1_OBJECT *obj; 344 char *file; 345 int depth, error, i, nid; 346 347 error = X509_STORE_CTX_get_error(store_ctx); 348 depth = X509_STORE_CTX_get_error_depth(store_ctx); 349 350 if (error != X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) 351 return ok; 352 353 if ((file = X509_STORE_CTX_get_app_data(store_ctx)) == NULL) 354 cryptoerrx("X509_STORE_CTX_get_app_data"); 355 356 if ((cert = X509_STORE_CTX_get_current_cert(store_ctx)) == NULL) { 357 warnx("%s: got no current cert", file); 358 return 0; 359 } 360 if ((exts = X509_get0_extensions(cert)) == NULL) { 361 warnx("%s: got no cert extensions", file); 362 return 0; 363 } 364 365 for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { 366 ext = sk_X509_EXTENSION_value(exts, i); 367 368 /* skip over non-critical and known extensions */ 369 if (!X509_EXTENSION_get_critical(ext)) 370 continue; 371 if (X509_supported_extension(ext)) 372 continue; 373 374 if ((obj = X509_EXTENSION_get_object(ext)) == NULL) { 375 warnx("%s: got no extension object", file); 376 return 0; 377 } 378 379 nid = OBJ_obj2nid(obj); 380 switch (nid) { 381 case NID_sbgp_ipAddrBlock: 382 case NID_sbgp_autonomousSysNum: 383 continue; 384 default: 385 warnx("%s: depth %d: unknown extension: nid %d", 386 file, depth, nid); 387 return 0; 388 } 389 } 390 391 return 1; 392 } 393 394 /* 395 * Walk the certificate tree to the root and build a certificate 396 * chain from cert->x509. All certs in the tree are validated and 397 * can be loaded as trusted stack into the validator. 398 */ 399 static void 400 build_chain(const struct auth *a, STACK_OF(X509) **chain) 401 { 402 *chain = NULL; 403 404 if (a == NULL) 405 return; 406 407 if ((*chain = sk_X509_new_null()) == NULL) 408 err(1, "sk_X509_new_null"); 409 for (; a != NULL; a = a->parent) { 410 assert(a->cert->x509 != NULL); 411 if (!sk_X509_push(*chain, a->cert->x509)) 412 errx(1, "sk_X509_push"); 413 } 414 } 415 416 /* 417 * Add the CRL based on the certs SKI value. 418 * No need to insert any other CRL since those were already checked. 419 */ 420 static void 421 build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls) 422 { 423 *crls = NULL; 424 425 if (crl == NULL) 426 return; 427 if ((*crls = sk_X509_CRL_new_null()) == NULL) 428 errx(1, "sk_X509_CRL_new_null"); 429 if (!sk_X509_CRL_push(*crls, crl->x509_crl)) 430 err(1, "sk_X509_CRL_push"); 431 } 432 433 /* 434 * Validate the X509 certificate. If crl is NULL don't check CRL. 435 * Returns 1 for valid certificates, returns 0 if there is a verify error 436 */ 437 int 438 valid_x509(char *file, X509_STORE_CTX *store_ctx, X509 *x509, struct auth *a, 439 struct crl *crl, int nowarn) 440 { 441 X509_VERIFY_PARAM *params; 442 ASN1_OBJECT *cp_oid; 443 STACK_OF(X509) *chain; 444 STACK_OF(X509_CRL) *crls = NULL; 445 unsigned long flags; 446 int c; 447 448 build_chain(a, &chain); 449 build_crls(crl, &crls); 450 451 assert(store_ctx != NULL); 452 assert(x509 != NULL); 453 if (!X509_STORE_CTX_init(store_ctx, NULL, x509, NULL)) 454 cryptoerrx("X509_STORE_CTX_init"); 455 456 if ((params = X509_STORE_CTX_get0_param(store_ctx)) == NULL) 457 cryptoerrx("X509_STORE_CTX_get0_param"); 458 if ((cp_oid = OBJ_dup(certpol_oid)) == NULL) 459 cryptoerrx("OBJ_dup"); 460 if (!X509_VERIFY_PARAM_add0_policy(params, cp_oid)) 461 cryptoerrx("X509_VERIFY_PARAM_add0_policy"); 462 463 X509_STORE_CTX_set_verify_cb(store_ctx, verify_cb); 464 if (!X509_STORE_CTX_set_app_data(store_ctx, file)) 465 cryptoerrx("X509_STORE_CTX_set_app_data"); 466 flags = X509_V_FLAG_CRL_CHECK; 467 flags |= X509_V_FLAG_EXPLICIT_POLICY; 468 flags |= X509_V_FLAG_INHIBIT_MAP; 469 X509_STORE_CTX_set_flags(store_ctx, flags); 470 X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH); 471 X509_STORE_CTX_set0_trusted_stack(store_ctx, chain); 472 X509_STORE_CTX_set0_crls(store_ctx, crls); 473 474 if (X509_verify_cert(store_ctx) <= 0) { 475 c = X509_STORE_CTX_get_error(store_ctx); 476 if (!nowarn || verbose > 1) 477 warnx("%s: %s", file, X509_verify_cert_error_string(c)); 478 X509_STORE_CTX_cleanup(store_ctx); 479 sk_X509_free(chain); 480 sk_X509_CRL_free(crls); 481 return 0; 482 } 483 484 X509_STORE_CTX_cleanup(store_ctx); 485 sk_X509_free(chain); 486 sk_X509_CRL_free(crls); 487 return 1; 488 } 489