github.com/fisco-bcos/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/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 "github.com/FISCO-BCOS/crypto/ecdsa" 10 "github.com/FISCO-BCOS/crypto/elliptic" 11 "crypto/rand" 12 "crypto/x509/pkix" 13 "encoding/asn1" 14 "encoding/hex" 15 "encoding/pem" 16 "fmt" 17 "io/ioutil" 18 "math/big" 19 "net" 20 "net/url" 21 "os" 22 "os/exec" 23 "strconv" 24 "strings" 25 "sync" 26 "testing" 27 "time" 28 ) 29 30 const ( 31 // testNameConstraintsAgainstOpenSSL can be set to true to run tests 32 // against the system OpenSSL. This is disabled by default because Go 33 // cannot depend on having OpenSSL installed at testing time. 34 testNameConstraintsAgainstOpenSSL = false 35 36 // debugOpenSSLFailure can be set to true, when 37 // testNameConstraintsAgainstOpenSSL is also true, to cause 38 // intermediate files to be preserved for debugging. 39 debugOpenSSLFailure = false 40 ) 41 42 type nameConstraintsTest struct { 43 roots []constraintsSpec 44 intermediates [][]constraintsSpec 45 leaf leafSpec 46 requestedEKUs []ExtKeyUsage 47 expectedError string 48 noOpenSSL bool 49 ignoreCN bool 50 } 51 52 type constraintsSpec struct { 53 ok []string 54 bad []string 55 ekus []string 56 } 57 58 type leafSpec struct { 59 sans []string 60 ekus []string 61 cn string 62 } 63 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 rejected in a constrained chain. 619 { 620 roots: []constraintsSpec{ 621 { 622 ok: []string{"dns:foo.com", "dns:.foo.com"}, 623 }, 624 }, 625 intermediates: [][]constraintsSpec{ 626 { 627 {}, 628 }, 629 }, 630 leaf: leafSpec{ 631 sans: []string{}, 632 cn: "foo.com", 633 }, 634 expectedError: "leaf doesn't have a SAN extension", 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 constaint 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 // #85: without SANs, a certificate with a valid CN is accepted in a 1601 // constrained chain if x509ignoreCN is set. 1602 { 1603 roots: []constraintsSpec{ 1604 { 1605 ok: []string{"dns:foo.com", "dns:.foo.com"}, 1606 }, 1607 }, 1608 intermediates: [][]constraintsSpec{ 1609 { 1610 {}, 1611 }, 1612 }, 1613 leaf: leafSpec{ 1614 sans: []string{}, 1615 cn: "foo.com", 1616 }, 1617 ignoreCN: true, 1618 }, 1619 } 1620 1621 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { 1622 var serialBytes [16]byte 1623 rand.Read(serialBytes[:]) 1624 1625 template := &Certificate{ 1626 SerialNumber: new(big.Int).SetBytes(serialBytes[:]), 1627 Subject: pkix.Name{ 1628 CommonName: name, 1629 }, 1630 NotBefore: time.Unix(1000, 0), 1631 NotAfter: time.Unix(2000, 0), 1632 KeyUsage: KeyUsageCertSign, 1633 BasicConstraintsValid: true, 1634 IsCA: true, 1635 } 1636 1637 if err := addConstraintsToTemplate(constraints, template); err != nil { 1638 return nil, err 1639 } 1640 1641 if parent == nil { 1642 parent = template 1643 } 1644 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) 1645 if err != nil { 1646 return nil, err 1647 } 1648 1649 caCert, err := ParseCertificate(derBytes) 1650 if err != nil { 1651 return nil, err 1652 } 1653 1654 return caCert, nil 1655 } 1656 1657 func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { 1658 var serialBytes [16]byte 1659 rand.Read(serialBytes[:]) 1660 1661 template := &Certificate{ 1662 SerialNumber: new(big.Int).SetBytes(serialBytes[:]), 1663 Subject: pkix.Name{ 1664 OrganizationalUnit: []string{"Leaf"}, 1665 CommonName: leaf.cn, 1666 }, 1667 NotBefore: time.Unix(1000, 0), 1668 NotAfter: time.Unix(2000, 0), 1669 KeyUsage: KeyUsageDigitalSignature, 1670 BasicConstraintsValid: true, 1671 IsCA: false, 1672 } 1673 1674 for _, name := range leaf.sans { 1675 switch { 1676 case strings.HasPrefix(name, "dns:"): 1677 template.DNSNames = append(template.DNSNames, name[4:]) 1678 1679 case strings.HasPrefix(name, "ip:"): 1680 ip := net.ParseIP(name[3:]) 1681 if ip == nil { 1682 return nil, fmt.Errorf("cannot parse IP %q", name[3:]) 1683 } 1684 template.IPAddresses = append(template.IPAddresses, ip) 1685 1686 case strings.HasPrefix(name, "invalidip:"): 1687 ipBytes, err := hex.DecodeString(name[10:]) 1688 if err != nil { 1689 return nil, fmt.Errorf("cannot parse invalid IP: %s", err) 1690 } 1691 template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes)) 1692 1693 case strings.HasPrefix(name, "email:"): 1694 template.EmailAddresses = append(template.EmailAddresses, name[6:]) 1695 1696 case strings.HasPrefix(name, "uri:"): 1697 uri, err := url.Parse(name[4:]) 1698 if err != nil { 1699 return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err) 1700 } 1701 template.URIs = append(template.URIs, uri) 1702 1703 case strings.HasPrefix(name, "unknown:"): 1704 // This is a special case for testing unknown 1705 // name types. A custom SAN extension is 1706 // injected into the certificate. 1707 if len(leaf.sans) != 1 { 1708 panic("when using unknown name types, it must be the sole name") 1709 } 1710 1711 template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{ 1712 Id: []int{2, 5, 29, 17}, 1713 Value: []byte{ 1714 0x30, // SEQUENCE 1715 3, // three bytes 1716 9, // undefined GeneralName type 9 1717 1, 1718 1, 1719 }, 1720 }) 1721 1722 default: 1723 return nil, fmt.Errorf("unknown name type %q", name) 1724 } 1725 } 1726 1727 var err error 1728 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil { 1729 return nil, err 1730 } 1731 1732 if parent == nil { 1733 parent = template 1734 } 1735 1736 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) 1737 if err != nil { 1738 return nil, err 1739 } 1740 1741 return ParseCertificate(derBytes) 1742 } 1743 1744 func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension { 1745 appendConstraint := func(contents []byte, tag uint8) []byte { 1746 contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */) 1747 contents = append(contents, byte(4+len(constraint)) /* length */) 1748 contents = append(contents, 0x30 /* SEQUENCE */) 1749 contents = append(contents, byte(2+len(constraint)) /* length */) 1750 contents = append(contents, byte(typeNum) /* GeneralName type */) 1751 contents = append(contents, byte(len(constraint))) 1752 return append(contents, constraint...) 1753 } 1754 1755 var contents []byte 1756 if !isExcluded { 1757 contents = appendConstraint(contents, 0 /* tag 0 for permitted */) 1758 } else { 1759 contents = appendConstraint(contents, 1 /* tag 1 for excluded */) 1760 } 1761 1762 var value []byte 1763 value = append(value, 0x30 /* SEQUENCE */) 1764 value = append(value, byte(len(contents))) 1765 value = append(value, contents...) 1766 1767 return pkix.Extension{ 1768 Id: []int{2, 5, 29, 30}, 1769 Value: value, 1770 } 1771 } 1772 1773 func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error { 1774 parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) { 1775 for _, constraint := range constraints { 1776 switch { 1777 case strings.HasPrefix(constraint, "dns:"): 1778 dnsNames = append(dnsNames, constraint[4:]) 1779 1780 case strings.HasPrefix(constraint, "ip:"): 1781 _, ipNet, err := net.ParseCIDR(constraint[3:]) 1782 if err != nil { 1783 return nil, nil, nil, nil, err 1784 } 1785 ips = append(ips, ipNet) 1786 1787 case strings.HasPrefix(constraint, "email:"): 1788 emailAddrs = append(emailAddrs, constraint[6:]) 1789 1790 case strings.HasPrefix(constraint, "uri:"): 1791 uriDomains = append(uriDomains, constraint[4:]) 1792 1793 default: 1794 return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint) 1795 } 1796 } 1797 1798 return dnsNames, ips, emailAddrs, uriDomains, err 1799 } 1800 1801 handleSpecialConstraint := func(constraint string, isExcluded bool) bool { 1802 switch { 1803 case constraint == "unknown:": 1804 template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded)) 1805 1806 default: 1807 return false 1808 } 1809 1810 return true 1811 } 1812 1813 if len(constraints.ok) == 1 && len(constraints.bad) == 0 { 1814 if handleSpecialConstraint(constraints.ok[0], false) { 1815 return nil 1816 } 1817 } 1818 1819 if len(constraints.bad) == 1 && len(constraints.ok) == 0 { 1820 if handleSpecialConstraint(constraints.bad[0], true) { 1821 return nil 1822 } 1823 } 1824 1825 var err error 1826 template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok) 1827 if err != nil { 1828 return err 1829 } 1830 1831 template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad) 1832 if err != nil { 1833 return err 1834 } 1835 1836 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil { 1837 return err 1838 } 1839 1840 return nil 1841 } 1842 1843 func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) { 1844 for _, s := range ekuStrs { 1845 switch s { 1846 case "serverAuth": 1847 ekus = append(ekus, ExtKeyUsageServerAuth) 1848 case "clientAuth": 1849 ekus = append(ekus, ExtKeyUsageClientAuth) 1850 case "email": 1851 ekus = append(ekus, ExtKeyUsageEmailProtection) 1852 case "netscapeSGC": 1853 ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto) 1854 case "msSGC": 1855 ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto) 1856 case "any": 1857 ekus = append(ekus, ExtKeyUsageAny) 1858 case "other": 1859 unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3}) 1860 default: 1861 return nil, nil, fmt.Errorf("unknown EKU %q", s) 1862 } 1863 } 1864 1865 return 1866 } 1867 1868 func TestConstraintCases(t *testing.T) { 1869 defer func(savedIgnoreCN bool) { 1870 ignoreCN = savedIgnoreCN 1871 }(ignoreCN) 1872 1873 privateKeys := sync.Pool{ 1874 New: func() interface{} { 1875 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 1876 if err != nil { 1877 panic(err) 1878 } 1879 return priv 1880 }, 1881 } 1882 1883 for i, test := range nameConstraintsTests { 1884 rootPool := NewCertPool() 1885 rootKey := privateKeys.Get().(*ecdsa.PrivateKey) 1886 rootName := "Root " + strconv.Itoa(i) 1887 1888 // keys keeps track of all the private keys used in a given 1889 // test and puts them back in the privateKeys pool at the end. 1890 keys := []*ecdsa.PrivateKey{rootKey} 1891 1892 // At each level (root, intermediate(s), leaf), parent points to 1893 // an example parent certificate and parentKey the key for the 1894 // parent level. Since all certificates at a given level have 1895 // the same name and public key, any parent certificate is 1896 // sufficient to get the correct issuer name and authority 1897 // key ID. 1898 var parent *Certificate 1899 parentKey := rootKey 1900 1901 for _, root := range test.roots { 1902 rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey) 1903 if err != nil { 1904 t.Fatalf("#%d: failed to create root: %s", i, err) 1905 } 1906 1907 parent = rootCert 1908 rootPool.AddCert(rootCert) 1909 } 1910 1911 intermediatePool := NewCertPool() 1912 1913 for level, intermediates := range test.intermediates { 1914 levelKey := privateKeys.Get().(*ecdsa.PrivateKey) 1915 keys = append(keys, levelKey) 1916 levelName := "Intermediate level " + strconv.Itoa(level) 1917 var last *Certificate 1918 1919 for _, intermediate := range intermediates { 1920 caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey) 1921 if err != nil { 1922 t.Fatalf("#%d: failed to create %q: %s", i, levelName, err) 1923 } 1924 1925 last = caCert 1926 intermediatePool.AddCert(caCert) 1927 } 1928 1929 parent = last 1930 parentKey = levelKey 1931 } 1932 1933 leafKey := privateKeys.Get().(*ecdsa.PrivateKey) 1934 keys = append(keys, leafKey) 1935 1936 leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey) 1937 if err != nil { 1938 t.Fatalf("#%d: cannot create leaf: %s", i, err) 1939 } 1940 1941 // Skip tests with CommonName set because OpenSSL will try to match it 1942 // against name constraints, while we ignore it when it's not hostname-looking. 1943 if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" { 1944 output, err := testChainAgainstOpenSSL(leafCert, intermediatePool, rootPool) 1945 if err == nil && len(test.expectedError) > 0 { 1946 t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i) 1947 if debugOpenSSLFailure { 1948 return 1949 } 1950 } 1951 1952 if err != nil { 1953 if _, ok := err.(*exec.ExitError); !ok { 1954 t.Errorf("#%d: OpenSSL failed to run: %s", i, err) 1955 } else if len(test.expectedError) == 0 { 1956 t.Errorf("#%d: OpenSSL unexpectedly failed: %v", i, output) 1957 if debugOpenSSLFailure { 1958 return 1959 } 1960 } 1961 } 1962 } 1963 1964 ignoreCN = test.ignoreCN 1965 verifyOpts := VerifyOptions{ 1966 Roots: rootPool, 1967 Intermediates: intermediatePool, 1968 CurrentTime: time.Unix(1500, 0), 1969 KeyUsages: test.requestedEKUs, 1970 } 1971 _, err = leafCert.Verify(verifyOpts) 1972 1973 logInfo := true 1974 if len(test.expectedError) == 0 { 1975 if err != nil { 1976 t.Errorf("#%d: unexpected failure: %s", i, err) 1977 } else { 1978 logInfo = false 1979 } 1980 } else { 1981 if err == nil { 1982 t.Errorf("#%d: unexpected success", i) 1983 } else if !strings.Contains(err.Error(), test.expectedError) { 1984 t.Errorf("#%d: expected error containing %q, but got: %s", i, test.expectedError, err) 1985 } else { 1986 logInfo = false 1987 } 1988 } 1989 1990 if logInfo { 1991 certAsPEM := func(cert *Certificate) string { 1992 var buf bytes.Buffer 1993 pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) 1994 return buf.String() 1995 } 1996 t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0])) 1997 t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert)) 1998 } 1999 2000 for _, key := range keys { 2001 privateKeys.Put(key) 2002 } 2003 keys = keys[:0] 2004 } 2005 } 2006 2007 func writePEMsToTempFile(certs []*Certificate) *os.File { 2008 file, err := ioutil.TempFile("", "name_constraints_test") 2009 if err != nil { 2010 panic("cannot create tempfile") 2011 } 2012 2013 pemBlock := &pem.Block{Type: "CERTIFICATE"} 2014 for _, cert := range certs { 2015 pemBlock.Bytes = cert.Raw 2016 pem.Encode(file, pemBlock) 2017 } 2018 2019 return file 2020 } 2021 2022 func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool) (string, error) { 2023 args := []string{"verify", "-no_check_time"} 2024 2025 rootsFile := writePEMsToTempFile(roots.certs) 2026 if debugOpenSSLFailure { 2027 println("roots file:", rootsFile.Name()) 2028 } else { 2029 defer os.Remove(rootsFile.Name()) 2030 } 2031 args = append(args, "-CAfile", rootsFile.Name()) 2032 2033 if len(intermediates.certs) > 0 { 2034 intermediatesFile := writePEMsToTempFile(intermediates.certs) 2035 if debugOpenSSLFailure { 2036 println("intermediates file:", intermediatesFile.Name()) 2037 } else { 2038 defer os.Remove(intermediatesFile.Name()) 2039 } 2040 args = append(args, "-untrusted", intermediatesFile.Name()) 2041 } 2042 2043 leafFile := writePEMsToTempFile([]*Certificate{leaf}) 2044 if debugOpenSSLFailure { 2045 println("leaf file:", leafFile.Name()) 2046 } else { 2047 defer os.Remove(leafFile.Name()) 2048 } 2049 args = append(args, leafFile.Name()) 2050 2051 var output bytes.Buffer 2052 cmd := exec.Command("openssl", args...) 2053 cmd.Stdout = &output 2054 cmd.Stderr = &output 2055 2056 err := cmd.Run() 2057 return output.String(), err 2058 } 2059 2060 var rfc2821Tests = []struct { 2061 in string 2062 localPart, domain string 2063 }{ 2064 {"foo@example.com", "foo", "example.com"}, 2065 {"@example.com", "", ""}, 2066 {"\"@example.com", "", ""}, 2067 {"\"\"@example.com", "", "example.com"}, 2068 {"\"a\"@example.com", "a", "example.com"}, 2069 {"\"\\a\"@example.com", "a", "example.com"}, 2070 {"a\"@example.com", "", ""}, 2071 {"foo..bar@example.com", "", ""}, 2072 {".foo.bar@example.com", "", ""}, 2073 {"foo.bar.@example.com", "", ""}, 2074 {"|{}?'@example.com", "|{}?'", "example.com"}, 2075 2076 // Examples from RFC 3696 2077 {"Abc\\@def@example.com", "Abc@def", "example.com"}, 2078 {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"}, 2079 {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"}, 2080 {"\"Abc@def\"@example.com", "Abc@def", "example.com"}, 2081 {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"}, 2082 {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"}, 2083 {"$A12345@example.com", "$A12345", "example.com"}, 2084 {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"}, 2085 {"_somename@example.com", "_somename", "example.com"}, 2086 } 2087 2088 func TestRFC2821Parsing(t *testing.T) { 2089 for i, test := range rfc2821Tests { 2090 mailbox, ok := parseRFC2821Mailbox(test.in) 2091 expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0 2092 2093 if ok && expectedFailure { 2094 t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain) 2095 continue 2096 } 2097 2098 if !ok && !expectedFailure { 2099 t.Errorf("#%d: unexpected failure for %q", i, test.in) 2100 continue 2101 } 2102 2103 if !ok { 2104 continue 2105 } 2106 2107 if mailbox.local != test.localPart || mailbox.domain != test.domain { 2108 t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain) 2109 } 2110 } 2111 } 2112 2113 func TestBadNamesInConstraints(t *testing.T) { 2114 constraintParseError := func(err error) bool { 2115 str := err.Error() 2116 return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint") 2117 } 2118 2119 encodingError := func(err error) bool { 2120 return strings.Contains(err.Error(), "cannot be encoded as an IA5String") 2121 } 2122 2123 // Bad names in constraints should not parse. 2124 badNames := []struct { 2125 name string 2126 matcher func(error) bool 2127 }{ 2128 {"dns:foo.com.", constraintParseError}, 2129 {"email:abc@foo.com.", constraintParseError}, 2130 {"email:foo.com.", constraintParseError}, 2131 {"uri:example.com.", constraintParseError}, 2132 {"uri:1.2.3.4", constraintParseError}, 2133 {"uri:ffff::1", constraintParseError}, 2134 {"dns:not–hyphen.com", encodingError}, 2135 {"email:foo@not–hyphen.com", encodingError}, 2136 {"uri:not–hyphen.com", encodingError}, 2137 } 2138 2139 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2140 if err != nil { 2141 panic(err) 2142 } 2143 2144 for _, test := range badNames { 2145 _, err := makeConstraintsCACert(constraintsSpec{ 2146 ok: []string{test.name}, 2147 }, "TestAbsoluteNamesInConstraints", priv, nil, priv) 2148 2149 if err == nil { 2150 t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name) 2151 continue 2152 } else { 2153 if !test.matcher(err) { 2154 t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err) 2155 } 2156 } 2157 } 2158 } 2159 2160 func TestBadNamesInSANs(t *testing.T) { 2161 // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs 2162 // will parse and are tested in name constraint tests at the top of this 2163 // file. 2164 badNames := []string{ 2165 "uri:https://example.com./dsf", 2166 "invalidip:0102", 2167 "invalidip:0102030405", 2168 } 2169 2170 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2171 if err != nil { 2172 panic(err) 2173 } 2174 2175 for _, badName := range badNames { 2176 _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv) 2177 2178 if err == nil { 2179 t.Errorf("bad name %q unexpectedly accepted in SAN", badName) 2180 continue 2181 } 2182 2183 if str := err.Error(); !strings.Contains(str, "cannot parse ") { 2184 t.Errorf("bad name %q triggered unrecognised error: %s", badName, str) 2185 } 2186 } 2187 }