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