PR c++/86342 - -Wdeprecated-copy and system headers.
[official-gcc.git] / libgo / go / crypto / x509 / name_constraints_test.go
blob95d55fd7619b4f5ab3310b4fcfbd40e8e4179037
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.
5 package x509
7 import (
8 "bytes"
9 "crypto/ecdsa"
10 "crypto/elliptic"
11 "crypto/rand"
12 "crypto/x509/pkix"
13 "encoding/asn1"
14 "encoding/hex"
15 "encoding/pem"
16 "fmt"
17 "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"
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
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
42 type nameConstraintsTest struct {
43 roots []constraintsSpec
44 intermediates [][]constraintsSpec
45 leaf leafSpec
46 requestedEKUs []ExtKeyUsage
47 expectedError string
48 noOpenSSL bool
51 type constraintsSpec struct {
52 ok []string
53 bad []string
54 ekus []string
57 type leafSpec struct {
58 sans []string
59 ekus []string
62 var nameConstraintsTests = []nameConstraintsTest{
63 // #0: dummy test for the certificate generation process itself.
64 nameConstraintsTest{
65 roots: []constraintsSpec{
66 constraintsSpec{},
68 leaf: leafSpec{
69 sans: []string{"dns:example.com"},
73 // #1: dummy test for the certificate generation process itself: single
74 // level of intermediate.
75 nameConstraintsTest{
76 roots: []constraintsSpec{
77 constraintsSpec{},
79 intermediates: [][]constraintsSpec{
80 []constraintsSpec{
81 constraintsSpec{},
84 leaf: leafSpec{
85 sans: []string{"dns:example.com"},
89 // #2: dummy test for the certificate generation process itself: two
90 // levels of intermediates.
91 nameConstraintsTest{
92 roots: []constraintsSpec{
93 constraintsSpec{},
95 intermediates: [][]constraintsSpec{
96 []constraintsSpec{
97 constraintsSpec{},
99 []constraintsSpec{
100 constraintsSpec{},
103 leaf: leafSpec{
104 sans: []string{"dns:example.com"},
108 // #3: matching DNS constraint in root
109 nameConstraintsTest{
110 roots: []constraintsSpec{
111 constraintsSpec{
112 ok: []string{"dns:example.com"},
115 intermediates: [][]constraintsSpec{
116 []constraintsSpec{
117 constraintsSpec{},
120 leaf: leafSpec{
121 sans: []string{"dns:example.com"},
125 // #4: matching DNS constraint in intermediate.
126 nameConstraintsTest{
127 roots: []constraintsSpec{
128 constraintsSpec{},
130 intermediates: [][]constraintsSpec{
131 []constraintsSpec{
132 constraintsSpec{
133 ok: []string{"dns:example.com"},
137 leaf: leafSpec{
138 sans: []string{"dns:example.com"},
142 // #5: .example.com only matches subdomains.
143 nameConstraintsTest{
144 roots: []constraintsSpec{
145 constraintsSpec{
146 ok: []string{"dns:.example.com"},
149 intermediates: [][]constraintsSpec{
150 []constraintsSpec{
151 constraintsSpec{},
154 leaf: leafSpec{
155 sans: []string{"dns:example.com"},
157 expectedError: "\"example.com\" is not permitted",
160 // #6: .example.com matches subdomains.
161 nameConstraintsTest{
162 roots: []constraintsSpec{
163 constraintsSpec{},
165 intermediates: [][]constraintsSpec{
166 []constraintsSpec{
167 constraintsSpec{
168 ok: []string{"dns:.example.com"},
172 leaf: leafSpec{
173 sans: []string{"dns:foo.example.com"},
177 // #7: .example.com matches multiple levels of subdomains
178 nameConstraintsTest{
179 roots: []constraintsSpec{
180 constraintsSpec{
181 ok: []string{"dns:.example.com"},
184 intermediates: [][]constraintsSpec{
185 []constraintsSpec{
186 constraintsSpec{},
189 leaf: leafSpec{
190 sans: []string{"dns:foo.bar.example.com"},
194 // #8: specifying a permitted list of names does not exclude other name
195 // types
196 nameConstraintsTest{
197 roots: []constraintsSpec{
198 constraintsSpec{
199 ok: []string{"dns:.example.com"},
202 intermediates: [][]constraintsSpec{
203 []constraintsSpec{
204 constraintsSpec{},
207 leaf: leafSpec{
208 sans: []string{"ip:10.1.1.1"},
212 // #9: specifying a permitted list of names does not exclude other name
213 // types
214 nameConstraintsTest{
215 roots: []constraintsSpec{
216 constraintsSpec{
217 ok: []string{"ip:10.0.0.0/8"},
220 intermediates: [][]constraintsSpec{
221 []constraintsSpec{
222 constraintsSpec{},
225 leaf: leafSpec{
226 sans: []string{"dns:example.com"},
230 // #10: intermediates can try to permit other names, which isn't
231 // forbidden if the leaf doesn't mention them. I.e. name constraints
232 // apply to names, not constraints themselves.
233 nameConstraintsTest{
234 roots: []constraintsSpec{
235 constraintsSpec{
236 ok: []string{"dns:example.com"},
239 intermediates: [][]constraintsSpec{
240 []constraintsSpec{
241 constraintsSpec{
242 ok: []string{"dns:example.com", "dns:foo.com"},
246 leaf: leafSpec{
247 sans: []string{"dns:example.com"},
251 // #11: intermediates cannot add permitted names that the root doesn't
252 // grant them.
253 nameConstraintsTest{
254 roots: []constraintsSpec{
255 constraintsSpec{
256 ok: []string{"dns:example.com"},
259 intermediates: [][]constraintsSpec{
260 []constraintsSpec{
261 constraintsSpec{
262 ok: []string{"dns:example.com", "dns:foo.com"},
266 leaf: leafSpec{
267 sans: []string{"dns:foo.com"},
269 expectedError: "\"foo.com\" is not permitted",
272 // #12: intermediates can further limit their scope if they wish.
273 nameConstraintsTest{
274 roots: []constraintsSpec{
275 constraintsSpec{
276 ok: []string{"dns:.example.com"},
279 intermediates: [][]constraintsSpec{
280 []constraintsSpec{
281 constraintsSpec{
282 ok: []string{"dns:.bar.example.com"},
286 leaf: leafSpec{
287 sans: []string{"dns:foo.bar.example.com"},
291 // #13: intermediates can further limit their scope and that limitation
292 // is effective
293 nameConstraintsTest{
294 roots: []constraintsSpec{
295 constraintsSpec{
296 ok: []string{"dns:.example.com"},
299 intermediates: [][]constraintsSpec{
300 []constraintsSpec{
301 constraintsSpec{
302 ok: []string{"dns:.bar.example.com"},
306 leaf: leafSpec{
307 sans: []string{"dns:foo.notbar.example.com"},
309 expectedError: "\"foo.notbar.example.com\" is not permitted",
312 // #14: roots can exclude subtrees and that doesn't affect other names.
313 nameConstraintsTest{
314 roots: []constraintsSpec{
315 constraintsSpec{
316 bad: []string{"dns:.example.com"},
319 intermediates: [][]constraintsSpec{
320 []constraintsSpec{
321 constraintsSpec{},
324 leaf: leafSpec{
325 sans: []string{"dns:foo.com"},
329 // #15: roots exclusions are effective.
330 nameConstraintsTest{
331 roots: []constraintsSpec{
332 constraintsSpec{
333 bad: []string{"dns:.example.com"},
336 intermediates: [][]constraintsSpec{
337 []constraintsSpec{
338 constraintsSpec{},
341 leaf: leafSpec{
342 sans: []string{"dns:foo.example.com"},
344 expectedError: "\"foo.example.com\" is excluded",
347 // #16: intermediates can also exclude names and that doesn't affect
348 // other names.
349 nameConstraintsTest{
350 roots: []constraintsSpec{
351 constraintsSpec{},
353 intermediates: [][]constraintsSpec{
354 []constraintsSpec{
355 constraintsSpec{
356 bad: []string{"dns:.example.com"},
360 leaf: leafSpec{
361 sans: []string{"dns:foo.com"},
365 // #17: intermediate exclusions are effective.
366 nameConstraintsTest{
367 roots: []constraintsSpec{
368 constraintsSpec{},
370 intermediates: [][]constraintsSpec{
371 []constraintsSpec{
372 constraintsSpec{
373 bad: []string{"dns:.example.com"},
377 leaf: leafSpec{
378 sans: []string{"dns:foo.example.com"},
380 expectedError: "\"foo.example.com\" is excluded",
383 // #18: having an exclusion doesn't prohibit other types of names.
384 nameConstraintsTest{
385 roots: []constraintsSpec{
386 constraintsSpec{
387 bad: []string{"dns:.example.com"},
390 intermediates: [][]constraintsSpec{
391 []constraintsSpec{
392 constraintsSpec{},
395 leaf: leafSpec{
396 sans: []string{"dns:foo.com", "ip:10.1.1.1"},
400 // #19: IP-based exclusions are permitted and don't affect unrelated IP
401 // addresses.
402 nameConstraintsTest{
403 roots: []constraintsSpec{
404 constraintsSpec{
405 bad: []string{"ip:10.0.0.0/8"},
408 intermediates: [][]constraintsSpec{
409 []constraintsSpec{
410 constraintsSpec{},
413 leaf: leafSpec{
414 sans: []string{"ip:192.168.1.1"},
418 // #20: IP-based exclusions are effective
419 nameConstraintsTest{
420 roots: []constraintsSpec{
421 constraintsSpec{
422 bad: []string{"ip:10.0.0.0/8"},
425 intermediates: [][]constraintsSpec{
426 []constraintsSpec{
427 constraintsSpec{},
430 leaf: leafSpec{
431 sans: []string{"ip:10.0.0.1"},
433 expectedError: "\"10.0.0.1\" is excluded",
436 // #21: intermediates can further constrain IP ranges.
437 nameConstraintsTest{
438 roots: []constraintsSpec{
439 constraintsSpec{
440 bad: []string{"ip:0.0.0.0/1"},
443 intermediates: [][]constraintsSpec{
444 []constraintsSpec{
445 constraintsSpec{
446 bad: []string{"ip:11.0.0.0/8"},
450 leaf: leafSpec{
451 sans: []string{"ip:11.0.0.1"},
453 expectedError: "\"11.0.0.1\" is excluded",
456 // #22: when multiple intermediates are present, chain building can
457 // avoid intermediates with incompatible constraints.
458 nameConstraintsTest{
459 roots: []constraintsSpec{
460 constraintsSpec{},
462 intermediates: [][]constraintsSpec{
463 []constraintsSpec{
464 constraintsSpec{
465 ok: []string{"dns:.foo.com"},
467 constraintsSpec{
468 ok: []string{"dns:.example.com"},
472 leaf: leafSpec{
473 sans: []string{"dns:foo.example.com"},
475 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
478 // #23: (same as the previous test, but in the other order in ensure
479 // that we don't pass it by luck.)
480 nameConstraintsTest{
481 roots: []constraintsSpec{
482 constraintsSpec{},
484 intermediates: [][]constraintsSpec{
485 []constraintsSpec{
486 constraintsSpec{
487 ok: []string{"dns:.example.com"},
489 constraintsSpec{
490 ok: []string{"dns:.foo.com"},
494 leaf: leafSpec{
495 sans: []string{"dns:foo.example.com"},
497 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
500 // #24: when multiple roots are valid, chain building can avoid roots
501 // with incompatible constraints.
502 nameConstraintsTest{
503 roots: []constraintsSpec{
504 constraintsSpec{},
505 constraintsSpec{
506 ok: []string{"dns:foo.com"},
509 intermediates: [][]constraintsSpec{
510 []constraintsSpec{
511 constraintsSpec{},
514 leaf: leafSpec{
515 sans: []string{"dns:example.com"},
517 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
520 // #25: (same as the previous test, but in the other order in ensure
521 // that we don't pass it by luck.)
522 nameConstraintsTest{
523 roots: []constraintsSpec{
524 constraintsSpec{
525 ok: []string{"dns:foo.com"},
527 constraintsSpec{},
529 intermediates: [][]constraintsSpec{
530 []constraintsSpec{
531 constraintsSpec{},
534 leaf: leafSpec{
535 sans: []string{"dns:example.com"},
537 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
540 // #26: chain building can find a valid path even with multiple levels
541 // of alternative intermediates and alternative roots.
542 nameConstraintsTest{
543 roots: []constraintsSpec{
544 constraintsSpec{
545 ok: []string{"dns:foo.com"},
547 constraintsSpec{
548 ok: []string{"dns:example.com"},
550 constraintsSpec{},
552 intermediates: [][]constraintsSpec{
553 []constraintsSpec{
554 constraintsSpec{},
555 constraintsSpec{
556 ok: []string{"dns:foo.com"},
559 []constraintsSpec{
560 constraintsSpec{},
561 constraintsSpec{
562 ok: []string{"dns:foo.com"},
566 leaf: leafSpec{
567 sans: []string{"dns:bar.com"},
569 noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
572 // #27: chain building doesn't get stuck when there is no valid path.
573 nameConstraintsTest{
574 roots: []constraintsSpec{
575 constraintsSpec{
576 ok: []string{"dns:foo.com"},
578 constraintsSpec{
579 ok: []string{"dns:example.com"},
582 intermediates: [][]constraintsSpec{
583 []constraintsSpec{
584 constraintsSpec{},
585 constraintsSpec{
586 ok: []string{"dns:foo.com"},
589 []constraintsSpec{
590 constraintsSpec{
591 ok: []string{"dns:bar.com"},
593 constraintsSpec{
594 ok: []string{"dns:foo.com"},
598 leaf: leafSpec{
599 sans: []string{"dns:bar.com"},
601 expectedError: "\"bar.com\" is not permitted",
604 // #28: unknown name types don't cause a problem without constraints.
605 nameConstraintsTest{
606 roots: []constraintsSpec{
607 constraintsSpec{},
609 intermediates: [][]constraintsSpec{
610 []constraintsSpec{
611 constraintsSpec{},
614 leaf: leafSpec{
615 sans: []string{"unknown:"},
619 // #29: unknown name types are allowed even in constrained chains.
620 nameConstraintsTest{
621 roots: []constraintsSpec{
622 constraintsSpec{
623 ok: []string{"dns:foo.com", "dns:.foo.com"},
626 intermediates: [][]constraintsSpec{
627 []constraintsSpec{
628 constraintsSpec{},
631 leaf: leafSpec{
632 sans: []string{"unknown:"},
636 // #30: without SANs, a certificate is rejected in a constrained chain.
637 nameConstraintsTest{
638 roots: []constraintsSpec{
639 constraintsSpec{
640 ok: []string{"dns:foo.com", "dns:.foo.com"},
643 intermediates: [][]constraintsSpec{
644 []constraintsSpec{
645 constraintsSpec{},
648 leaf: leafSpec{
649 sans: []string{},
651 expectedError: "leaf doesn't have a SAN extension",
652 noOpenSSL: true, // OpenSSL doesn't require SANs in this case.
655 // #31: IPv6 addresses work in constraints: roots can permit them as
656 // expected.
657 nameConstraintsTest{
658 roots: []constraintsSpec{
659 constraintsSpec{
660 ok: []string{"ip:2000:abcd::/32"},
663 intermediates: [][]constraintsSpec{
664 []constraintsSpec{
665 constraintsSpec{},
668 leaf: leafSpec{
669 sans: []string{"ip:2000:abcd:1234::"},
673 // #32: IPv6 addresses work in constraints: root restrictions are
674 // effective.
675 nameConstraintsTest{
676 roots: []constraintsSpec{
677 constraintsSpec{
678 ok: []string{"ip:2000:abcd::/32"},
681 intermediates: [][]constraintsSpec{
682 []constraintsSpec{
683 constraintsSpec{},
686 leaf: leafSpec{
687 sans: []string{"ip:2000:1234:abcd::"},
689 expectedError: "\"2000:1234:abcd::\" is not permitted",
692 // #33: An IPv6 permitted subtree doesn't affect DNS names.
693 nameConstraintsTest{
694 roots: []constraintsSpec{
695 constraintsSpec{
696 ok: []string{"ip:2000:abcd::/32"},
699 intermediates: [][]constraintsSpec{
700 []constraintsSpec{
701 constraintsSpec{},
704 leaf: leafSpec{
705 sans: []string{"ip:2000:abcd::", "dns:foo.com"},
709 // #34: IPv6 exclusions don't affect unrelated addresses.
710 nameConstraintsTest{
711 roots: []constraintsSpec{
712 constraintsSpec{
713 bad: []string{"ip:2000:abcd::/32"},
716 intermediates: [][]constraintsSpec{
717 []constraintsSpec{
718 constraintsSpec{},
721 leaf: leafSpec{
722 sans: []string{"ip:2000:1234::"},
726 // #35: IPv6 exclusions are effective.
727 nameConstraintsTest{
728 roots: []constraintsSpec{
729 constraintsSpec{
730 bad: []string{"ip:2000:abcd::/32"},
733 intermediates: [][]constraintsSpec{
734 []constraintsSpec{
735 constraintsSpec{},
738 leaf: leafSpec{
739 sans: []string{"ip:2000:abcd::"},
741 expectedError: "\"2000:abcd::\" is excluded",
744 // #36: IPv6 constraints do not permit IPv4 addresses.
745 nameConstraintsTest{
746 roots: []constraintsSpec{
747 constraintsSpec{
748 ok: []string{"ip:2000:abcd::/32"},
751 intermediates: [][]constraintsSpec{
752 []constraintsSpec{
753 constraintsSpec{},
756 leaf: leafSpec{
757 sans: []string{"ip:10.0.0.1"},
759 expectedError: "\"10.0.0.1\" is not permitted",
762 // #37: IPv4 constraints do not permit IPv6 addresses.
763 nameConstraintsTest{
764 roots: []constraintsSpec{
765 constraintsSpec{
766 ok: []string{"ip:10.0.0.0/8"},
769 intermediates: [][]constraintsSpec{
770 []constraintsSpec{
771 constraintsSpec{},
774 leaf: leafSpec{
775 sans: []string{"ip:2000:abcd::"},
777 expectedError: "\"2000:abcd::\" is not permitted",
780 // #38: an exclusion of an unknown type doesn't affect other names.
781 nameConstraintsTest{
782 roots: []constraintsSpec{
783 constraintsSpec{
784 bad: []string{"unknown:"},
787 intermediates: [][]constraintsSpec{
788 []constraintsSpec{
789 constraintsSpec{},
792 leaf: leafSpec{
793 sans: []string{"dns:example.com"},
797 // #39: a permitted subtree of an unknown type doesn't affect other
798 // name types.
799 nameConstraintsTest{
800 roots: []constraintsSpec{
801 constraintsSpec{
802 ok: []string{"unknown:"},
805 intermediates: [][]constraintsSpec{
806 []constraintsSpec{
807 constraintsSpec{},
810 leaf: leafSpec{
811 sans: []string{"dns:example.com"},
815 // #40: exact email constraints work
816 nameConstraintsTest{
817 roots: []constraintsSpec{
818 constraintsSpec{
819 ok: []string{"email:foo@example.com"},
822 intermediates: [][]constraintsSpec{
823 []constraintsSpec{
824 constraintsSpec{},
827 leaf: leafSpec{
828 sans: []string{"email:foo@example.com"},
832 // #41: exact email constraints are effective
833 nameConstraintsTest{
834 roots: []constraintsSpec{
835 constraintsSpec{
836 ok: []string{"email:foo@example.com"},
839 intermediates: [][]constraintsSpec{
840 []constraintsSpec{
841 constraintsSpec{},
844 leaf: leafSpec{
845 sans: []string{"email:bar@example.com"},
847 expectedError: "\"bar@example.com\" is not permitted",
850 // #42: email canonicalisation works.
851 nameConstraintsTest{
852 roots: []constraintsSpec{
853 constraintsSpec{
854 ok: []string{"email:foo@example.com"},
857 intermediates: [][]constraintsSpec{
858 []constraintsSpec{
859 constraintsSpec{},
862 leaf: leafSpec{
863 sans: []string{"email:\"\\f\\o\\o\"@example.com"},
865 noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching
868 // #43: limiting email addresses to a host works.
869 nameConstraintsTest{
870 roots: []constraintsSpec{
871 constraintsSpec{
872 ok: []string{"email:example.com"},
875 intermediates: [][]constraintsSpec{
876 []constraintsSpec{
877 constraintsSpec{},
880 leaf: leafSpec{
881 sans: []string{"email:foo@example.com"},
885 // #44: a leading dot matches hosts one level deep
886 nameConstraintsTest{
887 roots: []constraintsSpec{
888 constraintsSpec{
889 ok: []string{"email:.example.com"},
892 intermediates: [][]constraintsSpec{
893 []constraintsSpec{
894 constraintsSpec{},
897 leaf: leafSpec{
898 sans: []string{"email:foo@sub.example.com"},
902 // #45: a leading dot does not match the host itself
903 nameConstraintsTest{
904 roots: []constraintsSpec{
905 constraintsSpec{
906 ok: []string{"email:.example.com"},
909 intermediates: [][]constraintsSpec{
910 []constraintsSpec{
911 constraintsSpec{},
914 leaf: leafSpec{
915 sans: []string{"email:foo@example.com"},
917 expectedError: "\"foo@example.com\" is not permitted",
920 // #46: a leading dot also matches two (or more) levels deep.
921 nameConstraintsTest{
922 roots: []constraintsSpec{
923 constraintsSpec{
924 ok: []string{"email:.example.com"},
927 intermediates: [][]constraintsSpec{
928 []constraintsSpec{
929 constraintsSpec{},
932 leaf: leafSpec{
933 sans: []string{"email:foo@sub.sub.example.com"},
937 // #47: the local part of an email is case-sensitive
938 nameConstraintsTest{
939 roots: []constraintsSpec{
940 constraintsSpec{
941 ok: []string{"email:foo@example.com"},
944 intermediates: [][]constraintsSpec{
945 []constraintsSpec{
946 constraintsSpec{},
949 leaf: leafSpec{
950 sans: []string{"email:Foo@example.com"},
952 expectedError: "\"Foo@example.com\" is not permitted",
955 // #48: the domain part of an email is not case-sensitive
956 nameConstraintsTest{
957 roots: []constraintsSpec{
958 constraintsSpec{
959 ok: []string{"email:foo@EXAMPLE.com"},
962 intermediates: [][]constraintsSpec{
963 []constraintsSpec{
964 constraintsSpec{},
967 leaf: leafSpec{
968 sans: []string{"email:foo@example.com"},
972 // #49: the domain part of a DNS constraint is also not case-sensitive.
973 nameConstraintsTest{
974 roots: []constraintsSpec{
975 constraintsSpec{
976 ok: []string{"dns:EXAMPLE.com"},
979 intermediates: [][]constraintsSpec{
980 []constraintsSpec{
981 constraintsSpec{},
984 leaf: leafSpec{
985 sans: []string{"dns:example.com"},
989 // #50: URI constraints only cover the host part of the URI
990 nameConstraintsTest{
991 roots: []constraintsSpec{
992 constraintsSpec{
993 ok: []string{"uri:example.com"},
996 intermediates: [][]constraintsSpec{
997 []constraintsSpec{
998 constraintsSpec{},
1001 leaf: leafSpec{
1002 sans: []string{
1003 "uri:http://example.com/bar",
1004 "uri:http://example.com:8080/",
1005 "uri:https://example.com/wibble#bar",
1010 // #51: URIs with IPs are rejected
1011 nameConstraintsTest{
1012 roots: []constraintsSpec{
1013 constraintsSpec{
1014 ok: []string{"uri:example.com"},
1017 intermediates: [][]constraintsSpec{
1018 []constraintsSpec{
1019 constraintsSpec{},
1022 leaf: leafSpec{
1023 sans: []string{"uri:http://1.2.3.4/"},
1025 expectedError: "URI with IP",
1028 // #52: URIs with IPs and ports are rejected
1029 nameConstraintsTest{
1030 roots: []constraintsSpec{
1031 constraintsSpec{
1032 ok: []string{"uri:example.com"},
1035 intermediates: [][]constraintsSpec{
1036 []constraintsSpec{
1037 constraintsSpec{},
1040 leaf: leafSpec{
1041 sans: []string{"uri:http://1.2.3.4:43/"},
1043 expectedError: "URI with IP",
1046 // #53: URIs with IPv6 addresses are also rejected
1047 nameConstraintsTest{
1048 roots: []constraintsSpec{
1049 constraintsSpec{
1050 ok: []string{"uri:example.com"},
1053 intermediates: [][]constraintsSpec{
1054 []constraintsSpec{
1055 constraintsSpec{},
1058 leaf: leafSpec{
1059 sans: []string{"uri:http://[2006:abcd::1]/"},
1061 expectedError: "URI with IP",
1064 // #54: URIs with IPv6 addresses with ports are also rejected
1065 nameConstraintsTest{
1066 roots: []constraintsSpec{
1067 constraintsSpec{
1068 ok: []string{"uri:example.com"},
1071 intermediates: [][]constraintsSpec{
1072 []constraintsSpec{
1073 constraintsSpec{},
1076 leaf: leafSpec{
1077 sans: []string{"uri:http://[2006:abcd::1]:16/"},
1079 expectedError: "URI with IP",
1082 // #55: URI constraints are effective
1083 nameConstraintsTest{
1084 roots: []constraintsSpec{
1085 constraintsSpec{
1086 ok: []string{"uri:example.com"},
1089 intermediates: [][]constraintsSpec{
1090 []constraintsSpec{
1091 constraintsSpec{},
1094 leaf: leafSpec{
1095 sans: []string{"uri:http://bar.com/"},
1097 expectedError: "\"http://bar.com/\" is not permitted",
1100 // #56: URI constraints are effective
1101 nameConstraintsTest{
1102 roots: []constraintsSpec{
1103 constraintsSpec{
1104 bad: []string{"uri:foo.com"},
1107 intermediates: [][]constraintsSpec{
1108 []constraintsSpec{
1109 constraintsSpec{},
1112 leaf: leafSpec{
1113 sans: []string{"uri:http://foo.com/"},
1115 expectedError: "\"http://foo.com/\" is excluded",
1118 // #57: URI constraints can allow subdomains
1119 nameConstraintsTest{
1120 roots: []constraintsSpec{
1121 constraintsSpec{
1122 ok: []string{"uri:.foo.com"},
1125 intermediates: [][]constraintsSpec{
1126 []constraintsSpec{
1127 constraintsSpec{},
1130 leaf: leafSpec{
1131 sans: []string{"uri:http://www.foo.com/"},
1135 // #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4
1136 // version of that address.
1137 nameConstraintsTest{
1138 roots: []constraintsSpec{
1139 constraintsSpec{
1140 bad: []string{"ip:::ffff:1.2.3.4/128"},
1143 intermediates: [][]constraintsSpec{
1144 []constraintsSpec{
1145 constraintsSpec{},
1148 leaf: leafSpec{
1149 sans: []string{"ip:1.2.3.4"},
1153 // #59: a URI constraint isn't matched by a URN.
1154 nameConstraintsTest{
1155 roots: []constraintsSpec{
1156 constraintsSpec{
1157 ok: []string{"uri:example.com"},
1160 intermediates: [][]constraintsSpec{
1161 []constraintsSpec{
1162 constraintsSpec{},
1165 leaf: leafSpec{
1166 sans: []string{"uri:urn:example"},
1168 expectedError: "URI with empty host",
1171 // #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses
1172 // too, even though IPv4 is mapped into the IPv6 range.
1173 nameConstraintsTest{
1174 roots: []constraintsSpec{
1175 constraintsSpec{
1176 ok: []string{"ip:1.2.3.0/24"},
1177 bad: []string{"ip:::0/0"},
1180 intermediates: [][]constraintsSpec{
1181 []constraintsSpec{
1182 constraintsSpec{},
1185 leaf: leafSpec{
1186 sans: []string{"ip:1.2.3.4"},
1190 // #61: omitting extended key usage in a CA certificate implies that
1191 // any usage is ok.
1192 nameConstraintsTest{
1193 roots: []constraintsSpec{
1194 constraintsSpec{},
1196 intermediates: [][]constraintsSpec{
1197 []constraintsSpec{
1198 constraintsSpec{},
1201 leaf: leafSpec{
1202 sans: []string{"dns:example.com"},
1203 ekus: []string{"serverAuth", "other"},
1207 // #62: The “any” EKU also means that any usage is ok.
1208 nameConstraintsTest{
1209 roots: []constraintsSpec{
1210 constraintsSpec{},
1212 intermediates: [][]constraintsSpec{
1213 []constraintsSpec{
1214 constraintsSpec{
1215 ekus: []string{"any"},
1219 leaf: leafSpec{
1220 sans: []string{"dns:example.com"},
1221 ekus: []string{"serverAuth", "other"},
1225 // #63: An intermediate with enumerated EKUs causes a failure if we
1226 // test for an EKU not in that set. (ServerAuth is required by
1227 // default.)
1228 nameConstraintsTest{
1229 roots: []constraintsSpec{
1230 constraintsSpec{},
1232 intermediates: [][]constraintsSpec{
1233 []constraintsSpec{
1234 constraintsSpec{
1235 ekus: []string{"email"},
1239 leaf: leafSpec{
1240 sans: []string{"dns:example.com"},
1241 ekus: []string{"serverAuth"},
1243 expectedError: "incompatible key usage",
1246 // #64: an unknown EKU in the leaf doesn't break anything, even if it's not
1247 // correctly nested.
1248 nameConstraintsTest{
1249 roots: []constraintsSpec{
1250 constraintsSpec{},
1252 intermediates: [][]constraintsSpec{
1253 []constraintsSpec{
1254 constraintsSpec{
1255 ekus: []string{"email"},
1259 leaf: leafSpec{
1260 sans: []string{"dns:example.com"},
1261 ekus: []string{"other"},
1263 requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
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"},
1275 intermediates: [][]constraintsSpec{
1276 []constraintsSpec{
1277 constraintsSpec{
1278 ekus: []string{"serverAuth", "email"},
1282 leaf: leafSpec{
1283 sans: []string{"dns:example.com"},
1284 ekus: []string{"serverAuth"},
1288 // #66: EKUs in roots are not ignored.
1289 nameConstraintsTest{
1290 roots: []constraintsSpec{
1291 constraintsSpec{
1292 ekus: []string{"email"},
1295 intermediates: [][]constraintsSpec{
1296 []constraintsSpec{
1297 constraintsSpec{
1298 ekus: []string{"serverAuth"},
1302 leaf: leafSpec{
1303 sans: []string{"dns:example.com"},
1304 ekus: []string{"serverAuth"},
1306 expectedError: "incompatible key usage",
1309 // #67: in order to support COMODO chains, SGC key usages permit
1310 // serverAuth and clientAuth.
1311 nameConstraintsTest{
1312 roots: []constraintsSpec{
1313 constraintsSpec{},
1315 intermediates: [][]constraintsSpec{
1316 []constraintsSpec{
1317 constraintsSpec{
1318 ekus: []string{"netscapeSGC"},
1322 leaf: leafSpec{
1323 sans: []string{"dns:example.com"},
1324 ekus: []string{"serverAuth", "clientAuth"},
1328 // #68: in order to support COMODO chains, SGC key usages permit
1329 // serverAuth and clientAuth.
1330 nameConstraintsTest{
1331 roots: []constraintsSpec{
1332 constraintsSpec{},
1334 intermediates: [][]constraintsSpec{
1335 []constraintsSpec{
1336 constraintsSpec{
1337 ekus: []string{"msSGC"},
1341 leaf: leafSpec{
1342 sans: []string{"dns:example.com"},
1343 ekus: []string{"serverAuth", "clientAuth"},
1347 // #69: an empty DNS constraint should allow anything.
1348 nameConstraintsTest{
1349 roots: []constraintsSpec{
1350 constraintsSpec{
1351 ok: []string{"dns:"},
1354 intermediates: [][]constraintsSpec{
1355 []constraintsSpec{
1356 constraintsSpec{},
1359 leaf: leafSpec{
1360 sans: []string{"dns:example.com"},
1364 // #70: an empty DNS constraint should also reject everything.
1365 nameConstraintsTest{
1366 roots: []constraintsSpec{
1367 constraintsSpec{
1368 bad: []string{"dns:"},
1371 intermediates: [][]constraintsSpec{
1372 []constraintsSpec{
1373 constraintsSpec{},
1376 leaf: leafSpec{
1377 sans: []string{"dns:example.com"},
1379 expectedError: "\"example.com\" is excluded",
1382 // #71: an empty email constraint should allow anything
1383 nameConstraintsTest{
1384 roots: []constraintsSpec{
1385 constraintsSpec{
1386 ok: []string{"email:"},
1389 intermediates: [][]constraintsSpec{
1390 []constraintsSpec{
1391 constraintsSpec{},
1394 leaf: leafSpec{
1395 sans: []string{"email:foo@example.com"},
1399 // #72: an empty email constraint should also reject everything.
1400 nameConstraintsTest{
1401 roots: []constraintsSpec{
1402 constraintsSpec{
1403 bad: []string{"email:"},
1406 intermediates: [][]constraintsSpec{
1407 []constraintsSpec{
1408 constraintsSpec{},
1411 leaf: leafSpec{
1412 sans: []string{"email:foo@example.com"},
1414 expectedError: "\"foo@example.com\" is excluded",
1417 // #73: an empty URI constraint should allow anything
1418 nameConstraintsTest{
1419 roots: []constraintsSpec{
1420 constraintsSpec{
1421 ok: []string{"uri:"},
1424 intermediates: [][]constraintsSpec{
1425 []constraintsSpec{
1426 constraintsSpec{},
1429 leaf: leafSpec{
1430 sans: []string{"uri:https://example.com/test"},
1434 // #74: an empty URI constraint should also reject everything.
1435 nameConstraintsTest{
1436 roots: []constraintsSpec{
1437 constraintsSpec{
1438 bad: []string{"uri:"},
1441 intermediates: [][]constraintsSpec{
1442 []constraintsSpec{
1443 constraintsSpec{},
1446 leaf: leafSpec{
1447 sans: []string{"uri:https://example.com/test"},
1449 expectedError: "\"https://example.com/test\" is excluded",
1452 // #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
1453 // VerifyOptions.
1454 nameConstraintsTest{
1455 roots: []constraintsSpec{
1456 constraintsSpec{},
1458 intermediates: [][]constraintsSpec{
1459 []constraintsSpec{
1460 constraintsSpec{},
1463 leaf: leafSpec{
1464 sans: []string{"dns:example.com"},
1465 ekus: []string{"serverAuth"},
1467 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
1468 expectedError: "incompatible key usage",
1471 // #76: However, MSSGC in a leaf should match a request for serverAuth.
1472 nameConstraintsTest{
1473 roots: []constraintsSpec{
1474 constraintsSpec{},
1476 intermediates: [][]constraintsSpec{
1477 []constraintsSpec{
1478 constraintsSpec{},
1481 leaf: leafSpec{
1482 sans: []string{"dns:example.com"},
1483 ekus: []string{"msSGC"},
1485 requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
1488 // An invalid DNS SAN should be detected only at validation time so
1489 // that we can process CA certificates in the wild that have invalid SANs.
1490 // See https://github.com/golang/go/issues/23995
1492 // #77: an invalid DNS or mail SAN will not be detected if name constaint
1493 // checking is not triggered.
1494 nameConstraintsTest{
1495 roots: []constraintsSpec{
1496 constraintsSpec{},
1498 intermediates: [][]constraintsSpec{
1499 []constraintsSpec{
1500 constraintsSpec{},
1503 leaf: leafSpec{
1504 sans: []string{"dns:this is invalid", "email:this @ is invalid"},
1508 // #78: an invalid DNS SAN will be detected if any name constraint checking
1509 // is triggered.
1510 nameConstraintsTest{
1511 roots: []constraintsSpec{
1512 constraintsSpec{
1513 bad: []string{"uri:"},
1516 intermediates: [][]constraintsSpec{
1517 []constraintsSpec{
1518 constraintsSpec{},
1521 leaf: leafSpec{
1522 sans: []string{"dns:this is invalid"},
1524 expectedError: "cannot parse dnsName",
1527 // #79: an invalid email SAN will be detected if any name constraint
1528 // checking is triggered.
1529 nameConstraintsTest{
1530 roots: []constraintsSpec{
1531 constraintsSpec{
1532 bad: []string{"uri:"},
1535 intermediates: [][]constraintsSpec{
1536 []constraintsSpec{
1537 constraintsSpec{},
1540 leaf: leafSpec{
1541 sans: []string{"email:this @ is invalid"},
1543 expectedError: "cannot parse rfc822Name",
1546 // #80: if several EKUs are requested, satisfying any of them is sufficient.
1547 nameConstraintsTest{
1548 roots: []constraintsSpec{
1549 constraintsSpec{},
1551 intermediates: [][]constraintsSpec{
1552 []constraintsSpec{
1553 constraintsSpec{},
1556 leaf: leafSpec{
1557 sans: []string{"dns:example.com"},
1558 ekus: []string{"email"},
1560 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
1563 // #81: EKUs that are not asserted in VerifyOpts are not required to be
1564 // nested.
1565 nameConstraintsTest{
1566 roots: []constraintsSpec{
1567 constraintsSpec{},
1569 intermediates: [][]constraintsSpec{
1570 []constraintsSpec{
1571 constraintsSpec{
1572 ekus: []string{"serverAuth"},
1576 leaf: leafSpec{
1577 sans: []string{"dns:example.com"},
1578 // There's no email EKU in the intermediate. This would be rejected if
1579 // full nesting was required.
1580 ekus: []string{"email", "serverAuth"},
1585 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
1586 var serialBytes [16]byte
1587 rand.Read(serialBytes[:])
1589 template := &Certificate{
1590 SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
1591 Subject: pkix.Name{
1592 CommonName: name,
1594 NotBefore: time.Unix(1000, 0),
1595 NotAfter: time.Unix(2000, 0),
1596 KeyUsage: KeyUsageCertSign,
1597 BasicConstraintsValid: true,
1598 IsCA: true,
1601 if err := addConstraintsToTemplate(constraints, template); err != nil {
1602 return nil, err
1605 if parent == nil {
1606 parent = template
1608 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
1609 if err != nil {
1610 return nil, err
1613 caCert, err := ParseCertificate(derBytes)
1614 if err != nil {
1615 return nil, err
1618 return caCert, nil
1621 func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
1622 var serialBytes [16]byte
1623 rand.Read(serialBytes[:])
1625 template := &Certificate{
1626 SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
1627 Subject: pkix.Name{
1628 // Don't set a CommonName because OpenSSL (at least) will try to
1629 // match it against name constraints.
1630 OrganizationalUnit: []string{"Leaf"},
1632 NotBefore: time.Unix(1000, 0),
1633 NotAfter: time.Unix(2000, 0),
1634 KeyUsage: KeyUsageDigitalSignature,
1635 BasicConstraintsValid: true,
1636 IsCA: false,
1639 for _, name := range leaf.sans {
1640 switch {
1641 case strings.HasPrefix(name, "dns:"):
1642 template.DNSNames = append(template.DNSNames, name[4:])
1644 case strings.HasPrefix(name, "ip:"):
1645 ip := net.ParseIP(name[3:])
1646 if ip == nil {
1647 return nil, fmt.Errorf("cannot parse IP %q", name[3:])
1649 template.IPAddresses = append(template.IPAddresses, ip)
1651 case strings.HasPrefix(name, "invalidip:"):
1652 ipBytes, err := hex.DecodeString(name[10:])
1653 if err != nil {
1654 return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
1656 template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
1658 case strings.HasPrefix(name, "email:"):
1659 template.EmailAddresses = append(template.EmailAddresses, name[6:])
1661 case strings.HasPrefix(name, "uri:"):
1662 uri, err := url.Parse(name[4:])
1663 if err != nil {
1664 return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
1666 template.URIs = append(template.URIs, uri)
1668 case strings.HasPrefix(name, "unknown:"):
1669 // This is a special case for testing unknown
1670 // name types. A custom SAN extension is
1671 // injected into the certificate.
1672 if len(leaf.sans) != 1 {
1673 panic("when using unknown name types, it must be the sole name")
1676 template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
1677 Id: []int{2, 5, 29, 17},
1678 Value: []byte{
1679 0x30, // SEQUENCE
1680 3, // three bytes
1681 9, // undefined GeneralName type 9
1687 default:
1688 return nil, fmt.Errorf("unknown name type %q", name)
1692 var err error
1693 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
1694 return nil, err
1697 if parent == nil {
1698 parent = template
1701 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
1702 if err != nil {
1703 return nil, err
1706 return ParseCertificate(derBytes)
1709 func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
1710 appendConstraint := func(contents []byte, tag uint8) []byte {
1711 contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
1712 contents = append(contents, byte(4+len(constraint)) /* length */)
1713 contents = append(contents, 0x30 /* SEQUENCE */)
1714 contents = append(contents, byte(2+len(constraint)) /* length */)
1715 contents = append(contents, byte(typeNum) /* GeneralName type */)
1716 contents = append(contents, byte(len(constraint)))
1717 return append(contents, constraint...)
1720 var contents []byte
1721 if !isExcluded {
1722 contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
1723 } else {
1724 contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
1727 var value []byte
1728 value = append(value, 0x30 /* SEQUENCE */)
1729 value = append(value, byte(len(contents)))
1730 value = append(value, contents...)
1732 return pkix.Extension{
1733 Id: []int{2, 5, 29, 30},
1734 Value: value,
1738 func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
1739 parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
1740 for _, constraint := range constraints {
1741 switch {
1742 case strings.HasPrefix(constraint, "dns:"):
1743 dnsNames = append(dnsNames, constraint[4:])
1745 case strings.HasPrefix(constraint, "ip:"):
1746 _, ipNet, err := net.ParseCIDR(constraint[3:])
1747 if err != nil {
1748 return nil, nil, nil, nil, err
1750 ips = append(ips, ipNet)
1752 case strings.HasPrefix(constraint, "email:"):
1753 emailAddrs = append(emailAddrs, constraint[6:])
1755 case strings.HasPrefix(constraint, "uri:"):
1756 uriDomains = append(uriDomains, constraint[4:])
1758 default:
1759 return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
1763 return dnsNames, ips, emailAddrs, uriDomains, err
1766 handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
1767 switch {
1768 case constraint == "unknown:":
1769 template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
1771 default:
1772 return false
1775 return true
1778 if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
1779 if handleSpecialConstraint(constraints.ok[0], false) {
1780 return nil
1784 if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
1785 if handleSpecialConstraint(constraints.bad[0], true) {
1786 return nil
1790 var err error
1791 template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
1792 if err != nil {
1793 return err
1796 template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
1797 if err != nil {
1798 return err
1801 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
1802 return err
1805 return nil
1808 func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
1809 for _, s := range ekuStrs {
1810 switch s {
1811 case "serverAuth":
1812 ekus = append(ekus, ExtKeyUsageServerAuth)
1813 case "clientAuth":
1814 ekus = append(ekus, ExtKeyUsageClientAuth)
1815 case "email":
1816 ekus = append(ekus, ExtKeyUsageEmailProtection)
1817 case "netscapeSGC":
1818 ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
1819 case "msSGC":
1820 ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
1821 case "any":
1822 ekus = append(ekus, ExtKeyUsageAny)
1823 case "other":
1824 unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
1825 default:
1826 return nil, nil, fmt.Errorf("unknown EKU %q", s)
1830 return
1833 func TestConstraintCases(t *testing.T) {
1834 privateKeys := sync.Pool{
1835 New: func() interface{} {
1836 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1837 if err != nil {
1838 panic(err)
1840 return priv
1844 for i, test := range nameConstraintsTests {
1845 rootPool := NewCertPool()
1846 rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
1847 rootName := "Root " + strconv.Itoa(i)
1849 // keys keeps track of all the private keys used in a given
1850 // test and puts them back in the privateKeys pool at the end.
1851 keys := []*ecdsa.PrivateKey{rootKey}
1853 // At each level (root, intermediate(s), leaf), parent points to
1854 // an example parent certificate and parentKey the key for the
1855 // parent level. Since all certificates at a given level have
1856 // the same name and public key, any parent certificate is
1857 // sufficient to get the correct issuer name and authority
1858 // key ID.
1859 var parent *Certificate
1860 parentKey := rootKey
1862 for _, root := range test.roots {
1863 rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
1864 if err != nil {
1865 t.Fatalf("#%d: failed to create root: %s", i, err)
1868 parent = rootCert
1869 rootPool.AddCert(rootCert)
1872 intermediatePool := NewCertPool()
1874 for level, intermediates := range test.intermediates {
1875 levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
1876 keys = append(keys, levelKey)
1877 levelName := "Intermediate level " + strconv.Itoa(level)
1878 var last *Certificate
1880 for _, intermediate := range intermediates {
1881 caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
1882 if err != nil {
1883 t.Fatalf("#%d: failed to create %q: %s", i, levelName, err)
1886 last = caCert
1887 intermediatePool.AddCert(caCert)
1890 parent = last
1891 parentKey = levelKey
1894 leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
1895 keys = append(keys, leafKey)
1897 leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
1898 if err != nil {
1899 t.Fatalf("#%d: cannot create leaf: %s", i, err)
1902 if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL {
1903 output, err := testChainAgainstOpenSSL(leafCert, intermediatePool, rootPool)
1904 if err == nil && len(test.expectedError) > 0 {
1905 t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i)
1906 if debugOpenSSLFailure {
1907 return
1911 if err != nil {
1912 if _, ok := err.(*exec.ExitError); !ok {
1913 t.Errorf("#%d: OpenSSL failed to run: %s", i, err)
1914 } else if len(test.expectedError) == 0 {
1915 t.Errorf("#%d: OpenSSL unexpectedly failed: %q", i, output)
1916 if debugOpenSSLFailure {
1917 return
1923 verifyOpts := VerifyOptions{
1924 Roots: rootPool,
1925 Intermediates: intermediatePool,
1926 CurrentTime: time.Unix(1500, 0),
1927 KeyUsages: test.requestedEKUs,
1929 _, err = leafCert.Verify(verifyOpts)
1931 logInfo := true
1932 if len(test.expectedError) == 0 {
1933 if err != nil {
1934 t.Errorf("#%d: unexpected failure: %s", i, err)
1935 } else {
1936 logInfo = false
1938 } else {
1939 if err == nil {
1940 t.Errorf("#%d: unexpected success", i)
1941 } else if !strings.Contains(err.Error(), test.expectedError) {
1942 t.Errorf("#%d: expected error containing %q, but got: %s", i, test.expectedError, err)
1943 } else {
1944 logInfo = false
1948 if logInfo {
1949 certAsPEM := func(cert *Certificate) string {
1950 var buf bytes.Buffer
1951 pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
1952 return string(buf.Bytes())
1954 t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0]))
1955 t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert))
1958 for _, key := range keys {
1959 privateKeys.Put(key)
1961 keys = keys[:0]
1965 func writePEMsToTempFile(certs []*Certificate) *os.File {
1966 file, err := ioutil.TempFile("", "name_constraints_test")
1967 if err != nil {
1968 panic("cannot create tempfile")
1971 pemBlock := &pem.Block{Type: "CERTIFICATE"}
1972 for _, cert := range certs {
1973 pemBlock.Bytes = cert.Raw
1974 pem.Encode(file, pemBlock)
1977 return file
1980 func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool) (string, error) {
1981 args := []string{"verify", "-no_check_time"}
1983 rootsFile := writePEMsToTempFile(roots.certs)
1984 if debugOpenSSLFailure {
1985 println("roots file:", rootsFile.Name())
1986 } else {
1987 defer os.Remove(rootsFile.Name())
1989 args = append(args, "-CAfile", rootsFile.Name())
1991 if len(intermediates.certs) > 0 {
1992 intermediatesFile := writePEMsToTempFile(intermediates.certs)
1993 if debugOpenSSLFailure {
1994 println("intermediates file:", intermediatesFile.Name())
1995 } else {
1996 defer os.Remove(intermediatesFile.Name())
1998 args = append(args, "-untrusted", intermediatesFile.Name())
2001 leafFile := writePEMsToTempFile([]*Certificate{leaf})
2002 if debugOpenSSLFailure {
2003 println("leaf file:", leafFile.Name())
2004 } else {
2005 defer os.Remove(leafFile.Name())
2007 args = append(args, leafFile.Name())
2009 var output bytes.Buffer
2010 cmd := exec.Command("openssl", args...)
2011 cmd.Stdout = &output
2012 cmd.Stderr = &output
2014 err := cmd.Run()
2015 return string(output.Bytes()), err
2018 var rfc2821Tests = []struct {
2019 in string
2020 localPart, domain string
2022 {"foo@example.com", "foo", "example.com"},
2023 {"@example.com", "", ""},
2024 {"\"@example.com", "", ""},
2025 {"\"\"@example.com", "", "example.com"},
2026 {"\"a\"@example.com", "a", "example.com"},
2027 {"\"\\a\"@example.com", "a", "example.com"},
2028 {"a\"@example.com", "", ""},
2029 {"foo..bar@example.com", "", ""},
2030 {".foo.bar@example.com", "", ""},
2031 {"foo.bar.@example.com", "", ""},
2032 {"|{}?'@example.com", "|{}?'", "example.com"},
2034 // Examples from RFC 3696
2035 {"Abc\\@def@example.com", "Abc@def", "example.com"},
2036 {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
2037 {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
2038 {"\"Abc@def\"@example.com", "Abc@def", "example.com"},
2039 {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
2040 {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
2041 {"$A12345@example.com", "$A12345", "example.com"},
2042 {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
2043 {"_somename@example.com", "_somename", "example.com"},
2046 func TestRFC2821Parsing(t *testing.T) {
2047 for i, test := range rfc2821Tests {
2048 mailbox, ok := parseRFC2821Mailbox(test.in)
2049 expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
2051 if ok && expectedFailure {
2052 t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
2053 continue
2056 if !ok && !expectedFailure {
2057 t.Errorf("#%d: unexpected failure for %q", i, test.in)
2058 continue
2061 if !ok {
2062 continue
2065 if mailbox.local != test.localPart || mailbox.domain != test.domain {
2066 t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
2071 func TestBadNamesInConstraints(t *testing.T) {
2072 constraintParseError := func(err error) bool {
2073 str := err.Error()
2074 return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
2077 encodingError := func(err error) bool {
2078 return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
2081 // Bad names in constraints should not parse.
2082 badNames := []struct {
2083 name string
2084 matcher func(error) bool
2086 {"dns:foo.com.", constraintParseError},
2087 {"email:abc@foo.com.", constraintParseError},
2088 {"email:foo.com.", constraintParseError},
2089 {"uri:example.com.", constraintParseError},
2090 {"uri:1.2.3.4", constraintParseError},
2091 {"uri:ffff::1", constraintParseError},
2092 {"dns:not–hyphen.com", encodingError},
2093 {"email:foo@not–hyphen.com", encodingError},
2094 {"uri:not–hyphen.com", encodingError},
2097 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2098 if err != nil {
2099 panic(err)
2102 for _, test := range badNames {
2103 _, err := makeConstraintsCACert(constraintsSpec{
2104 ok: []string{test.name},
2105 }, "TestAbsoluteNamesInConstraints", priv, nil, priv)
2107 if err == nil {
2108 t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
2109 continue
2110 } else {
2111 if !test.matcher(err) {
2112 t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
2118 func TestBadNamesInSANs(t *testing.T) {
2119 // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
2120 // will parse and are tested in name constraint tests at the top of this
2121 // file.
2122 badNames := []string{
2123 "uri:https://example.com./dsf",
2124 "invalidip:0102",
2125 "invalidip:0102030405",
2128 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2129 if err != nil {
2130 panic(err)
2133 for _, badName := range badNames {
2134 _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
2136 if err == nil {
2137 t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
2138 continue
2141 if err != nil {
2142 if str := err.Error(); !strings.Contains(str, "cannot parse ") {
2143 t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)