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