1 /* $OpenBSD: x509_constraints.c,v 1.12 2020/11/25 21:17:52 tb Exp $ */ 2 /* 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 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 <ctype.h> 19 #include <errno.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <time.h> 23 #include <unistd.h> 24 25 #include <sys/socket.h> 26 #include <arpa/inet.h> 27 28 #include <openssl/safestack.h> 29 #include <openssl/x509.h> 30 #include <openssl/x509v3.h> 31 32 #include "x509_internal.h" 33 34 /* RFC 2821 section 4.5.3.1 */ 35 #define LOCAL_PART_MAX_LEN 64 36 #define DOMAIN_PART_MAX_LEN 255 37 38 struct x509_constraints_name * 39 x509_constraints_name_new() 40 { 41 return (calloc(1, sizeof(struct x509_constraints_name))); 42 } 43 44 void 45 x509_constraints_name_clear(struct x509_constraints_name *name) 46 { 47 free(name->name); 48 free(name->local); 49 free(name->der); 50 memset(name, 0, sizeof(*name)); 51 } 52 53 void 54 x509_constraints_name_free(struct x509_constraints_name *name) 55 { 56 if (name == NULL) 57 return; 58 x509_constraints_name_clear(name); 59 free(name); 60 } 61 62 struct x509_constraints_name * 63 x509_constraints_name_dup(struct x509_constraints_name *name) 64 { 65 struct x509_constraints_name *new; 66 67 if ((new = x509_constraints_name_new()) == NULL) 68 goto err; 69 new->type = name->type; 70 new->af = name->af; 71 new->der_len = name->der_len; 72 if (name->der_len > 0) { 73 if ((new->der = malloc(name->der_len)) == NULL) 74 goto err; 75 memcpy(new->der, name->der, name->der_len); 76 } 77 if (name->name != NULL && (new->name = strdup(name->name)) == NULL) 78 goto err; 79 if (name->local != NULL && (new->local = strdup(name->local)) == NULL) 80 goto err; 81 memcpy(new->address, name->address, sizeof(name->address)); 82 return new; 83 err: 84 x509_constraints_name_free(new); 85 return NULL; 86 } 87 88 struct x509_constraints_names * 89 x509_constraints_names_new() 90 { 91 return (calloc(1, sizeof(struct x509_constraints_names))); 92 } 93 94 void 95 x509_constraints_names_clear(struct x509_constraints_names *names) 96 { 97 size_t i; 98 99 for (i = 0; i < names->names_count; i++) 100 x509_constraints_name_free(names->names[i]); 101 free(names->names); 102 memset(names, 0, sizeof(*names)); 103 } 104 105 void 106 x509_constraints_names_free(struct x509_constraints_names *names) 107 { 108 if (names == NULL) 109 return; 110 111 x509_constraints_names_clear(names); 112 free(names); 113 } 114 115 int 116 x509_constraints_names_add(struct x509_constraints_names *names, 117 struct x509_constraints_name *name) 118 { 119 size_t i = names->names_count; 120 121 if (names->names_count == names->names_len) { 122 struct x509_constraints_name **tmp; 123 if ((tmp = recallocarray(names->names, names->names_len, 124 names->names_len + 32, sizeof(*tmp))) == NULL) 125 return 0; 126 names->names_len += 32; 127 names->names = tmp; 128 } 129 names->names[i] = name; 130 names->names_count++; 131 return 1; 132 } 133 134 struct x509_constraints_names * 135 x509_constraints_names_dup(struct x509_constraints_names *names) 136 { 137 struct x509_constraints_names *new = NULL; 138 struct x509_constraints_name *name = NULL; 139 size_t i; 140 141 if (names == NULL) 142 return NULL; 143 144 if ((new = x509_constraints_names_new()) == NULL) 145 goto err; 146 for (i = 0; i < names->names_count; i++) { 147 if ((name = x509_constraints_name_dup(names->names[i])) == NULL) 148 goto err; 149 if (!x509_constraints_names_add(new, name)) 150 goto err; 151 } 152 return new; 153 err: 154 x509_constraints_names_free(new); 155 x509_constraints_name_free(name); 156 return NULL; 157 } 158 159 160 /* 161 * Validate that the name contains only a hostname consisting of RFC 162 * 5890 compliant A-labels (see RFC 6066 section 3). This is more 163 * permissive to allow for a leading '*' for a SAN DNSname wildcard, 164 * or a leading '.' for a subdomain based constraint, as well as 165 * allowing for '_' which is commonly accepted by nonconformant 166 * DNS implementaitons. 167 */ 168 static int 169 x509_constraints_valid_domain_internal(uint8_t *name, size_t len) 170 { 171 uint8_t prev, c = 0; 172 int component = 0; 173 int first; 174 size_t i; 175 176 if (len > DOMAIN_PART_MAX_LEN) 177 return 0; 178 179 for (i = 0; i < len; i++) { 180 prev = c; 181 c = name[i]; 182 183 first = (i == 0); 184 185 /* Everything has to be ASCII, with no NUL byte */ 186 if (!isascii(c) || c == '\0') 187 return 0; 188 /* It must be alphanumeric, a '-', '.', '_' or '*' */ 189 if (!isalnum(c) && c != '-' && c != '.' && c != '_' && c != '*') 190 return 0; 191 192 /* '*' can only be the first thing. */ 193 if (c == '*' && !first) 194 return 0; 195 196 /* '-' must not start a component or be at the end. */ 197 if (c == '-' && (component == 0 || i == len - 1)) 198 return 0; 199 200 /* 201 * '.' must not be at the end. It may be first overall 202 * but must not otherwise start a component. 203 */ 204 if (c == '.' && ((component == 0 && !first) || i == len - 1)) 205 return 0; 206 207 if (c == '.') { 208 /* Components can not end with a dash. */ 209 if (prev == '-') 210 return 0; 211 /* Start new component */ 212 component = 0; 213 continue; 214 } 215 /* Components must be 63 chars or less. */ 216 if (++component > 63) 217 return 0; 218 } 219 return 1; 220 } 221 222 int 223 x509_constraints_valid_domain(uint8_t *name, size_t len) 224 { 225 if (len == 0) 226 return 0; 227 if (name[0] == '*') /* wildcard not allowed in a domain name */ 228 return 0; 229 /* 230 * A domain may not be less than two characters, so you can't 231 * have a require subdomain name with less than that. 232 */ 233 if (len < 3 && name[0] == '.') 234 return 0; 235 return x509_constraints_valid_domain_internal(name, len); 236 } 237 238 int 239 x509_constraints_valid_host(uint8_t *name, size_t len) 240 { 241 struct sockaddr_in sin4; 242 struct sockaddr_in6 sin6; 243 244 if (len == 0) 245 return 0; 246 if (name[0] == '*') /* wildcard not allowed in a host name */ 247 return 0; 248 if (name[0] == '.') /* leading . not allowed in a host name*/ 249 return 0; 250 if (inet_pton(AF_INET, name, &sin4) == 1) 251 return 0; 252 if (inet_pton(AF_INET6, name, &sin6) == 1) 253 return 0; 254 return x509_constraints_valid_domain_internal(name, len); 255 } 256 257 int 258 x509_constraints_valid_sandns(uint8_t *name, size_t len) 259 { 260 if (len == 0) 261 return 0; 262 263 if (name[0] == '.') /* leading . not allowed in a SAN DNS name */ 264 return 0; 265 /* 266 * A domain may not be less than two characters, so you 267 * can't wildcard a single domain of less than that 268 */ 269 if (len < 4 && name[0] == '*') 270 return 0; 271 /* 272 * A wildcard may only be followed by a '.' 273 */ 274 if (len >= 4 && name[0] == '*' && name[1] != '.') 275 return 0; 276 277 return x509_constraints_valid_domain_internal(name, len); 278 } 279 280 static inline int 281 local_part_ok(char c) 282 { 283 return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || 284 ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' || 285 c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' || 286 c == '-' || c == '/' || c == '=' || c == '?' || c == '^' || 287 c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || 288 c == '~' || c == '.'); 289 } 290 291 /* 292 * Parse "candidate" as an RFC 2821 mailbox. 293 * Returns 0 if candidate is not a valid mailbox or if an error occurs. 294 * Returns 1 if candidate is a mailbox and adds newly allocated 295 * local and domain parts of the mailbox to "name->local" and name->name" 296 */ 297 int 298 x509_constraints_parse_mailbox(uint8_t *candidate, size_t len, 299 struct x509_constraints_name *name) 300 { 301 char working[DOMAIN_PART_MAX_LEN + 1] = { 0 }; 302 char *candidate_local = NULL; 303 char *candidate_domain = NULL; 304 size_t i, wi = 0; 305 int accept = 0; 306 int quoted = 0; 307 308 if (candidate == NULL) 309 return 0; 310 311 /* It can't be bigger than the local part, domain part and the '@' */ 312 if (len > LOCAL_PART_MAX_LEN + DOMAIN_PART_MAX_LEN + 1) 313 return 0; 314 315 for (i = 0; i < len; i++) { 316 char c = candidate[i]; 317 /* non ascii, cr, lf, or nul is never allowed */ 318 if (!isascii(c) || c == '\r' || c == '\n' || c == '\0') 319 goto bad; 320 if (i == 0) { 321 /* local part is quoted part */ 322 if (c == '"') 323 quoted = 1; 324 /* can not start with a . */ 325 if (c == '.') 326 goto bad; 327 } 328 if (wi > DOMAIN_PART_MAX_LEN) 329 goto bad; 330 if (accept) { 331 working[wi++] = c; 332 accept = 0; 333 continue; 334 } 335 if (candidate_local != NULL) { 336 /* We are looking for the domain part */ 337 if (wi > DOMAIN_PART_MAX_LEN) 338 goto bad; 339 working[wi++] = c; 340 if (i == len - 1) { 341 if (wi == 0) 342 goto bad; 343 if (candidate_domain != NULL) 344 goto bad; 345 candidate_domain = strdup(working); 346 if (candidate_domain == NULL) 347 goto bad; 348 } 349 continue; 350 } 351 /* We are looking for the local part */ 352 if (wi > LOCAL_PART_MAX_LEN) 353 break; 354 355 if (quoted) { 356 if (c == '\\') { 357 accept = 1; 358 continue; 359 } 360 if (c == '"' && i != 0) { 361 /* end the quoted part. @ must be next */ 362 if (i + 1 == len || candidate[i + 1] != '@') 363 goto bad; 364 quoted = 0; 365 } 366 /* 367 * XXX Go strangely permits sp but forbids ht 368 * mimic that for now 369 */ 370 if (c == 9) 371 goto bad; 372 working[wi++] = c; 373 continue; /* all's good inside our quoted string */ 374 } 375 if (c == '@') { 376 if (wi == 0) 377 goto bad;; 378 if (candidate_local != NULL) 379 goto bad; 380 candidate_local = strdup(working); 381 if (candidate_local == NULL) 382 goto bad; 383 memset(working, 0, sizeof(working)); 384 wi = 0; 385 continue; 386 } 387 if (c == '\\') { 388 /* 389 * RFC 3936 hints these can happen outside of 390 * quotend string. don't include the \ but 391 * next character must be ok. 392 */ 393 if (i + 1 == len) 394 goto bad; 395 if (!local_part_ok(candidate[i + 1])) 396 goto bad; 397 accept = 1; 398 } 399 if (!local_part_ok(c)) 400 goto bad; 401 working[wi++] = c; 402 } 403 if (candidate_local == NULL || candidate_domain == NULL) 404 goto bad; 405 if (!x509_constraints_valid_host(candidate_domain, 406 strlen(candidate_domain))) 407 goto bad; 408 409 name->local = candidate_local; 410 name->name = candidate_domain; 411 name->type = GEN_EMAIL; 412 return 1; 413 bad: 414 free(candidate_local); 415 free(candidate_domain); 416 return 0; 417 } 418 419 int 420 x509_constraints_valid_domain_constraint(uint8_t *constraint, size_t len) 421 { 422 if (len == 0) 423 return 1; /* empty constraints match */ 424 425 if (constraint[0] == '*') /* wildcard not allowed in a constraint */ 426 return 0; 427 428 /* 429 * A domain may not be less than two characters, so you 430 * can't match a single domain of less than that 431 */ 432 if (len < 3 && constraint[0] == '.') 433 return 0; 434 return x509_constraints_valid_domain_internal(constraint, len); 435 } 436 437 /* 438 * Extract the host part of a URI, returns the host part as a c string 439 * the caller must free, or or NULL if it could not be found or is 440 * invalid. 441 * 442 * RFC 3986: 443 * the authority part of a uri starts with // and is terminated with 444 * the next '/', '?', '#' or end of the URI. 445 * 446 * The authority itself contains [userinfo '@'] host [: port] 447 * 448 * so the host starts at the start or after the '@', and ends 449 * with end of URI, '/', '?', "#', or ':'. 450 */ 451 int 452 x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart) 453 { 454 size_t i, hostlen = 0; 455 uint8_t *authority = NULL; 456 char *host = NULL; 457 458 /* 459 * Find first '//'. there must be at least a '//' and 460 * something else. 461 */ 462 if (len < 3) 463 return 0; 464 for (i = 0; i < len - 1; i++) { 465 if (!isascii(uri[i])) 466 return 0; 467 if (uri[i] == '/' && uri[i + 1] == '/') { 468 authority = uri + i + 2; 469 break; 470 } 471 } 472 if (authority == NULL) 473 return 0; 474 for (i = authority - uri; i < len; i++) { 475 if (!isascii(uri[i])) 476 return 0; 477 /* it has a userinfo part */ 478 if (uri[i] == '@') { 479 hostlen = 0; 480 /* it can only have one */ 481 if (host != NULL) 482 break; 483 /* start after the userinfo part */ 484 host = uri + i + 1; 485 continue; 486 } 487 /* did we find the end? */ 488 if (uri[i] == ':' || uri[i] == '/' || uri[i] == '?' || 489 uri[i] == '#') 490 break; 491 hostlen++; 492 } 493 if (hostlen == 0) 494 return 0; 495 if (host == NULL) 496 host = authority; 497 if (!x509_constraints_valid_host(host, hostlen)) 498 return 0; 499 *hostpart = strndup(host, hostlen); 500 return 1; 501 } 502 503 int 504 x509_constraints_sandns(char *sandns, size_t dlen, char *constraint, size_t len) 505 { 506 char *suffix; 507 508 if (len == 0) 509 return 1; /* an empty constraint matches everything */ 510 511 /* match the end of the domain */ 512 if (dlen < len) 513 return 0; 514 suffix = sandns + (dlen - len); 515 return (strncasecmp(suffix, constraint, len) == 0); 516 } 517 518 /* 519 * Validate a pre-validated domain of length dlen against a pre-validated 520 * constraint of length len. 521 * 522 * returns 1 if the domain and constraint match. 523 * returns 0 otherwise. 524 * 525 * an empty constraint matches everyting. 526 * constraint will be matched against the domain as a suffix if it 527 * starts with a '.'. 528 * domain will be matched against the constraint as a suffix if it 529 * starts with a '.'. 530 */ 531 int 532 x509_constraints_domain(char *domain, size_t dlen, char *constraint, size_t len) 533 { 534 if (len == 0) 535 return 1; /* an empty constraint matches everything */ 536 537 if (constraint[0] == '.') { 538 /* match the end of the domain */ 539 char *suffix; 540 if (dlen < len) 541 return 0; 542 suffix = domain + (dlen - len); 543 return (strncasecmp(suffix, constraint, len) == 0); 544 } 545 if (domain[0] == '.') { 546 /* match the end of the constraint */ 547 char *suffix; 548 if (len < dlen) 549 return 0; 550 suffix = constraint + (len - dlen); 551 return (strncasecmp(suffix, domain, dlen) == 0); 552 } 553 /* otherwise we must exactly match the constraint */ 554 if (dlen != len) 555 return 0; 556 return (strncasecmp(domain, constraint, len) == 0); 557 } 558 559 int 560 x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, size_t len, 561 int *error) 562 { 563 int ret = 0; 564 char *hostpart = NULL; 565 566 if (!x509_constraints_uri_host(uri, ulen, &hostpart)) { 567 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 568 goto err; 569 } 570 if (hostpart == NULL) { 571 *error = X509_V_ERR_OUT_OF_MEM; 572 goto err; 573 } 574 if (!x509_constraints_valid_domain_constraint(constraint, len)) { 575 *error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX; 576 goto err; 577 } 578 ret = x509_constraints_domain(hostpart, strlen(hostpart), constraint, 579 len); 580 err: 581 free(hostpart); 582 return ret; 583 } 584 585 /* 586 * Verify a validated address of size alen with a validated contraint 587 * of size constraint_len. returns 1 if matching, 0 if not. 588 * Addresses are assumed to be pre-validated for a length of 4 and 8 589 * respectively for ipv4 addreses and constraints, and a length of 590 * 16 and 32 respectively for ipv6 address constraints by the caller. 591 */ 592 int 593 x509_constraints_ipaddr(uint8_t *address, size_t alen, uint8_t *constraint, 594 size_t len) 595 { 596 uint8_t *mask; 597 size_t i; 598 599 if (alen * 2 != len) 600 return 0; 601 602 mask = constraint + alen; 603 for (i = 0; i < alen; i++) { 604 if ((address[i] & mask[i]) != (constraint[i] & mask[i])) 605 return 0; 606 } 607 return 1; 608 } 609 610 /* 611 * Verify a canonicalized der encoded constraint dirname 612 * a canonicalized der encoded constraint. 613 */ 614 int 615 x509_constraints_dirname(uint8_t *dirname, size_t dlen, 616 uint8_t *constraint, size_t len) 617 { 618 if (len != dlen) 619 return 0; 620 return (memcmp(constraint, dirname, len) == 0); 621 } 622 623 /* 624 * De-obfuscate a GENERAL_NAME into useful bytes for a name or constraint. 625 */ 626 int 627 x509_constraints_general_to_bytes(GENERAL_NAME *name, uint8_t **bytes, 628 size_t *len) 629 { 630 *bytes = NULL; 631 *len = 0; 632 633 if (name->type == GEN_DNS) { 634 ASN1_IA5STRING *aname = name->d.dNSName; 635 *bytes = aname->data; 636 *len = strlen(aname->data); 637 return name->type; 638 } 639 if (name->type == GEN_EMAIL) { 640 ASN1_IA5STRING *aname = name->d.rfc822Name; 641 *bytes = aname->data; 642 *len = strlen(aname->data); 643 return name->type; 644 } 645 if (name->type == GEN_URI) { 646 ASN1_IA5STRING *aname = name->d.uniformResourceIdentifier; 647 *bytes = aname->data; 648 *len = strlen(aname->data); 649 return name->type; 650 } 651 if (name->type == GEN_DIRNAME) { 652 X509_NAME *dname = name->d.directoryName; 653 if (!dname->modified || i2d_X509_NAME(dname, NULL) >= 0) { 654 *bytes = dname->canon_enc; 655 *len = dname->canon_enclen; 656 return name->type; 657 } 658 } 659 if (name->type == GEN_IPADD) { 660 *bytes = name->d.ip->data; 661 *len = name->d.ip->length; 662 return name->type; 663 } 664 return 0; 665 } 666 667 668 /* 669 * Extract the relevant names for constraint checking from "cert", 670 * validate them, and add them to the list of cert names for "chain". 671 * returns 1 on success sets error and returns 0 on failure. 672 */ 673 int 674 x509_constraints_extract_names(struct x509_constraints_names *names, 675 X509 *cert, int is_leaf, int *error) 676 { 677 struct x509_constraints_name *vname = NULL; 678 X509_NAME *subject_name; 679 GENERAL_NAME *name; 680 ssize_t i = 0; 681 int name_type, include_cn = is_leaf, include_email = is_leaf; 682 683 /* first grab the altnames */ 684 while ((name = sk_GENERAL_NAME_value(cert->altname, i++)) != NULL) { 685 uint8_t *bytes = NULL; 686 size_t len = 0; 687 688 if ((vname = x509_constraints_name_new()) == NULL) { 689 *error = X509_V_ERR_OUT_OF_MEM; 690 goto err; 691 } 692 693 name_type = x509_constraints_general_to_bytes(name, &bytes, 694 &len); 695 switch(name_type) { 696 case GEN_DNS: 697 if (!x509_constraints_valid_sandns(bytes, len)) { 698 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 699 goto err; 700 } 701 if ((vname->name = strdup(bytes)) == NULL) { 702 *error = X509_V_ERR_OUT_OF_MEM; 703 goto err; 704 } 705 vname->type = GEN_DNS; 706 include_cn = 0; /* don't use cn from subject */ 707 break; 708 case GEN_EMAIL: 709 if (!x509_constraints_parse_mailbox(bytes, len, 710 vname)) { 711 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 712 goto err; 713 } 714 vname->type = GEN_EMAIL; 715 include_email = 0; /* don't use email from subject */ 716 break; 717 case GEN_URI: 718 if (!x509_constraints_uri_host(bytes, len, &vname->name)) { 719 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 720 goto err; 721 } 722 if (vname->name == NULL) { 723 *error = X509_V_ERR_OUT_OF_MEM; 724 goto err; 725 } 726 vname->type = GEN_URI; 727 break; 728 case GEN_DIRNAME: 729 if (bytes == NULL || ((vname->der = malloc(len)) == 730 NULL)) { 731 *error = X509_V_ERR_OUT_OF_MEM; 732 goto err; 733 } 734 if (len == 0) { 735 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 736 goto err; 737 } 738 memcpy(vname->der, bytes, len); 739 vname->der_len = len; 740 vname->type = GEN_DIRNAME; 741 break; 742 case GEN_IPADD: 743 if (len == 4) 744 vname->af = AF_INET; 745 if (len == 16) 746 vname->af = AF_INET6; 747 if (vname->af != AF_INET && vname->af != 748 AF_INET6) { 749 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 750 goto err; 751 } 752 memcpy(vname->address, bytes, len); 753 vname->type = GEN_IPADD; 754 break; 755 default: 756 /* Ignore this name */ 757 x509_constraints_name_free(vname); 758 vname = NULL; 759 continue; 760 } 761 if (!x509_constraints_names_add(names, vname)) { 762 *error = X509_V_ERR_OUT_OF_MEM; 763 goto err; 764 } 765 vname = NULL; 766 } 767 768 x509_constraints_name_free(vname); 769 vname = NULL; 770 771 subject_name = X509_get_subject_name(cert); 772 if (X509_NAME_entry_count(subject_name) > 0) { 773 X509_NAME_ENTRY *email; 774 X509_NAME_ENTRY *cn; 775 /* 776 * This cert has a non-empty subject, so we must add 777 * the subject as a dirname to be compared against 778 * any dirname constraints 779 */ 780 if ((subject_name->modified && 781 i2d_X509_NAME(subject_name, NULL) < 0) || 782 (vname = x509_constraints_name_new()) == NULL || 783 (vname->der = malloc(subject_name->canon_enclen)) == NULL) { 784 *error = X509_V_ERR_OUT_OF_MEM; 785 goto err; 786 } 787 788 memcpy(vname->der, subject_name->canon_enc, 789 subject_name->canon_enclen); 790 vname->der_len = subject_name->canon_enclen; 791 vname->type = GEN_DIRNAME; 792 if (!x509_constraints_names_add(names, vname)) { 793 *error = X509_V_ERR_OUT_OF_MEM; 794 goto err; 795 } 796 vname = NULL; 797 /* 798 * Get any email addresses from the subject line, and 799 * add them as mbox names to be compared against any 800 * email constraints 801 */ 802 while (include_email && 803 (i = X509_NAME_get_index_by_NID(subject_name, 804 NID_pkcs9_emailAddress, i)) >= 0) { 805 ASN1_STRING *aname; 806 if ((email = X509_NAME_get_entry(subject_name, i)) == NULL || 807 (aname = X509_NAME_ENTRY_get_data(email)) == NULL) { 808 *error = X509_V_ERR_OUT_OF_MEM; 809 goto err; 810 } 811 if ((vname = x509_constraints_name_new()) == NULL) { 812 *error = X509_V_ERR_OUT_OF_MEM; 813 goto err; 814 } 815 if (!x509_constraints_parse_mailbox(aname->data, 816 aname->length, vname)) { 817 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 818 goto err; 819 } 820 vname->type = GEN_EMAIL; 821 if (!x509_constraints_names_add(names, vname)) { 822 *error = X509_V_ERR_OUT_OF_MEM; 823 goto err; 824 } 825 vname = NULL; 826 } 827 /* 828 * Include the CN as a hostname to be checked againt 829 * name constraints if it looks like a hostname. 830 */ 831 while (include_cn && 832 (i = X509_NAME_get_index_by_NID(subject_name, 833 NID_commonName, i)) >= 0) { 834 ASN1_STRING *aname; 835 if ((cn = X509_NAME_get_entry(subject_name, i)) == NULL || 836 (aname = X509_NAME_ENTRY_get_data(cn)) == NULL) { 837 *error = X509_V_ERR_OUT_OF_MEM; 838 goto err; 839 } 840 if (!x509_constraints_valid_host(aname->data, 841 aname->length)) 842 continue; /* ignore it if not a hostname */ 843 if ((vname = x509_constraints_name_new()) == NULL) { 844 *error = X509_V_ERR_OUT_OF_MEM; 845 goto err; 846 } 847 if ((vname->name = strndup(aname->data, 848 aname->length)) == NULL) { 849 *error = X509_V_ERR_OUT_OF_MEM; 850 goto err; 851 } 852 vname->type = GEN_DNS; 853 if (!x509_constraints_names_add(names, vname)) { 854 *error = X509_V_ERR_OUT_OF_MEM; 855 goto err; 856 } 857 vname = NULL; 858 } 859 } 860 return 1; 861 err: 862 x509_constraints_name_free(vname); 863 return 0; 864 } 865 866 /* 867 * Validate a constraint in a general name, putting the relevant data 868 * into "name" if valid. returns 0, and sets error if the constraint is 869 * not valid. returns 1 if the constraint validated. name->type will be 870 * set to a valid type if there is constraint data in name, or unmodified 871 * if the GENERAL_NAME had a valid type but was ignored. 872 */ 873 int 874 x509_constraints_validate(GENERAL_NAME *constraint, 875 struct x509_constraints_name *name, int *error) 876 { 877 uint8_t *bytes = NULL; 878 size_t len = 0; 879 int name_type; 880 881 name_type = x509_constraints_general_to_bytes(constraint, &bytes, &len); 882 switch (name_type) { 883 case GEN_DIRNAME: 884 if (bytes == NULL || (name->der = malloc(len)) == NULL) { 885 *error = X509_V_ERR_OUT_OF_MEM; 886 return 0; 887 } 888 if (len == 0) 889 goto err; /* XXX The RFCs are delightfully vague */ 890 memcpy(name->der, bytes, len); 891 name->der_len = len; 892 name->type = GEN_DIRNAME; 893 break; 894 case GEN_DNS: 895 if (!x509_constraints_valid_domain_constraint(bytes, len)) 896 goto err; 897 if ((name->name = strdup(bytes)) == NULL) { 898 *error = X509_V_ERR_OUT_OF_MEM; 899 return 0; 900 } 901 name->type = GEN_DNS; 902 break; 903 case GEN_EMAIL: 904 if (memchr(bytes, '@', len) != NULL) { 905 if (!x509_constraints_parse_mailbox(bytes, len, name)) 906 goto err; 907 } else { 908 if (!x509_constraints_valid_domain_constraint(bytes, 909 len)) 910 goto err; 911 if ((name->name = strdup(bytes)) == NULL) { 912 *error = X509_V_ERR_OUT_OF_MEM; 913 return 0; 914 } 915 } 916 name->type = GEN_EMAIL; 917 break; 918 case GEN_IPADD: 919 /* Constraints are ip then mask */ 920 if (len == 8) 921 name->af = AF_INET; 922 else if (len == 32) 923 name->af = AF_INET6; 924 else 925 goto err; 926 memcpy(&name->address[0], bytes, len); 927 name->type = GEN_IPADD; 928 break; 929 case GEN_URI: 930 if (!x509_constraints_valid_domain_constraint(bytes, len)) 931 goto err; 932 name->name = strdup(bytes); 933 name->type = GEN_URI; 934 break; 935 default: 936 break; 937 } 938 return 1; 939 err: 940 *error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX; 941 return 0; 942 } 943 944 int 945 x509_constraints_extract_constraints(X509 *cert, 946 struct x509_constraints_names *permitted, 947 struct x509_constraints_names *excluded, 948 int *error) 949 { 950 struct x509_constraints_name *vname; 951 NAME_CONSTRAINTS *nc = cert->nc; 952 GENERAL_SUBTREE *subtree; 953 int i; 954 955 if (nc == NULL) 956 return 1; 957 958 for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) { 959 960 subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); 961 if (subtree->minimum || subtree->maximum) { 962 *error = X509_V_ERR_SUBTREE_MINMAX; 963 return 0; 964 } 965 if ((vname = x509_constraints_name_new()) == NULL) { 966 *error = X509_V_ERR_OUT_OF_MEM; 967 return 0; 968 } 969 if (x509_constraints_validate(subtree->base, vname, error) == 970 0) { 971 x509_constraints_name_free(vname); 972 return 0; 973 } 974 if (vname->type == 0) { 975 x509_constraints_name_free(vname); 976 continue; 977 } 978 if (!x509_constraints_names_add(permitted, vname)) { 979 x509_constraints_name_free(vname); 980 *error = X509_V_ERR_OUT_OF_MEM; 981 return 0; 982 } 983 } 984 985 for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) { 986 subtree = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); 987 if (subtree->minimum || subtree->maximum) { 988 *error = X509_V_ERR_SUBTREE_MINMAX; 989 return 0; 990 } 991 if ((vname = x509_constraints_name_new()) == NULL) { 992 *error = X509_V_ERR_OUT_OF_MEM; 993 return 0; 994 } 995 if (x509_constraints_validate(subtree->base, vname, error) == 996 0) { 997 x509_constraints_name_free(vname); 998 return 0; 999 } 1000 if (vname->type == 0) { 1001 x509_constraints_name_free(vname); 1002 continue; 1003 } 1004 if (!x509_constraints_names_add(excluded, vname)) { 1005 x509_constraints_name_free(vname); 1006 *error = X509_V_ERR_OUT_OF_MEM; 1007 return 0; 1008 } 1009 } 1010 1011 return 1; 1012 } 1013 1014 /* 1015 * Match a validated name in "name" against a validated constraint in 1016 * "constraint" return 1 if then name matches, 0 otherwise. 1017 */ 1018 int 1019 x509_constraints_match(struct x509_constraints_name *name, 1020 struct x509_constraints_name *constraint) 1021 { 1022 if (name->type != constraint->type) 1023 return 0; 1024 if (name->type == GEN_DNS) 1025 return x509_constraints_sandns(name->name, strlen(name->name), 1026 constraint->name, strlen(constraint->name)); 1027 if (name->type == GEN_URI) 1028 return x509_constraints_domain(name->name, strlen(name->name), 1029 constraint->name, strlen(constraint->name)); 1030 if (name->type == GEN_IPADD) { 1031 size_t nlen = name->af == AF_INET ? 4 : 16; 1032 size_t clen = name->af == AF_INET ? 8 : 32; 1033 if (name->af != AF_INET && name->af != AF_INET6) 1034 return 0; 1035 if (constraint->af != AF_INET && constraint->af != AF_INET6) 1036 return 0; 1037 if (name->af != constraint->af) 1038 return 0; 1039 return x509_constraints_ipaddr(name->address, nlen, 1040 constraint->address, clen); 1041 } 1042 if (name->type == GEN_EMAIL) { 1043 if (constraint->local) { 1044 /* mailbox local and domain parts must exactly match */ 1045 return (strcmp(name->local, constraint->local) == 0 && 1046 strcmp(name->name, constraint->name) == 0); 1047 } 1048 /* otherwise match the constraint to the domain part */ 1049 return x509_constraints_domain(name->name, strlen(name->name), 1050 constraint->name, strlen(constraint->name)); 1051 } 1052 if (name->type == GEN_DIRNAME) 1053 return x509_constraints_dirname(name->der, name->der_len, 1054 constraint->der, constraint->der_len); 1055 return 0; 1056 } 1057 1058 /* 1059 * Make sure every name in names does not match any excluded 1060 * constraints, and does match at least one permitted constraint if 1061 * any are present. Returns 1 if ok, 0, and sets error if not. 1062 */ 1063 int 1064 x509_constraints_check(struct x509_constraints_names *names, 1065 struct x509_constraints_names *permitted, 1066 struct x509_constraints_names *excluded, int *error) 1067 { 1068 size_t i, j; 1069 1070 for (i = 0; i < names->names_count; i++) { 1071 int permitted_seen = 0; 1072 int permitted_matched = 0; 1073 1074 for (j = 0; j < excluded->names_count; j++) { 1075 if (x509_constraints_match(names->names[i], 1076 excluded->names[j])) { 1077 *error = X509_V_ERR_EXCLUDED_VIOLATION; 1078 return 0; 1079 } 1080 } 1081 for (j = 0; j < permitted->names_count; j++) { 1082 if (permitted->names[j]->type == names->names[i]->type) 1083 permitted_seen++; 1084 if (x509_constraints_match(names->names[i], 1085 permitted->names[j])) { 1086 permitted_matched++; 1087 break; 1088 } 1089 } 1090 if (permitted_seen && !permitted_matched) { 1091 *error = X509_V_ERR_PERMITTED_VIOLATION; 1092 return 0; 1093 } 1094 } 1095 return 1; 1096 } 1097 1098 /* 1099 * Walk a validated chain of X509 certs, starting at the leaf, and 1100 * validate the name constraints in the chain. Intended for use with 1101 * the legacy X509 validtion code in x509_vfy.c 1102 * 1103 * returns 1 if the constraints are ok, 0 otherwise, setting error and 1104 * depth 1105 */ 1106 int 1107 x509_constraints_chain(STACK_OF(X509) *chain, int *error, int *depth) 1108 { 1109 int chain_length, verify_err = X509_V_ERR_UNSPECIFIED, i = 0; 1110 struct x509_constraints_names *names = NULL; 1111 struct x509_constraints_names *excluded = NULL; 1112 struct x509_constraints_names *permitted = NULL; 1113 size_t constraints_count = 0; 1114 X509 *cert; 1115 1116 if (chain == NULL || (chain_length = sk_X509_num(chain)) == 0) 1117 goto err; 1118 if (chain_length == 1) 1119 return 1; 1120 if ((names = x509_constraints_names_new()) == NULL) { 1121 verify_err = X509_V_ERR_OUT_OF_MEM; 1122 goto err; 1123 } 1124 1125 if ((cert = sk_X509_value(chain, 0)) == NULL) 1126 goto err; 1127 if (!x509_constraints_extract_names(names, cert, 1, &verify_err)) 1128 goto err; 1129 for (i = 1; i < chain_length; i++) { 1130 if ((cert = sk_X509_value(chain, i)) == NULL) 1131 goto err; 1132 if (cert->nc != NULL) { 1133 if ((permitted = 1134 x509_constraints_names_new()) == NULL) { 1135 verify_err = X509_V_ERR_OUT_OF_MEM; 1136 goto err; 1137 } 1138 if ((excluded = 1139 x509_constraints_names_new()) == NULL) { 1140 verify_err = X509_V_ERR_OUT_OF_MEM; 1141 goto err; 1142 } 1143 if (!x509_constraints_extract_constraints(cert, 1144 permitted, excluded, &verify_err)) 1145 goto err; 1146 constraints_count += permitted->names_count; 1147 constraints_count += excluded->names_count; 1148 if (constraints_count > 1149 X509_VERIFY_MAX_CHAIN_CONSTRAINTS) { 1150 verify_err = X509_V_ERR_OUT_OF_MEM; 1151 goto err; 1152 } 1153 if (!x509_constraints_check(names, permitted, excluded, 1154 &verify_err)) 1155 goto err; 1156 x509_constraints_names_free(excluded); 1157 excluded = NULL; 1158 x509_constraints_names_free(permitted); 1159 permitted = NULL; 1160 } 1161 if (!x509_constraints_extract_names(names, cert, 0, 1162 &verify_err)) 1163 goto err; 1164 if (names->names_count > X509_VERIFY_MAX_CHAIN_NAMES) { 1165 verify_err = X509_V_ERR_OUT_OF_MEM; 1166 goto err; 1167 } 1168 } 1169 1170 x509_constraints_names_free(names); 1171 return 1; 1172 1173 err: 1174 *error = verify_err; 1175 *depth = i; 1176 x509_constraints_names_free(excluded); 1177 x509_constraints_names_free(permitted); 1178 x509_constraints_names_free(names); 1179 return 0; 1180 } 1181