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