github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/x509/name_constraints_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package x509 6 7 import ( 8 "bytes" 9 "crypto/ecdsa" 10 "crypto/elliptic" 11 "crypto/rand" 12 "crypto/x509/pkix" 13 "encoding/asn1" 14 "encoding/hex" 15 "encoding/pem" 16 "fmt" 17 "math/big" 18 "net" 19 "net/url" 20 "os" 21 "os/exec" 22 "strconv" 23 "strings" 24 "sync" 25 "testing" 26 "time" 27 ) 28 29 const ( 30 // testNameConstraintsAgainstOpenSSL can be set to true to run tests 31 // against the system OpenSSL. This is disabled by default because Go 32 // cannot depend on having OpenSSL installed at testing time. 33 testNameConstraintsAgainstOpenSSL = false 34 35 // debugOpenSSLFailure can be set to true, when 36 // testNameConstraintsAgainstOpenSSL is also true, to cause 37 // intermediate files to be preserved for debugging. 38 debugOpenSSLFailure = false 39 ) 40 41 type nameConstraintsTest struct { 42 roots []constraintsSpec 43 intermediates [][]constraintsSpec 44 leaf leafSpec 45 requestedEKUs []ExtKeyUsage 46 expectedError string 47 noOpenSSL bool 48 // ignoreCN bool 49 } 50 51 type constraintsSpec struct { 52 ok []string 53 bad []string 54 ekus []string 55 } 56 57 type leafSpec struct { 58 sans []string 59 ekus []string 60 cn string 61 } 62 63 //goland:noinspection HttpUrlsUsage 64 var nameConstraintsTests = []nameConstraintsTest{ 65 // #0: dummy test for the certificate generation process itself. 66 { 67 roots: make([]constraintsSpec, 1), 68 leaf: leafSpec{ 69 sans: []string{"dns:example.com"}, 70 }, 71 }, 72 73 // #1: dummy test for the certificate generation process itself: single 74 // level of intermediate. 75 { 76 roots: make([]constraintsSpec, 1), 77 intermediates: [][]constraintsSpec{ 78 { 79 {}, 80 }, 81 }, 82 leaf: leafSpec{ 83 sans: []string{"dns:example.com"}, 84 }, 85 }, 86 87 // #2: dummy test for the certificate generation process itself: two 88 // levels of intermediates. 89 { 90 roots: make([]constraintsSpec, 1), 91 intermediates: [][]constraintsSpec{ 92 { 93 {}, 94 }, 95 { 96 {}, 97 }, 98 }, 99 leaf: leafSpec{ 100 sans: []string{"dns:example.com"}, 101 }, 102 }, 103 104 // #3: matching DNS constraint in root 105 { 106 roots: []constraintsSpec{ 107 { 108 ok: []string{"dns:example.com"}, 109 }, 110 }, 111 intermediates: [][]constraintsSpec{ 112 { 113 {}, 114 }, 115 }, 116 leaf: leafSpec{ 117 sans: []string{"dns:example.com"}, 118 }, 119 }, 120 121 // #4: matching DNS constraint in intermediate. 122 { 123 roots: make([]constraintsSpec, 1), 124 intermediates: [][]constraintsSpec{ 125 { 126 { 127 ok: []string{"dns:example.com"}, 128 }, 129 }, 130 }, 131 leaf: leafSpec{ 132 sans: []string{"dns:example.com"}, 133 }, 134 }, 135 136 // #5: .example.com only matches subdomains. 137 { 138 roots: []constraintsSpec{ 139 { 140 ok: []string{"dns:.example.com"}, 141 }, 142 }, 143 intermediates: [][]constraintsSpec{ 144 { 145 {}, 146 }, 147 }, 148 leaf: leafSpec{ 149 sans: []string{"dns:example.com"}, 150 }, 151 expectedError: "\"example.com\" is not permitted", 152 }, 153 154 // #6: .example.com matches subdomains. 155 { 156 roots: make([]constraintsSpec, 1), 157 intermediates: [][]constraintsSpec{ 158 { 159 { 160 ok: []string{"dns:.example.com"}, 161 }, 162 }, 163 }, 164 leaf: leafSpec{ 165 sans: []string{"dns:foo.example.com"}, 166 }, 167 }, 168 169 // #7: .example.com matches multiple levels of subdomains 170 { 171 roots: []constraintsSpec{ 172 { 173 ok: []string{"dns:.example.com"}, 174 }, 175 }, 176 intermediates: [][]constraintsSpec{ 177 { 178 {}, 179 }, 180 }, 181 leaf: leafSpec{ 182 sans: []string{"dns:foo.bar.example.com"}, 183 }, 184 }, 185 186 // #8: specifying a permitted list of names does not exclude other name 187 // types 188 { 189 roots: []constraintsSpec{ 190 { 191 ok: []string{"dns:.example.com"}, 192 }, 193 }, 194 intermediates: [][]constraintsSpec{ 195 { 196 {}, 197 }, 198 }, 199 leaf: leafSpec{ 200 sans: []string{"ip:10.1.1.1"}, 201 }, 202 }, 203 204 // #9: specifying a permitted list of names does not exclude other name 205 // types 206 { 207 roots: []constraintsSpec{ 208 { 209 ok: []string{"ip:10.0.0.0/8"}, 210 }, 211 }, 212 intermediates: [][]constraintsSpec{ 213 { 214 {}, 215 }, 216 }, 217 leaf: leafSpec{ 218 sans: []string{"dns:example.com"}, 219 }, 220 }, 221 222 // #10: intermediates can try to permit other names, which isn't 223 // forbidden if the leaf doesn't mention them. I.e. name constraints 224 // apply to names, not constraints themselves. 225 { 226 roots: []constraintsSpec{ 227 { 228 ok: []string{"dns:example.com"}, 229 }, 230 }, 231 intermediates: [][]constraintsSpec{ 232 { 233 { 234 ok: []string{"dns:example.com", "dns:foo.com"}, 235 }, 236 }, 237 }, 238 leaf: leafSpec{ 239 sans: []string{"dns:example.com"}, 240 }, 241 }, 242 243 // #11: intermediates cannot add permitted names that the root doesn't 244 // grant them. 245 { 246 roots: []constraintsSpec{ 247 { 248 ok: []string{"dns:example.com"}, 249 }, 250 }, 251 intermediates: [][]constraintsSpec{ 252 { 253 { 254 ok: []string{"dns:example.com", "dns:foo.com"}, 255 }, 256 }, 257 }, 258 leaf: leafSpec{ 259 sans: []string{"dns:foo.com"}, 260 }, 261 expectedError: "\"foo.com\" is not permitted", 262 }, 263 264 // #12: intermediates can further limit their scope if they wish. 265 { 266 roots: []constraintsSpec{ 267 { 268 ok: []string{"dns:.example.com"}, 269 }, 270 }, 271 intermediates: [][]constraintsSpec{ 272 { 273 { 274 ok: []string{"dns:.bar.example.com"}, 275 }, 276 }, 277 }, 278 leaf: leafSpec{ 279 sans: []string{"dns:foo.bar.example.com"}, 280 }, 281 }, 282 283 // #13: intermediates can further limit their scope and that limitation 284 // is effective 285 { 286 roots: []constraintsSpec{ 287 { 288 ok: []string{"dns:.example.com"}, 289 }, 290 }, 291 intermediates: [][]constraintsSpec{ 292 { 293 { 294 ok: []string{"dns:.bar.example.com"}, 295 }, 296 }, 297 }, 298 leaf: leafSpec{ 299 sans: []string{"dns:foo.notbar.example.com"}, 300 }, 301 expectedError: "\"foo.notbar.example.com\" is not permitted", 302 }, 303 304 // #14: roots can exclude subtrees and that doesn't affect other names. 305 { 306 roots: []constraintsSpec{ 307 { 308 bad: []string{"dns:.example.com"}, 309 }, 310 }, 311 intermediates: [][]constraintsSpec{ 312 { 313 {}, 314 }, 315 }, 316 leaf: leafSpec{ 317 sans: []string{"dns:foo.com"}, 318 }, 319 }, 320 321 // #15: roots exclusions are effective. 322 { 323 roots: []constraintsSpec{ 324 { 325 bad: []string{"dns:.example.com"}, 326 }, 327 }, 328 intermediates: [][]constraintsSpec{ 329 { 330 {}, 331 }, 332 }, 333 leaf: leafSpec{ 334 sans: []string{"dns:foo.example.com"}, 335 }, 336 expectedError: "\"foo.example.com\" is excluded", 337 }, 338 339 // #16: intermediates can also exclude names and that doesn't affect 340 // other names. 341 { 342 roots: make([]constraintsSpec, 1), 343 intermediates: [][]constraintsSpec{ 344 { 345 { 346 bad: []string{"dns:.example.com"}, 347 }, 348 }, 349 }, 350 leaf: leafSpec{ 351 sans: []string{"dns:foo.com"}, 352 }, 353 }, 354 355 // #17: intermediate exclusions are effective. 356 { 357 roots: make([]constraintsSpec, 1), 358 intermediates: [][]constraintsSpec{ 359 { 360 { 361 bad: []string{"dns:.example.com"}, 362 }, 363 }, 364 }, 365 leaf: leafSpec{ 366 sans: []string{"dns:foo.example.com"}, 367 }, 368 expectedError: "\"foo.example.com\" is excluded", 369 }, 370 371 // #18: having an exclusion doesn't prohibit other types of names. 372 { 373 roots: []constraintsSpec{ 374 { 375 bad: []string{"dns:.example.com"}, 376 }, 377 }, 378 intermediates: [][]constraintsSpec{ 379 { 380 {}, 381 }, 382 }, 383 leaf: leafSpec{ 384 sans: []string{"dns:foo.com", "ip:10.1.1.1"}, 385 }, 386 }, 387 388 // #19: IP-based exclusions are permitted and don't affect unrelated IP 389 // addresses. 390 { 391 roots: []constraintsSpec{ 392 { 393 bad: []string{"ip:10.0.0.0/8"}, 394 }, 395 }, 396 intermediates: [][]constraintsSpec{ 397 { 398 {}, 399 }, 400 }, 401 leaf: leafSpec{ 402 sans: []string{"ip:192.168.1.1"}, 403 }, 404 }, 405 406 // #20: IP-based exclusions are effective 407 { 408 roots: []constraintsSpec{ 409 { 410 bad: []string{"ip:10.0.0.0/8"}, 411 }, 412 }, 413 intermediates: [][]constraintsSpec{ 414 { 415 {}, 416 }, 417 }, 418 leaf: leafSpec{ 419 sans: []string{"ip:10.0.0.1"}, 420 }, 421 expectedError: "\"10.0.0.1\" is excluded", 422 }, 423 424 // #21: intermediates can further constrain IP ranges. 425 { 426 roots: []constraintsSpec{ 427 { 428 bad: []string{"ip:0.0.0.0/1"}, 429 }, 430 }, 431 intermediates: [][]constraintsSpec{ 432 { 433 { 434 bad: []string{"ip:11.0.0.0/8"}, 435 }, 436 }, 437 }, 438 leaf: leafSpec{ 439 sans: []string{"ip:11.0.0.1"}, 440 }, 441 expectedError: "\"11.0.0.1\" is excluded", 442 }, 443 444 // #22: when multiple intermediates are present, chain building can 445 // avoid intermediates with incompatible constraints. 446 { 447 roots: make([]constraintsSpec, 1), 448 intermediates: [][]constraintsSpec{ 449 { 450 { 451 ok: []string{"dns:.foo.com"}, 452 }, 453 { 454 ok: []string{"dns:.example.com"}, 455 }, 456 }, 457 }, 458 leaf: leafSpec{ 459 sans: []string{"dns:foo.example.com"}, 460 }, 461 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. 462 }, 463 464 // #23: (same as the previous test, but in the other order in ensure 465 // that we don't pass it by luck.) 466 { 467 roots: make([]constraintsSpec, 1), 468 intermediates: [][]constraintsSpec{ 469 { 470 { 471 ok: []string{"dns:.example.com"}, 472 }, 473 { 474 ok: []string{"dns:.foo.com"}, 475 }, 476 }, 477 }, 478 leaf: leafSpec{ 479 sans: []string{"dns:foo.example.com"}, 480 }, 481 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. 482 }, 483 484 // #24: when multiple roots are valid, chain building can avoid roots 485 // with incompatible constraints. 486 { 487 roots: []constraintsSpec{ 488 {}, 489 { 490 ok: []string{"dns:foo.com"}, 491 }, 492 }, 493 intermediates: [][]constraintsSpec{ 494 { 495 {}, 496 }, 497 }, 498 leaf: leafSpec{ 499 sans: []string{"dns:example.com"}, 500 }, 501 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. 502 }, 503 504 // #25: (same as the previous test, but in the other order in ensure 505 // that we don't pass it by luck.) 506 { 507 roots: []constraintsSpec{ 508 { 509 ok: []string{"dns:foo.com"}, 510 }, 511 {}, 512 }, 513 intermediates: [][]constraintsSpec{ 514 { 515 {}, 516 }, 517 }, 518 leaf: leafSpec{ 519 sans: []string{"dns:example.com"}, 520 }, 521 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. 522 }, 523 524 // #26: chain building can find a valid path even with multiple levels 525 // of alternative intermediates and alternative roots. 526 { 527 roots: []constraintsSpec{ 528 { 529 ok: []string{"dns:foo.com"}, 530 }, 531 { 532 ok: []string{"dns:example.com"}, 533 }, 534 {}, 535 }, 536 intermediates: [][]constraintsSpec{ 537 { 538 {}, 539 { 540 ok: []string{"dns:foo.com"}, 541 }, 542 }, 543 { 544 {}, 545 { 546 ok: []string{"dns:foo.com"}, 547 }, 548 }, 549 }, 550 leaf: leafSpec{ 551 sans: []string{"dns:bar.com"}, 552 }, 553 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints. 554 }, 555 556 // #27: chain building doesn't get stuck when there is no valid path. 557 { 558 roots: []constraintsSpec{ 559 { 560 ok: []string{"dns:foo.com"}, 561 }, 562 { 563 ok: []string{"dns:example.com"}, 564 }, 565 }, 566 intermediates: [][]constraintsSpec{ 567 { 568 {}, 569 { 570 ok: []string{"dns:foo.com"}, 571 }, 572 }, 573 { 574 { 575 ok: []string{"dns:bar.com"}, 576 }, 577 { 578 ok: []string{"dns:foo.com"}, 579 }, 580 }, 581 }, 582 leaf: leafSpec{ 583 sans: []string{"dns:bar.com"}, 584 }, 585 expectedError: "\"bar.com\" is not permitted", 586 }, 587 588 // #28: unknown name types don't cause a problem without constraints. 589 { 590 roots: make([]constraintsSpec, 1), 591 intermediates: [][]constraintsSpec{ 592 { 593 {}, 594 }, 595 }, 596 leaf: leafSpec{ 597 sans: []string{"unknown:"}, 598 }, 599 }, 600 601 // #29: unknown name types are allowed even in constrained chains. 602 { 603 roots: []constraintsSpec{ 604 { 605 ok: []string{"dns:foo.com", "dns:.foo.com"}, 606 }, 607 }, 608 intermediates: [][]constraintsSpec{ 609 { 610 {}, 611 }, 612 }, 613 leaf: leafSpec{ 614 sans: []string{"unknown:"}, 615 }, 616 }, 617 618 // #30: without SANs, a certificate with a CN is still accepted in a 619 // constrained chain, since we ignore the CN in VerifyHostname. 620 { 621 roots: []constraintsSpec{ 622 { 623 ok: []string{"dns:foo.com", "dns:.foo.com"}, 624 }, 625 }, 626 intermediates: [][]constraintsSpec{ 627 { 628 {}, 629 }, 630 }, 631 leaf: leafSpec{ 632 sans: []string{}, 633 cn: "foo.com", 634 }, 635 }, 636 637 // #31: IPv6 addresses work in constraints: roots can permit them as 638 // expected. 639 { 640 roots: []constraintsSpec{ 641 { 642 ok: []string{"ip:2000:abcd::/32"}, 643 }, 644 }, 645 intermediates: [][]constraintsSpec{ 646 { 647 {}, 648 }, 649 }, 650 leaf: leafSpec{ 651 sans: []string{"ip:2000:abcd:1234::"}, 652 }, 653 }, 654 655 // #32: IPv6 addresses work in constraints: root restrictions are 656 // effective. 657 { 658 roots: []constraintsSpec{ 659 { 660 ok: []string{"ip:2000:abcd::/32"}, 661 }, 662 }, 663 intermediates: [][]constraintsSpec{ 664 { 665 {}, 666 }, 667 }, 668 leaf: leafSpec{ 669 sans: []string{"ip:2000:1234:abcd::"}, 670 }, 671 expectedError: "\"2000:1234:abcd::\" is not permitted", 672 }, 673 674 // #33: An IPv6 permitted subtree doesn't affect DNS names. 675 { 676 roots: []constraintsSpec{ 677 { 678 ok: []string{"ip:2000:abcd::/32"}, 679 }, 680 }, 681 intermediates: [][]constraintsSpec{ 682 { 683 {}, 684 }, 685 }, 686 leaf: leafSpec{ 687 sans: []string{"ip:2000:abcd::", "dns:foo.com"}, 688 }, 689 }, 690 691 // #34: IPv6 exclusions don't affect unrelated addresses. 692 { 693 roots: []constraintsSpec{ 694 { 695 bad: []string{"ip:2000:abcd::/32"}, 696 }, 697 }, 698 intermediates: [][]constraintsSpec{ 699 { 700 {}, 701 }, 702 }, 703 leaf: leafSpec{ 704 sans: []string{"ip:2000:1234::"}, 705 }, 706 }, 707 708 // #35: IPv6 exclusions are effective. 709 { 710 roots: []constraintsSpec{ 711 { 712 bad: []string{"ip:2000:abcd::/32"}, 713 }, 714 }, 715 intermediates: [][]constraintsSpec{ 716 { 717 {}, 718 }, 719 }, 720 leaf: leafSpec{ 721 sans: []string{"ip:2000:abcd::"}, 722 }, 723 expectedError: "\"2000:abcd::\" is excluded", 724 }, 725 726 // #36: IPv6 constraints do not permit IPv4 addresses. 727 { 728 roots: []constraintsSpec{ 729 { 730 ok: []string{"ip:2000:abcd::/32"}, 731 }, 732 }, 733 intermediates: [][]constraintsSpec{ 734 { 735 {}, 736 }, 737 }, 738 leaf: leafSpec{ 739 sans: []string{"ip:10.0.0.1"}, 740 }, 741 expectedError: "\"10.0.0.1\" is not permitted", 742 }, 743 744 // #37: IPv4 constraints do not permit IPv6 addresses. 745 { 746 roots: []constraintsSpec{ 747 { 748 ok: []string{"ip:10.0.0.0/8"}, 749 }, 750 }, 751 intermediates: [][]constraintsSpec{ 752 { 753 {}, 754 }, 755 }, 756 leaf: leafSpec{ 757 sans: []string{"ip:2000:abcd::"}, 758 }, 759 expectedError: "\"2000:abcd::\" is not permitted", 760 }, 761 762 // #38: an exclusion of an unknown type doesn't affect other names. 763 { 764 roots: []constraintsSpec{ 765 { 766 bad: []string{"unknown:"}, 767 }, 768 }, 769 intermediates: [][]constraintsSpec{ 770 { 771 {}, 772 }, 773 }, 774 leaf: leafSpec{ 775 sans: []string{"dns:example.com"}, 776 }, 777 }, 778 779 // #39: a permitted subtree of an unknown type doesn't affect other 780 // name types. 781 { 782 roots: []constraintsSpec{ 783 { 784 ok: []string{"unknown:"}, 785 }, 786 }, 787 intermediates: [][]constraintsSpec{ 788 { 789 {}, 790 }, 791 }, 792 leaf: leafSpec{ 793 sans: []string{"dns:example.com"}, 794 }, 795 }, 796 797 // #40: exact email constraints work 798 { 799 roots: []constraintsSpec{ 800 { 801 ok: []string{"email:foo@example.com"}, 802 }, 803 }, 804 intermediates: [][]constraintsSpec{ 805 { 806 {}, 807 }, 808 }, 809 leaf: leafSpec{ 810 sans: []string{"email:foo@example.com"}, 811 }, 812 }, 813 814 // #41: exact email constraints are effective 815 { 816 roots: []constraintsSpec{ 817 { 818 ok: []string{"email:foo@example.com"}, 819 }, 820 }, 821 intermediates: [][]constraintsSpec{ 822 { 823 {}, 824 }, 825 }, 826 leaf: leafSpec{ 827 sans: []string{"email:bar@example.com"}, 828 }, 829 expectedError: "\"bar@example.com\" is not permitted", 830 }, 831 832 // #42: email canonicalisation works. 833 { 834 roots: []constraintsSpec{ 835 { 836 ok: []string{"email:foo@example.com"}, 837 }, 838 }, 839 intermediates: [][]constraintsSpec{ 840 { 841 {}, 842 }, 843 }, 844 leaf: leafSpec{ 845 sans: []string{"email:\"\\f\\o\\o\"@example.com"}, 846 }, 847 noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching 848 }, 849 850 // #43: limiting email addresses to a host works. 851 { 852 roots: []constraintsSpec{ 853 { 854 ok: []string{"email:example.com"}, 855 }, 856 }, 857 intermediates: [][]constraintsSpec{ 858 { 859 {}, 860 }, 861 }, 862 leaf: leafSpec{ 863 sans: []string{"email:foo@example.com"}, 864 }, 865 }, 866 867 // #44: a leading dot matches hosts one level deep 868 { 869 roots: []constraintsSpec{ 870 { 871 ok: []string{"email:.example.com"}, 872 }, 873 }, 874 intermediates: [][]constraintsSpec{ 875 { 876 {}, 877 }, 878 }, 879 leaf: leafSpec{ 880 sans: []string{"email:foo@sub.example.com"}, 881 }, 882 }, 883 884 // #45: a leading dot does not match the host itself 885 { 886 roots: []constraintsSpec{ 887 { 888 ok: []string{"email:.example.com"}, 889 }, 890 }, 891 intermediates: [][]constraintsSpec{ 892 { 893 {}, 894 }, 895 }, 896 leaf: leafSpec{ 897 sans: []string{"email:foo@example.com"}, 898 }, 899 expectedError: "\"foo@example.com\" is not permitted", 900 }, 901 902 // #46: a leading dot also matches two (or more) levels deep. 903 { 904 roots: []constraintsSpec{ 905 { 906 ok: []string{"email:.example.com"}, 907 }, 908 }, 909 intermediates: [][]constraintsSpec{ 910 { 911 {}, 912 }, 913 }, 914 leaf: leafSpec{ 915 sans: []string{"email:foo@sub.sub.example.com"}, 916 }, 917 }, 918 919 // #47: the local part of an email is case-sensitive 920 { 921 roots: []constraintsSpec{ 922 { 923 ok: []string{"email:foo@example.com"}, 924 }, 925 }, 926 intermediates: [][]constraintsSpec{ 927 { 928 {}, 929 }, 930 }, 931 leaf: leafSpec{ 932 sans: []string{"email:Foo@example.com"}, 933 }, 934 expectedError: "\"Foo@example.com\" is not permitted", 935 }, 936 937 // #48: the domain part of an email is not case-sensitive 938 { 939 roots: []constraintsSpec{ 940 { 941 ok: []string{"email:foo@EXAMPLE.com"}, 942 }, 943 }, 944 intermediates: [][]constraintsSpec{ 945 { 946 {}, 947 }, 948 }, 949 leaf: leafSpec{ 950 sans: []string{"email:foo@example.com"}, 951 }, 952 }, 953 954 // #49: the domain part of a DNS constraint is also not case-sensitive. 955 { 956 roots: []constraintsSpec{ 957 { 958 ok: []string{"dns:EXAMPLE.com"}, 959 }, 960 }, 961 intermediates: [][]constraintsSpec{ 962 { 963 {}, 964 }, 965 }, 966 leaf: leafSpec{ 967 sans: []string{"dns:example.com"}, 968 }, 969 }, 970 971 // #50: URI constraints only cover the host part of the URI 972 { 973 roots: []constraintsSpec{ 974 { 975 ok: []string{"uri:example.com"}, 976 }, 977 }, 978 intermediates: [][]constraintsSpec{ 979 { 980 {}, 981 }, 982 }, 983 leaf: leafSpec{ 984 sans: []string{ 985 "uri:http://example.com/bar", 986 "uri:http://example.com:8080/", 987 "uri:https://example.com/wibble#bar", 988 }, 989 }, 990 }, 991 992 // #51: URIs with IPs are rejected 993 { 994 roots: []constraintsSpec{ 995 { 996 ok: []string{"uri:example.com"}, 997 }, 998 }, 999 intermediates: [][]constraintsSpec{ 1000 { 1001 {}, 1002 }, 1003 }, 1004 leaf: leafSpec{ 1005 sans: []string{"uri:http://1.2.3.4/"}, 1006 }, 1007 expectedError: "URI with IP", 1008 }, 1009 1010 // #52: URIs with IPs and ports are rejected 1011 { 1012 roots: []constraintsSpec{ 1013 { 1014 ok: []string{"uri:example.com"}, 1015 }, 1016 }, 1017 intermediates: [][]constraintsSpec{ 1018 { 1019 {}, 1020 }, 1021 }, 1022 leaf: leafSpec{ 1023 sans: []string{"uri:http://1.2.3.4:43/"}, 1024 }, 1025 expectedError: "URI with IP", 1026 }, 1027 1028 // #53: URIs with IPv6 addresses are also rejected 1029 { 1030 roots: []constraintsSpec{ 1031 { 1032 ok: []string{"uri:example.com"}, 1033 }, 1034 }, 1035 intermediates: [][]constraintsSpec{ 1036 { 1037 {}, 1038 }, 1039 }, 1040 leaf: leafSpec{ 1041 sans: []string{"uri:http://[2006:abcd::1]/"}, 1042 }, 1043 expectedError: "URI with IP", 1044 }, 1045 1046 // #54: URIs with IPv6 addresses with ports are also rejected 1047 { 1048 roots: []constraintsSpec{ 1049 { 1050 ok: []string{"uri:example.com"}, 1051 }, 1052 }, 1053 intermediates: [][]constraintsSpec{ 1054 { 1055 {}, 1056 }, 1057 }, 1058 leaf: leafSpec{ 1059 sans: []string{"uri:http://[2006:abcd::1]:16/"}, 1060 }, 1061 expectedError: "URI with IP", 1062 }, 1063 1064 // #55: URI constraints are effective 1065 { 1066 roots: []constraintsSpec{ 1067 { 1068 ok: []string{"uri:example.com"}, 1069 }, 1070 }, 1071 intermediates: [][]constraintsSpec{ 1072 { 1073 {}, 1074 }, 1075 }, 1076 leaf: leafSpec{ 1077 sans: []string{"uri:http://bar.com/"}, 1078 }, 1079 expectedError: "\"http://bar.com/\" is not permitted", 1080 }, 1081 1082 // #56: URI constraints are effective 1083 { 1084 roots: []constraintsSpec{ 1085 { 1086 bad: []string{"uri:foo.com"}, 1087 }, 1088 }, 1089 intermediates: [][]constraintsSpec{ 1090 { 1091 {}, 1092 }, 1093 }, 1094 leaf: leafSpec{ 1095 sans: []string{"uri:http://foo.com/"}, 1096 }, 1097 expectedError: "\"http://foo.com/\" is excluded", 1098 }, 1099 1100 // #57: URI constraints can allow subdomains 1101 { 1102 roots: []constraintsSpec{ 1103 { 1104 ok: []string{"uri:.foo.com"}, 1105 }, 1106 }, 1107 intermediates: [][]constraintsSpec{ 1108 { 1109 {}, 1110 }, 1111 }, 1112 leaf: leafSpec{ 1113 sans: []string{"uri:http://www.foo.com/"}, 1114 }, 1115 }, 1116 1117 // #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4 1118 // version of that address. 1119 { 1120 roots: []constraintsSpec{ 1121 { 1122 bad: []string{"ip:::ffff:1.2.3.4/128"}, 1123 }, 1124 }, 1125 intermediates: [][]constraintsSpec{ 1126 { 1127 {}, 1128 }, 1129 }, 1130 leaf: leafSpec{ 1131 sans: []string{"ip:1.2.3.4"}, 1132 }, 1133 }, 1134 1135 // #59: a URI constraint isn't matched by a URN. 1136 { 1137 roots: []constraintsSpec{ 1138 { 1139 ok: []string{"uri:example.com"}, 1140 }, 1141 }, 1142 intermediates: [][]constraintsSpec{ 1143 { 1144 {}, 1145 }, 1146 }, 1147 leaf: leafSpec{ 1148 sans: []string{"uri:urn:example"}, 1149 }, 1150 expectedError: "URI with empty host", 1151 }, 1152 1153 // #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses 1154 // too, even though IPv4 is mapped into the IPv6 range. 1155 { 1156 roots: []constraintsSpec{ 1157 { 1158 ok: []string{"ip:1.2.3.0/24"}, 1159 bad: []string{"ip:::0/0"}, 1160 }, 1161 }, 1162 intermediates: [][]constraintsSpec{ 1163 { 1164 {}, 1165 }, 1166 }, 1167 leaf: leafSpec{ 1168 sans: []string{"ip:1.2.3.4"}, 1169 }, 1170 }, 1171 1172 // #61: omitting extended key usage in a CA certificate implies that 1173 // any usage is ok. 1174 { 1175 roots: make([]constraintsSpec, 1), 1176 intermediates: [][]constraintsSpec{ 1177 { 1178 {}, 1179 }, 1180 }, 1181 leaf: leafSpec{ 1182 sans: []string{"dns:example.com"}, 1183 ekus: []string{"serverAuth", "other"}, 1184 }, 1185 }, 1186 1187 // #62: The “any” EKU also means that any usage is ok. 1188 { 1189 roots: make([]constraintsSpec, 1), 1190 intermediates: [][]constraintsSpec{ 1191 { 1192 { 1193 ekus: []string{"any"}, 1194 }, 1195 }, 1196 }, 1197 leaf: leafSpec{ 1198 sans: []string{"dns:example.com"}, 1199 ekus: []string{"serverAuth", "other"}, 1200 }, 1201 }, 1202 1203 // #63: An intermediate with enumerated EKUs causes a failure if we 1204 // test for an EKU not in that set. (ServerAuth is required by 1205 // default.) 1206 { 1207 roots: make([]constraintsSpec, 1), 1208 intermediates: [][]constraintsSpec{ 1209 { 1210 { 1211 ekus: []string{"email"}, 1212 }, 1213 }, 1214 }, 1215 leaf: leafSpec{ 1216 sans: []string{"dns:example.com"}, 1217 ekus: []string{"serverAuth"}, 1218 }, 1219 expectedError: "incompatible key usage", 1220 }, 1221 1222 // #64: an unknown EKU in the leaf doesn't break anything, even if it's not 1223 // correctly nested. 1224 { 1225 roots: make([]constraintsSpec, 1), 1226 intermediates: [][]constraintsSpec{ 1227 { 1228 { 1229 ekus: []string{"email"}, 1230 }, 1231 }, 1232 }, 1233 leaf: leafSpec{ 1234 sans: []string{"dns:example.com"}, 1235 ekus: []string{"other"}, 1236 }, 1237 requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny}, 1238 }, 1239 1240 // #65: trying to add extra permitted key usages in an intermediate 1241 // (after a limitation in the root) is acceptable so long as the leaf 1242 // certificate doesn't use them. 1243 { 1244 roots: []constraintsSpec{ 1245 { 1246 ekus: []string{"serverAuth"}, 1247 }, 1248 }, 1249 intermediates: [][]constraintsSpec{ 1250 { 1251 { 1252 ekus: []string{"serverAuth", "email"}, 1253 }, 1254 }, 1255 }, 1256 leaf: leafSpec{ 1257 sans: []string{"dns:example.com"}, 1258 ekus: []string{"serverAuth"}, 1259 }, 1260 }, 1261 1262 // #66: EKUs in roots are not ignored. 1263 { 1264 roots: []constraintsSpec{ 1265 { 1266 ekus: []string{"email"}, 1267 }, 1268 }, 1269 intermediates: [][]constraintsSpec{ 1270 { 1271 { 1272 ekus: []string{"serverAuth"}, 1273 }, 1274 }, 1275 }, 1276 leaf: leafSpec{ 1277 sans: []string{"dns:example.com"}, 1278 ekus: []string{"serverAuth"}, 1279 }, 1280 expectedError: "incompatible key usage", 1281 }, 1282 1283 // #67: in order to support COMODO chains, SGC key usages permit 1284 // serverAuth and clientAuth. 1285 { 1286 roots: []constraintsSpec{ 1287 {}, 1288 }, 1289 intermediates: [][]constraintsSpec{ 1290 { 1291 { 1292 ekus: []string{"netscapeSGC"}, 1293 }, 1294 }, 1295 }, 1296 leaf: leafSpec{ 1297 sans: []string{"dns:example.com"}, 1298 ekus: []string{"serverAuth", "clientAuth"}, 1299 }, 1300 }, 1301 1302 // #68: in order to support COMODO chains, SGC key usages permit 1303 // serverAuth and clientAuth. 1304 { 1305 roots: make([]constraintsSpec, 1), 1306 intermediates: [][]constraintsSpec{ 1307 { 1308 { 1309 ekus: []string{"msSGC"}, 1310 }, 1311 }, 1312 }, 1313 leaf: leafSpec{ 1314 sans: []string{"dns:example.com"}, 1315 ekus: []string{"serverAuth", "clientAuth"}, 1316 }, 1317 }, 1318 1319 // #69: an empty DNS constraint should allow anything. 1320 { 1321 roots: []constraintsSpec{ 1322 { 1323 ok: []string{"dns:"}, 1324 }, 1325 }, 1326 intermediates: [][]constraintsSpec{ 1327 { 1328 {}, 1329 }, 1330 }, 1331 leaf: leafSpec{ 1332 sans: []string{"dns:example.com"}, 1333 }, 1334 }, 1335 1336 // #70: an empty DNS constraint should also reject everything. 1337 { 1338 roots: []constraintsSpec{ 1339 { 1340 bad: []string{"dns:"}, 1341 }, 1342 }, 1343 intermediates: [][]constraintsSpec{ 1344 { 1345 {}, 1346 }, 1347 }, 1348 leaf: leafSpec{ 1349 sans: []string{"dns:example.com"}, 1350 }, 1351 expectedError: "\"example.com\" is excluded", 1352 }, 1353 1354 // #71: an empty email constraint should allow anything 1355 { 1356 roots: []constraintsSpec{ 1357 { 1358 ok: []string{"email:"}, 1359 }, 1360 }, 1361 intermediates: [][]constraintsSpec{ 1362 { 1363 {}, 1364 }, 1365 }, 1366 leaf: leafSpec{ 1367 sans: []string{"email:foo@example.com"}, 1368 }, 1369 }, 1370 1371 // #72: an empty email constraint should also reject everything. 1372 { 1373 roots: []constraintsSpec{ 1374 { 1375 bad: []string{"email:"}, 1376 }, 1377 }, 1378 intermediates: [][]constraintsSpec{ 1379 { 1380 {}, 1381 }, 1382 }, 1383 leaf: leafSpec{ 1384 sans: []string{"email:foo@example.com"}, 1385 }, 1386 expectedError: "\"foo@example.com\" is excluded", 1387 }, 1388 1389 // #73: an empty URI constraint should allow anything 1390 { 1391 roots: []constraintsSpec{ 1392 { 1393 ok: []string{"uri:"}, 1394 }, 1395 }, 1396 intermediates: [][]constraintsSpec{ 1397 { 1398 {}, 1399 }, 1400 }, 1401 leaf: leafSpec{ 1402 sans: []string{"uri:https://example.com/test"}, 1403 }, 1404 }, 1405 1406 // #74: an empty URI constraint should also reject everything. 1407 { 1408 roots: []constraintsSpec{ 1409 { 1410 bad: []string{"uri:"}, 1411 }, 1412 }, 1413 intermediates: [][]constraintsSpec{ 1414 { 1415 {}, 1416 }, 1417 }, 1418 leaf: leafSpec{ 1419 sans: []string{"uri:https://example.com/test"}, 1420 }, 1421 expectedError: "\"https://example.com/test\" is excluded", 1422 }, 1423 1424 // #75: serverAuth in a leaf shouldn't permit clientAuth when requested in 1425 // VerifyOptions. 1426 { 1427 roots: make([]constraintsSpec, 1), 1428 intermediates: [][]constraintsSpec{ 1429 { 1430 {}, 1431 }, 1432 }, 1433 leaf: leafSpec{ 1434 sans: []string{"dns:example.com"}, 1435 ekus: []string{"serverAuth"}, 1436 }, 1437 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}, 1438 expectedError: "incompatible key usage", 1439 }, 1440 1441 // #76: However, MSSGC in a leaf should match a request for serverAuth. 1442 { 1443 roots: make([]constraintsSpec, 1), 1444 intermediates: [][]constraintsSpec{ 1445 { 1446 {}, 1447 }, 1448 }, 1449 leaf: leafSpec{ 1450 sans: []string{"dns:example.com"}, 1451 ekus: []string{"msSGC"}, 1452 }, 1453 requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}, 1454 }, 1455 1456 // An invalid DNS SAN should be detected only at validation time so 1457 // that we can process CA certificates in the wild that have invalid SANs. 1458 // See https://github.com/golang/go/issues/23995 1459 1460 // #77: an invalid DNS or mail SAN will not be detected if name constraint 1461 // checking is not triggered. 1462 { 1463 roots: make([]constraintsSpec, 1), 1464 intermediates: [][]constraintsSpec{ 1465 { 1466 {}, 1467 }, 1468 }, 1469 leaf: leafSpec{ 1470 sans: []string{"dns:this is invalid", "email:this @ is invalid"}, 1471 }, 1472 }, 1473 1474 // #78: an invalid DNS SAN will be detected if any name constraint checking 1475 // is triggered. 1476 { 1477 roots: []constraintsSpec{ 1478 { 1479 bad: []string{"uri:"}, 1480 }, 1481 }, 1482 intermediates: [][]constraintsSpec{ 1483 { 1484 {}, 1485 }, 1486 }, 1487 leaf: leafSpec{ 1488 sans: []string{"dns:this is invalid"}, 1489 }, 1490 expectedError: "cannot parse dnsName", 1491 }, 1492 1493 // #79: an invalid email SAN will be detected if any name constraint 1494 // checking is triggered. 1495 { 1496 roots: []constraintsSpec{ 1497 { 1498 bad: []string{"uri:"}, 1499 }, 1500 }, 1501 intermediates: [][]constraintsSpec{ 1502 { 1503 {}, 1504 }, 1505 }, 1506 leaf: leafSpec{ 1507 sans: []string{"email:this @ is invalid"}, 1508 }, 1509 expectedError: "cannot parse rfc822Name", 1510 }, 1511 1512 // #80: if several EKUs are requested, satisfying any of them is sufficient. 1513 { 1514 roots: make([]constraintsSpec, 1), 1515 intermediates: [][]constraintsSpec{ 1516 { 1517 {}, 1518 }, 1519 }, 1520 leaf: leafSpec{ 1521 sans: []string{"dns:example.com"}, 1522 ekus: []string{"email"}, 1523 }, 1524 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection}, 1525 }, 1526 1527 // #81: EKUs that are not asserted in VerifyOpts are not required to be 1528 // nested. 1529 { 1530 roots: make([]constraintsSpec, 1), 1531 intermediates: [][]constraintsSpec{ 1532 { 1533 { 1534 ekus: []string{"serverAuth"}, 1535 }, 1536 }, 1537 }, 1538 leaf: leafSpec{ 1539 sans: []string{"dns:example.com"}, 1540 // There's no email EKU in the intermediate. This would be rejected if 1541 // full nesting was required. 1542 ekus: []string{"email", "serverAuth"}, 1543 }, 1544 }, 1545 1546 // #82: a certificate without SANs and CN is accepted in a constrained chain. 1547 { 1548 roots: []constraintsSpec{ 1549 { 1550 ok: []string{"dns:foo.com", "dns:.foo.com"}, 1551 }, 1552 }, 1553 intermediates: [][]constraintsSpec{ 1554 { 1555 {}, 1556 }, 1557 }, 1558 leaf: leafSpec{ 1559 sans: []string{}, 1560 }, 1561 }, 1562 1563 // #83: a certificate without SANs and with a CN that does not parse as a 1564 // hostname is accepted in a constrained chain. 1565 { 1566 roots: []constraintsSpec{ 1567 { 1568 ok: []string{"dns:foo.com", "dns:.foo.com"}, 1569 }, 1570 }, 1571 intermediates: [][]constraintsSpec{ 1572 { 1573 {}, 1574 }, 1575 }, 1576 leaf: leafSpec{ 1577 sans: []string{}, 1578 cn: "foo,bar", 1579 }, 1580 }, 1581 1582 // #84: a certificate with SANs and CN is accepted in a constrained chain. 1583 { 1584 roots: []constraintsSpec{ 1585 { 1586 ok: []string{"dns:foo.com", "dns:.foo.com"}, 1587 }, 1588 }, 1589 intermediates: [][]constraintsSpec{ 1590 { 1591 {}, 1592 }, 1593 }, 1594 leaf: leafSpec{ 1595 sans: []string{"dns:foo.com"}, 1596 cn: "foo.bar", 1597 }, 1598 }, 1599 } 1600 1601 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { 1602 var serialBytes [16]byte 1603 _, err := rand.Read(serialBytes[:]) 1604 if err != nil { 1605 return nil, err 1606 } 1607 1608 template := &Certificate{ 1609 SerialNumber: new(big.Int).SetBytes(serialBytes[:]), 1610 Subject: pkix.Name{ 1611 CommonName: name, 1612 }, 1613 NotBefore: time.Unix(1000, 0), 1614 NotAfter: time.Unix(2000, 0), 1615 KeyUsage: KeyUsageCertSign, 1616 BasicConstraintsValid: true, 1617 IsCA: true, 1618 } 1619 1620 if err := addConstraintsToTemplate(constraints, template); err != nil { 1621 return nil, err 1622 } 1623 1624 if parent == nil { 1625 parent = template 1626 } 1627 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) 1628 if err != nil { 1629 return nil, err 1630 } 1631 1632 caCert, err := ParseCertificate(derBytes) 1633 if err != nil { 1634 return nil, err 1635 } 1636 1637 return caCert, nil 1638 } 1639 1640 func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { 1641 var serialBytes [16]byte 1642 if _, err := rand.Read(serialBytes[:]); err != nil { 1643 return nil, err 1644 } 1645 1646 template := &Certificate{ 1647 SerialNumber: new(big.Int).SetBytes(serialBytes[:]), 1648 Subject: pkix.Name{ 1649 OrganizationalUnit: []string{"Leaf"}, 1650 CommonName: leaf.cn, 1651 }, 1652 NotBefore: time.Unix(1000, 0), 1653 NotAfter: time.Unix(2000, 0), 1654 KeyUsage: KeyUsageDigitalSignature, 1655 BasicConstraintsValid: true, 1656 IsCA: false, 1657 } 1658 1659 for _, name := range leaf.sans { 1660 switch { 1661 case strings.HasPrefix(name, "dns:"): 1662 template.DNSNames = append(template.DNSNames, name[4:]) 1663 1664 case strings.HasPrefix(name, "ip:"): 1665 ip := net.ParseIP(name[3:]) 1666 if ip == nil { 1667 return nil, fmt.Errorf("cannot parse IP %q", name[3:]) 1668 } 1669 template.IPAddresses = append(template.IPAddresses, ip) 1670 1671 case strings.HasPrefix(name, "invalidip:"): 1672 ipBytes, err := hex.DecodeString(name[10:]) 1673 if err != nil { 1674 return nil, fmt.Errorf("cannot parse invalid IP: %s", err) 1675 } 1676 template.IPAddresses = append(template.IPAddresses, ipBytes) 1677 1678 case strings.HasPrefix(name, "email:"): 1679 template.EmailAddresses = append(template.EmailAddresses, name[6:]) 1680 1681 case strings.HasPrefix(name, "uri:"): 1682 uri, err := url.Parse(name[4:]) 1683 if err != nil { 1684 return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err) 1685 } 1686 template.URIs = append(template.URIs, uri) 1687 1688 case strings.HasPrefix(name, "unknown:"): 1689 // This is a special case for testing unknown 1690 // name types. A custom SAN extension is 1691 // injected into the certificate. 1692 if len(leaf.sans) != 1 { 1693 panic("when using unknown name types, it must be the sole name") 1694 } 1695 1696 template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{ 1697 Id: []int{2, 5, 29, 17}, 1698 Value: []byte{ 1699 0x30, // SEQUENCE 1700 3, // three bytes 1701 9, // undefined GeneralName type 9 1702 1, 1703 1, 1704 }, 1705 }) 1706 1707 default: 1708 return nil, fmt.Errorf("unknown name type %q", name) 1709 } 1710 } 1711 1712 var err error 1713 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil { 1714 return nil, err 1715 } 1716 1717 if parent == nil { 1718 parent = template 1719 } 1720 1721 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) 1722 if err != nil { 1723 return nil, err 1724 } 1725 1726 return ParseCertificate(derBytes) 1727 } 1728 1729 func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension { 1730 appendConstraint := func(contents []byte, tag uint8) []byte { 1731 contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */) 1732 contents = append(contents, byte(4+len(constraint)) /* length */) 1733 contents = append(contents, 0x30 /* SEQUENCE */) 1734 contents = append(contents, byte(2+len(constraint)) /* length */) 1735 contents = append(contents, byte(typeNum) /* GeneralName type */) 1736 contents = append(contents, byte(len(constraint))) 1737 return append(contents, constraint...) 1738 } 1739 1740 var contents []byte 1741 if !isExcluded { 1742 contents = appendConstraint(contents, 0 /* tag 0 for permitted */) 1743 } else { 1744 contents = appendConstraint(contents, 1 /* tag 1 for excluded */) 1745 } 1746 1747 var value []byte 1748 value = append(value, 0x30 /* SEQUENCE */) 1749 value = append(value, byte(len(contents))) 1750 value = append(value, contents...) 1751 1752 return pkix.Extension{ 1753 Id: []int{2, 5, 29, 30}, 1754 Value: value, 1755 } 1756 } 1757 1758 func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error { 1759 parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) { 1760 for _, constraint := range constraints { 1761 switch { 1762 case strings.HasPrefix(constraint, "dns:"): 1763 dnsNames = append(dnsNames, constraint[4:]) 1764 1765 case strings.HasPrefix(constraint, "ip:"): 1766 _, ipNet, err := net.ParseCIDR(constraint[3:]) 1767 if err != nil { 1768 return nil, nil, nil, nil, err 1769 } 1770 ips = append(ips, ipNet) 1771 1772 case strings.HasPrefix(constraint, "email:"): 1773 emailAddrs = append(emailAddrs, constraint[6:]) 1774 1775 case strings.HasPrefix(constraint, "uri:"): 1776 uriDomains = append(uriDomains, constraint[4:]) 1777 1778 default: 1779 return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint) 1780 } 1781 } 1782 1783 return dnsNames, ips, emailAddrs, uriDomains, err 1784 } 1785 1786 handleSpecialConstraint := func(constraint string, isExcluded bool) bool { 1787 switch { 1788 case constraint == "unknown:": 1789 template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded)) 1790 1791 default: 1792 return false 1793 } 1794 1795 return true 1796 } 1797 1798 if len(constraints.ok) == 1 && len(constraints.bad) == 0 { 1799 if handleSpecialConstraint(constraints.ok[0], false) { 1800 return nil 1801 } 1802 } 1803 1804 if len(constraints.bad) == 1 && len(constraints.ok) == 0 { 1805 if handleSpecialConstraint(constraints.bad[0], true) { 1806 return nil 1807 } 1808 } 1809 1810 var err error 1811 template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok) 1812 if err != nil { 1813 return err 1814 } 1815 1816 template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad) 1817 if err != nil { 1818 return err 1819 } 1820 1821 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil { 1822 return err 1823 } 1824 1825 return nil 1826 } 1827 1828 func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) { 1829 for _, s := range ekuStrs { 1830 switch s { 1831 case "serverAuth": 1832 ekus = append(ekus, ExtKeyUsageServerAuth) 1833 case "clientAuth": 1834 ekus = append(ekus, ExtKeyUsageClientAuth) 1835 case "email": 1836 ekus = append(ekus, ExtKeyUsageEmailProtection) 1837 case "netscapeSGC": 1838 ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto) 1839 case "msSGC": 1840 ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto) 1841 case "any": 1842 ekus = append(ekus, ExtKeyUsageAny) 1843 case "other": 1844 unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3}) 1845 default: 1846 return nil, nil, fmt.Errorf("unknown EKU %q", s) 1847 } 1848 } 1849 1850 return 1851 } 1852 1853 func TestConstraintCases(t *testing.T) { 1854 privateKeys := sync.Pool{ 1855 New: func() interface{} { 1856 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 1857 if err != nil { 1858 panic(err) 1859 } 1860 return priv 1861 }, 1862 } 1863 1864 for i, test := range nameConstraintsTests { 1865 rootPool := NewCertPool() 1866 rootKey := privateKeys.Get().(*ecdsa.PrivateKey) 1867 rootName := "Root " + strconv.Itoa(i) 1868 1869 // keys keeps track of all the private keys used in a given 1870 // test and puts them back in the privateKeys pool at the end. 1871 keys := []*ecdsa.PrivateKey{rootKey} 1872 1873 // At each level (root, intermediate(s), leaf), parent points to 1874 // an example parent certificate and parentKey the key for the 1875 // parent level. Since all certificates at a given level have 1876 // the same name and public key, any parent certificate is 1877 // sufficient to get the correct issuer name and authority 1878 // key ID. 1879 var parent *Certificate 1880 parentKey := rootKey 1881 1882 for _, root := range test.roots { 1883 rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey) 1884 if err != nil { 1885 t.Fatalf("#%d: failed to create root: %s", i, err) 1886 } 1887 1888 parent = rootCert 1889 rootPool.AddCert(rootCert) 1890 } 1891 1892 intermediatePool := NewCertPool() 1893 1894 for level, intermediates := range test.intermediates { 1895 levelKey := privateKeys.Get().(*ecdsa.PrivateKey) 1896 keys = append(keys, levelKey) 1897 levelName := "Intermediate level " + strconv.Itoa(level) 1898 var last *Certificate 1899 1900 for _, intermediate := range intermediates { 1901 caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey) 1902 if err != nil { 1903 t.Fatalf("#%d: failed to create %q: %s", i, levelName, err) 1904 } 1905 1906 last = caCert 1907 intermediatePool.AddCert(caCert) 1908 } 1909 1910 parent = last 1911 parentKey = levelKey 1912 } 1913 1914 leafKey := privateKeys.Get().(*ecdsa.PrivateKey) 1915 keys = append(keys, leafKey) 1916 1917 leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey) 1918 if err != nil { 1919 t.Fatalf("#%d: cannot create leaf: %s", i, err) 1920 } 1921 1922 // Skip tests with CommonName set because OpenSSL will try to match it 1923 // against name constraints, while we ignore it when it's not hostname-looking. 1924 //goland:noinspection GoBoolExpressions 1925 if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" { 1926 output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool) 1927 if err == nil && len(test.expectedError) > 0 { 1928 t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i) 1929 if debugOpenSSLFailure { 1930 return 1931 } 1932 } 1933 1934 if err != nil { 1935 if _, ok := err.(*exec.ExitError); !ok { 1936 t.Errorf("#%d: OpenSSL failed to run: %s", i, err) 1937 } else if len(test.expectedError) == 0 { 1938 t.Errorf("#%d: OpenSSL unexpectedly failed: %v", i, output) 1939 if debugOpenSSLFailure { 1940 return 1941 } 1942 } 1943 } 1944 } 1945 1946 verifyOpts := VerifyOptions{ 1947 Roots: rootPool, 1948 Intermediates: intermediatePool, 1949 CurrentTime: time.Unix(1500, 0), 1950 KeyUsages: test.requestedEKUs, 1951 } 1952 _, err = leafCert.Verify(verifyOpts) 1953 1954 logInfo := true 1955 if len(test.expectedError) == 0 { 1956 if err != nil { 1957 t.Errorf("#%d: unexpected failure: %s", i, err) 1958 } else { 1959 logInfo = false 1960 } 1961 } else { 1962 if err == nil { 1963 t.Errorf("#%d: unexpected success", i) 1964 } else if !strings.Contains(err.Error(), test.expectedError) { 1965 t.Errorf("#%d: expected error containing %q, but got: %s", i, test.expectedError, err) 1966 } else { 1967 logInfo = false 1968 } 1969 } 1970 1971 if logInfo { 1972 certAsPEM := func(cert *Certificate) string { 1973 var buf bytes.Buffer 1974 err := pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) 1975 if err != nil { 1976 t.Fatal(err) 1977 } 1978 return buf.String() 1979 } 1980 t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.mustCert(t, 0))) 1981 t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert)) 1982 } 1983 1984 for _, key := range keys { 1985 privateKeys.Put(key) 1986 } 1987 } 1988 } 1989 1990 func writePEMsToTempFile(certs []*Certificate) *os.File { 1991 file, err := os.CreateTemp("", "name_constraints_test") 1992 if err != nil { 1993 panic("cannot create tempfile") 1994 } 1995 1996 pemBlock := &pem.Block{Type: "CERTIFICATE"} 1997 for _, cert := range certs { 1998 pemBlock.Bytes = cert.Raw 1999 err := pem.Encode(file, pemBlock) 2000 if err != nil { 2001 panic(err) 2002 } 2003 } 2004 2005 return file 2006 } 2007 2008 func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) { 2009 args := []string{"verify", "-no_check_time"} 2010 2011 rootsFile := writePEMsToTempFile(allCerts(t, roots)) 2012 if debugOpenSSLFailure { 2013 println("roots file:", rootsFile.Name()) 2014 } else { 2015 defer func(name string) { 2016 err := os.Remove(name) 2017 if err != nil { 2018 panic(err) 2019 } 2020 }(rootsFile.Name()) 2021 } 2022 args = append(args, "-CAfile", rootsFile.Name()) 2023 2024 if intermediates.len() > 0 { 2025 intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates)) 2026 if debugOpenSSLFailure { 2027 println("intermediates file:", intermediatesFile.Name()) 2028 } else { 2029 defer func(name string) { 2030 err := os.Remove(name) 2031 if err != nil { 2032 panic(err) 2033 } 2034 }(intermediatesFile.Name()) 2035 } 2036 args = append(args, "-untrusted", intermediatesFile.Name()) 2037 } 2038 2039 leafFile := writePEMsToTempFile([]*Certificate{leaf}) 2040 if debugOpenSSLFailure { 2041 println("leaf file:", leafFile.Name()) 2042 } else { 2043 defer func(name string) { 2044 err := os.Remove(name) 2045 if err != nil { 2046 panic(err) 2047 } 2048 }(leafFile.Name()) 2049 } 2050 args = append(args, leafFile.Name()) 2051 2052 var output bytes.Buffer 2053 cmd := exec.Command("openssl", args...) 2054 cmd.Stdout = &output 2055 cmd.Stderr = &output 2056 2057 err := cmd.Run() 2058 return output.String(), err 2059 } 2060 2061 var rfc2821Tests = []struct { 2062 in string 2063 localPart, domain string 2064 }{ 2065 {"foo@example.com", "foo", "example.com"}, 2066 {"@example.com", "", ""}, 2067 {"\"@example.com", "", ""}, 2068 {"\"\"@example.com", "", "example.com"}, 2069 {"\"a\"@example.com", "a", "example.com"}, 2070 {"\"\\a\"@example.com", "a", "example.com"}, 2071 {"a\"@example.com", "", ""}, 2072 {"foo..bar@example.com", "", ""}, 2073 {".foo.bar@example.com", "", ""}, 2074 {"foo.bar.@example.com", "", ""}, 2075 {"|{}?'@example.com", "|{}?'", "example.com"}, 2076 2077 // Examples from RFC 3696 2078 {"Abc\\@def@example.com", "Abc@def", "example.com"}, 2079 {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"}, 2080 {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"}, 2081 {"\"Abc@def\"@example.com", "Abc@def", "example.com"}, 2082 {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"}, 2083 {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"}, 2084 {"$A12345@example.com", "$A12345", "example.com"}, 2085 {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"}, 2086 {"_somename@example.com", "_somename", "example.com"}, 2087 } 2088 2089 func TestRFC2821Parsing(t *testing.T) { 2090 for i, test := range rfc2821Tests { 2091 mailbox, ok := parseRFC2821Mailbox(test.in) 2092 expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0 2093 2094 if ok && expectedFailure { 2095 t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain) 2096 continue 2097 } 2098 2099 if !ok && !expectedFailure { 2100 t.Errorf("#%d: unexpected failure for %q", i, test.in) 2101 continue 2102 } 2103 2104 if !ok { 2105 continue 2106 } 2107 2108 if mailbox.local != test.localPart || mailbox.domain != test.domain { 2109 t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain) 2110 } 2111 } 2112 } 2113 2114 func TestBadNamesInConstraints(t *testing.T) { 2115 constraintParseError := func(err error) bool { 2116 str := err.Error() 2117 return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint") 2118 } 2119 2120 encodingError := func(err error) bool { 2121 return strings.Contains(err.Error(), "cannot be encoded as an IA5String") 2122 } 2123 2124 // Bad names in constraints should not parse. 2125 badNames := []struct { 2126 name string 2127 matcher func(error) bool 2128 }{ 2129 {"dns:foo.com.", constraintParseError}, 2130 {"email:abc@foo.com.", constraintParseError}, 2131 {"email:foo.com.", constraintParseError}, 2132 {"uri:example.com.", constraintParseError}, 2133 {"uri:1.2.3.4", constraintParseError}, 2134 {"uri:ffff::1", constraintParseError}, 2135 {"dns:not–hyphen.com", encodingError}, 2136 {"email:foo@not–hyphen.com", encodingError}, 2137 {"uri:not–hyphen.com", encodingError}, 2138 } 2139 2140 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2141 if err != nil { 2142 panic(err) 2143 } 2144 2145 for _, test := range badNames { 2146 _, err := makeConstraintsCACert(constraintsSpec{ 2147 ok: []string{test.name}, 2148 }, "TestAbsoluteNamesInConstraints", priv, nil, priv) 2149 2150 if err == nil { 2151 t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name) 2152 continue 2153 } else { 2154 if !test.matcher(err) { 2155 t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err) 2156 } 2157 } 2158 } 2159 } 2160 2161 func TestBadNamesInSANs(t *testing.T) { 2162 // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs 2163 // will parse and are tested in name constraint tests at the top of this 2164 // file. 2165 badNames := []string{ 2166 "uri:https://example.com./dsf", 2167 "invalidip:0102", 2168 "invalidip:0102030405", 2169 } 2170 2171 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2172 if err != nil { 2173 panic(err) 2174 } 2175 2176 for _, badName := range badNames { 2177 _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv) 2178 2179 if err == nil { 2180 t.Errorf("bad name %q unexpectedly accepted in SAN", badName) 2181 continue 2182 } 2183 2184 if str := err.Error(); !strings.Contains(str, "cannot parse ") { 2185 t.Errorf("bad name %q triggered unrecognised error: %s", badName, str) 2186 } 2187 } 2188 }