Source file
src/crypto/x509/name_constraints_test.go
1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "crypto/ecdsa"
10 "crypto/elliptic"
11 "crypto/rand"
12 "crypto/x509/pkix"
13 "encoding/asn1"
14 "encoding/hex"
15 "encoding/pem"
16 "fmt"
17 "internal/testenv"
18 "math/big"
19 "net"
20 "net/url"
21 "os"
22 "os/exec"
23 "strconv"
24 "strings"
25 "sync"
26 "testing"
27 "time"
28 )
29
30 const (
31
32
33
34 testNameConstraintsAgainstOpenSSL = false
35
36
37
38
39 debugOpenSSLFailure = false
40 )
41
42 type nameConstraintsTest struct {
43 name string
44 roots []constraintsSpec
45 intermediates [][]constraintsSpec
46 leaf leafSpec
47 requestedEKUs []ExtKeyUsage
48 expectedError string
49 noOpenSSL bool
50 ignoreCN bool
51 }
52
53 type constraintsSpec struct {
54 ok []string
55 bad []string
56 ekus []string
57 }
58
59 type leafSpec struct {
60 sans []string
61 ekus []string
62 cn string
63 }
64
65 var nameConstraintsTests = []nameConstraintsTest{
66 {
67 name: "certificate generation process",
68 roots: make([]constraintsSpec, 1),
69 leaf: leafSpec{
70 sans: []string{"dns:example.com"},
71 },
72 },
73 {
74 name: "single level of intermediate",
75 roots: make([]constraintsSpec, 1),
76 intermediates: [][]constraintsSpec{
77 {
78 {},
79 },
80 },
81 leaf: leafSpec{
82 sans: []string{"dns:example.com"},
83 },
84 },
85 {
86 name: "two levels of intermediates",
87 roots: make([]constraintsSpec, 1),
88 intermediates: [][]constraintsSpec{
89 {
90 {},
91 },
92 {
93 {},
94 },
95 },
96 leaf: leafSpec{
97 sans: []string{"dns:example.com"},
98 },
99 },
100 {
101 name: "matching DNS constraint in root",
102 roots: []constraintsSpec{
103 {
104 ok: []string{"dns:example.com"},
105 },
106 },
107 intermediates: [][]constraintsSpec{
108 {
109 {},
110 },
111 },
112 leaf: leafSpec{
113 sans: []string{"dns:example.com"},
114 },
115 },
116 {
117 name: "matching DNS constraint in intermediate",
118 roots: make([]constraintsSpec, 1),
119 intermediates: [][]constraintsSpec{
120 {
121 {
122 ok: []string{"dns:example.com"},
123 },
124 },
125 },
126 leaf: leafSpec{
127 sans: []string{"dns:example.com"},
128 },
129 },
130 {
131 name: "leading period only matches subdomains",
132 roots: []constraintsSpec{
133 {
134 ok: []string{"dns:.example.com"},
135 },
136 },
137 intermediates: [][]constraintsSpec{
138 {
139 {},
140 },
141 },
142 leaf: leafSpec{
143 sans: []string{"dns:example.com"},
144 },
145 expectedError: "\"example.com\" is not permitted",
146 },
147 {
148 name: "leading period matches subdomains",
149 roots: make([]constraintsSpec, 1),
150 intermediates: [][]constraintsSpec{
151 {
152 {
153 ok: []string{"dns:.example.com"},
154 },
155 },
156 },
157 leaf: leafSpec{
158 sans: []string{"dns:foo.example.com"},
159 },
160 },
161 {
162 name: "leading period matches multiple levels of subdomains",
163 roots: []constraintsSpec{
164 {
165 ok: []string{"dns:.example.com"},
166 },
167 },
168 intermediates: [][]constraintsSpec{
169 {
170 {},
171 },
172 },
173 leaf: leafSpec{
174 sans: []string{"dns:foo.bar.example.com"},
175 },
176 },
177 {
178 name: "specifying a permitted list of names does not exclude other name types",
179 roots: []constraintsSpec{
180 {
181 ok: []string{"dns:.example.com"},
182 },
183 },
184 intermediates: [][]constraintsSpec{
185 {
186 {},
187 },
188 },
189 leaf: leafSpec{
190 sans: []string{"ip:10.1.1.1"},
191 },
192 },
193 {
194 name: "specifying a permitted list of names does not exclude other name types",
195 roots: []constraintsSpec{
196 {
197 ok: []string{"ip:10.0.0.0/8"},
198 },
199 },
200 intermediates: [][]constraintsSpec{
201 {
202 {},
203 },
204 },
205 leaf: leafSpec{
206 sans: []string{"dns:example.com"},
207 },
208 },
209 {
210 name: "intermediates can try to permit other names, which isn't forbidden if the leaf doesn't mention them",
211 roots: []constraintsSpec{
212 {
213 ok: []string{"dns:example.com"},
214 },
215 },
216 intermediates: [][]constraintsSpec{
217 {
218 {
219 ok: []string{"dns:example.com", "dns:foo.com"},
220 },
221 },
222 },
223 leaf: leafSpec{
224 sans: []string{"dns:example.com"},
225 },
226 },
227 {
228 name: "intermediates cannot add permitted names that the root doesn't grant them",
229 roots: []constraintsSpec{
230 {
231 ok: []string{"dns:example.com"},
232 },
233 },
234 intermediates: [][]constraintsSpec{
235 {
236 {
237 ok: []string{"dns:foo.example.com", "dns:foo.com"},
238 },
239 },
240 },
241 leaf: leafSpec{
242 sans: []string{"dns:foo.com"},
243 },
244 expectedError: "\"foo.com\" is not permitted",
245 },
246 {
247 name: "intermediates can further limit their scope if they wish",
248 roots: []constraintsSpec{
249 {
250 ok: []string{"dns:.example.com"},
251 },
252 },
253 intermediates: [][]constraintsSpec{
254 {
255 {
256 ok: []string{"dns:.bar.example.com"},
257 },
258 },
259 },
260 leaf: leafSpec{
261 sans: []string{"dns:foo.bar.example.com"},
262 },
263 },
264 {
265 name: "intermediates can further limit their scope and that limitation is effective",
266 roots: []constraintsSpec{
267 {
268 ok: []string{"dns:.example.com"},
269 },
270 },
271 intermediates: [][]constraintsSpec{
272 {
273 {
274 ok: []string{"dns:.bar.example.com"},
275 },
276 },
277 },
278 leaf: leafSpec{
279 sans: []string{"dns:foo.notbar.example.com"},
280 },
281 expectedError: "\"foo.notbar.example.com\" is not permitted",
282 },
283 {
284 name: "roots can exclude subtrees and that doesn't affect other names",
285 roots: []constraintsSpec{
286 {
287 bad: []string{"dns:.example.com"},
288 },
289 },
290 intermediates: [][]constraintsSpec{
291 {
292 {},
293 },
294 },
295 leaf: leafSpec{
296 sans: []string{"dns:foo.com"},
297 },
298 },
299 {
300 name: "roots exclusions are effective",
301 roots: []constraintsSpec{
302 {
303 bad: []string{"dns:.example.com"},
304 },
305 },
306 intermediates: [][]constraintsSpec{
307 {
308 {},
309 },
310 },
311 leaf: leafSpec{
312 sans: []string{"dns:foo.example.com"},
313 },
314 expectedError: "\"foo.example.com\" is excluded",
315 },
316 {
317 name: "intermediates can also exclude names and that doesn't affect other names",
318 roots: make([]constraintsSpec, 1),
319 intermediates: [][]constraintsSpec{
320 {
321 {
322 bad: []string{"dns:.example.com"},
323 },
324 },
325 },
326 leaf: leafSpec{
327 sans: []string{"dns:foo.com"},
328 },
329 },
330 {
331 name: "intermediate exclusions are effective",
332 roots: make([]constraintsSpec, 1),
333 intermediates: [][]constraintsSpec{
334 {
335 {
336 bad: []string{"dns:.example.com"},
337 },
338 },
339 },
340 leaf: leafSpec{
341 sans: []string{"dns:foo.example.com"},
342 },
343 expectedError: "\"foo.example.com\" is excluded",
344 },
345 {
346 name: "having an exclusion doesn't prohibit other types of names",
347 roots: []constraintsSpec{
348 {
349 bad: []string{"dns:.example.com"},
350 },
351 },
352 intermediates: [][]constraintsSpec{
353 {
354 {},
355 },
356 },
357 leaf: leafSpec{
358 sans: []string{"dns:foo.com", "ip:10.1.1.1"},
359 },
360 },
361 {
362 name: "IP-based exclusions are permitted and don't affect unrelated IP addresses",
363 roots: []constraintsSpec{
364 {
365 bad: []string{"ip:10.0.0.0/8"},
366 },
367 },
368 intermediates: [][]constraintsSpec{
369 {
370 {},
371 },
372 },
373 leaf: leafSpec{
374 sans: []string{"ip:192.168.1.1"},
375 },
376 },
377 {
378 name: "IP-based exclusions are effective",
379 roots: []constraintsSpec{
380 {
381 bad: []string{"ip:10.0.0.0/8"},
382 },
383 },
384 intermediates: [][]constraintsSpec{
385 {
386 {},
387 },
388 },
389 leaf: leafSpec{
390 sans: []string{"ip:10.0.0.1"},
391 },
392 expectedError: "\"10.0.0.1\" is excluded",
393 },
394 {
395 name: "intermediates can further constrain IP ranges",
396 roots: []constraintsSpec{
397 {
398 bad: []string{"ip:0.0.0.0/1"},
399 },
400 },
401 intermediates: [][]constraintsSpec{
402 {
403 {
404 bad: []string{"ip:11.0.0.0/8"},
405 },
406 },
407 },
408 leaf: leafSpec{
409 sans: []string{"ip:11.0.0.1"},
410 },
411 expectedError: "\"11.0.0.1\" is excluded",
412 },
413 {
414 name: "multiple intermediates with incompatible constraints",
415 roots: make([]constraintsSpec, 1),
416 intermediates: [][]constraintsSpec{
417 {
418 {
419 ok: []string{"dns:.foo.com"},
420 },
421 {
422 ok: []string{"dns:.example.com"},
423 },
424 },
425 },
426 leaf: leafSpec{
427 sans: []string{"dns:foo.example.com"},
428 },
429 noOpenSSL: true,
430 },
431 {
432 name: "multiple intermediates with incompatible constraints swapped",
433 roots: make([]constraintsSpec, 1),
434 intermediates: [][]constraintsSpec{
435 {
436 {
437 ok: []string{"dns:.example.com"},
438 },
439 {
440 ok: []string{"dns:.foo.com"},
441 },
442 },
443 },
444 leaf: leafSpec{
445 sans: []string{"dns:foo.example.com"},
446 },
447 noOpenSSL: true,
448 },
449 {
450 name: "multiple roots with incompatible constraints",
451 roots: []constraintsSpec{
452 {},
453 {
454 ok: []string{"dns:foo.com"},
455 },
456 },
457 intermediates: [][]constraintsSpec{
458 {
459 {},
460 },
461 },
462 leaf: leafSpec{
463 sans: []string{"dns:example.com"},
464 },
465 noOpenSSL: true,
466 },
467 {
468 name: "multiple roots with incompatible constraints swapped",
469 roots: []constraintsSpec{
470 {
471 ok: []string{"dns:foo.com"},
472 },
473 {},
474 },
475 intermediates: [][]constraintsSpec{
476 {
477 {},
478 },
479 },
480 leaf: leafSpec{
481 sans: []string{"dns:example.com"},
482 },
483 noOpenSSL: true,
484 },
485 {
486 name: "chain building with multiple intermediates and roots",
487 roots: []constraintsSpec{
488 {
489 ok: []string{"dns:foo.com"},
490 },
491 {
492 ok: []string{"dns:example.com"},
493 },
494 {},
495 },
496 intermediates: [][]constraintsSpec{
497 {
498 {},
499 {
500 ok: []string{"dns:foo.com"},
501 },
502 },
503 {
504 {},
505 {
506 ok: []string{"dns:foo.com"},
507 },
508 },
509 },
510 leaf: leafSpec{
511 sans: []string{"dns:bar.com"},
512 },
513 noOpenSSL: true,
514 },
515 {
516 name: "chain building fails with no valid path",
517 roots: []constraintsSpec{
518 {
519 ok: []string{"dns:foo.com"},
520 },
521 {
522 ok: []string{"dns:example.com"},
523 },
524 },
525 intermediates: [][]constraintsSpec{
526 {
527 {},
528 {
529 ok: []string{"dns:foo.com"},
530 },
531 },
532 {
533 {
534 ok: []string{"dns:bar.com"},
535 },
536 {
537 ok: []string{"dns:foo.com"},
538 },
539 },
540 },
541 leaf: leafSpec{
542 sans: []string{"dns:bar.com"},
543 },
544 expectedError: "\"bar.com\" is not permitted",
545 },
546 {
547 name: "unknown name types are unconstrained",
548 roots: make([]constraintsSpec, 1),
549 intermediates: [][]constraintsSpec{
550 {
551 {},
552 },
553 },
554 leaf: leafSpec{
555 sans: []string{"unknown:"},
556 },
557 },
558 {
559 name: "unknown name types allowed in constrained chain",
560 roots: []constraintsSpec{
561 {
562 ok: []string{"dns:foo.com", "dns:.foo.com"},
563 },
564 },
565 intermediates: [][]constraintsSpec{
566 {
567 {},
568 },
569 },
570 leaf: leafSpec{
571 sans: []string{"unknown:"},
572 },
573 },
574 {
575 name: "CN is ignored in constrained chain",
576 roots: []constraintsSpec{
577 {
578 ok: []string{"dns:foo.com", "dns:.foo.com"},
579 },
580 },
581 intermediates: [][]constraintsSpec{
582 {
583 {},
584 },
585 },
586 leaf: leafSpec{
587 sans: []string{},
588 cn: "foo.com",
589 },
590 },
591 {
592 name: "IPv6 permitted constraint",
593 roots: []constraintsSpec{
594 {
595 ok: []string{"ip:2000:abcd::/32"},
596 },
597 },
598 intermediates: [][]constraintsSpec{
599 {
600 {},
601 },
602 },
603 leaf: leafSpec{
604 sans: []string{"ip:2000:abcd:1234::"},
605 },
606 },
607 {
608 name: "IPv6 permitted constraint is effective",
609 roots: []constraintsSpec{
610 {
611 ok: []string{"ip:2000:abcd::/32"},
612 },
613 },
614 intermediates: [][]constraintsSpec{
615 {
616 {},
617 },
618 },
619 leaf: leafSpec{
620 sans: []string{"ip:2000:1234:abcd::"},
621 },
622 expectedError: "\"2000:1234:abcd::\" is not permitted",
623 },
624 {
625 name: "IPv6 permitted constraint does not affect DNS",
626 roots: []constraintsSpec{
627 {
628 ok: []string{"ip:2000:abcd::/32"},
629 },
630 },
631 intermediates: [][]constraintsSpec{
632 {
633 {},
634 },
635 },
636 leaf: leafSpec{
637 sans: []string{"ip:2000:abcd::", "dns:foo.com"},
638 },
639 },
640 {
641 name: "IPv6 excluded constraint",
642 roots: []constraintsSpec{
643 {
644 bad: []string{"ip:2000:abcd::/32"},
645 },
646 },
647 intermediates: [][]constraintsSpec{
648 {
649 {},
650 },
651 },
652 leaf: leafSpec{
653 sans: []string{"ip:2000:1234::"},
654 },
655 },
656 {
657 name: "IPv6 excluded constraint is effective",
658 roots: []constraintsSpec{
659 {
660 bad: []string{"ip:2000:abcd::/32"},
661 },
662 },
663 intermediates: [][]constraintsSpec{
664 {
665 {},
666 },
667 },
668 leaf: leafSpec{
669 sans: []string{"ip:2000:abcd::"},
670 },
671 expectedError: "\"2000:abcd::\" is excluded",
672 },
673 {
674 name: "IPv6 constraint does not permit IPv4",
675 roots: []constraintsSpec{
676 {
677 ok: []string{"ip:2000:abcd::/32"},
678 },
679 },
680 intermediates: [][]constraintsSpec{
681 {
682 {},
683 },
684 },
685 leaf: leafSpec{
686 sans: []string{"ip:10.0.0.1"},
687 },
688 expectedError: "\"10.0.0.1\" is not permitted",
689 },
690 {
691 name: "IPv4 constraint does not permit IPv6",
692 roots: []constraintsSpec{
693 {
694 ok: []string{"ip:10.0.0.0/8"},
695 },
696 },
697 intermediates: [][]constraintsSpec{
698 {
699 {},
700 },
701 },
702 leaf: leafSpec{
703 sans: []string{"ip:2000:abcd::"},
704 },
705 expectedError: "\"2000:abcd::\" is not permitted",
706 },
707 {
708 name: "unknown excluded constraint does not affect other names",
709 roots: []constraintsSpec{
710 {
711 bad: []string{"unknown:"},
712 },
713 },
714 intermediates: [][]constraintsSpec{
715 {
716 {},
717 },
718 },
719 leaf: leafSpec{
720 sans: []string{"dns:example.com"},
721 },
722 },
723 {
724 name: "unknown permitted constraint does not affect other names",
725 roots: []constraintsSpec{
726 {
727 ok: []string{"unknown:"},
728 },
729 },
730 intermediates: [][]constraintsSpec{
731 {
732 {},
733 },
734 },
735 leaf: leafSpec{
736 sans: []string{"dns:example.com"},
737 },
738 },
739 {
740 name: "exact email constraint",
741 roots: []constraintsSpec{
742 {
743 ok: []string{"email:foo@example.com"},
744 },
745 },
746 intermediates: [][]constraintsSpec{
747 {
748 {},
749 },
750 },
751 leaf: leafSpec{
752 sans: []string{"email:foo@example.com"},
753 },
754 },
755 {
756 name: "exact email constraint is effective",
757 roots: []constraintsSpec{
758 {
759 ok: []string{"email:foo@example.com"},
760 },
761 },
762 intermediates: [][]constraintsSpec{
763 {
764 {},
765 },
766 },
767 leaf: leafSpec{
768 sans: []string{"email:bar@example.com"},
769 },
770 expectedError: "\"bar@example.com\" is not permitted",
771 },
772 {
773 name: "email canonicalization",
774 roots: []constraintsSpec{
775 {
776 ok: []string{"email:foo@example.com"},
777 },
778 },
779 intermediates: [][]constraintsSpec{
780 {
781 {},
782 },
783 },
784 leaf: leafSpec{
785 sans: []string{"email:\"\\f\\o\\o\"@example.com"},
786 },
787 noOpenSSL: true,
788 },
789 {
790 name: "email host constraint",
791 roots: []constraintsSpec{
792 {
793 ok: []string{"email:example.com"},
794 },
795 },
796 intermediates: [][]constraintsSpec{
797 {
798 {},
799 },
800 },
801 leaf: leafSpec{
802 sans: []string{"email:foo@example.com"},
803 },
804 },
805 {
806 name: "email host constraint does not match subdomains",
807 roots: []constraintsSpec{
808 {
809 ok: []string{"email:example.com"},
810 },
811 },
812 intermediates: [][]constraintsSpec{
813 {
814 {},
815 },
816 },
817 leaf: leafSpec{
818 sans: []string{"email:foo@sub.example.com"},
819 },
820 expectedError: "\"foo@sub.example.com\" is not permitted",
821 },
822 {
823 name: "excluded email host constraint",
824 roots: []constraintsSpec{
825 {
826 bad: []string{"email:example.com"},
827 },
828 },
829 intermediates: [][]constraintsSpec{
830 {
831 {},
832 },
833 },
834 leaf: leafSpec{
835 sans: []string{"email:foo@example.com"},
836 },
837 expectedError: "\"foo@example.com\" is excluded",
838 },
839 {
840 name: "excluded email host constraint does not match subdomains",
841 roots: []constraintsSpec{
842 {
843 bad: []string{"email:example.com"},
844 },
845 },
846 intermediates: [][]constraintsSpec{
847 {
848 {},
849 },
850 },
851 leaf: leafSpec{
852 sans: []string{"email:foo@sub.example.com"},
853 },
854 },
855 {
856 name: "excluded email subdomain constraint does not match parent",
857 roots: []constraintsSpec{
858 {
859 bad: []string{"email:.example.com"},
860 },
861 },
862 intermediates: [][]constraintsSpec{
863 {
864 {},
865 },
866 },
867 leaf: leafSpec{
868 sans: []string{"email:foo@example.com"},
869 },
870 },
871 {
872 name: "excluded email host constraint treats wildcard literally",
873 roots: []constraintsSpec{
874 {
875 bad: []string{"email:example.com"},
876 },
877 },
878 intermediates: [][]constraintsSpec{
879 {
880 {},
881 },
882 },
883 leaf: leafSpec{
884 sans: []string{"email:foo@*.example.com"},
885 },
886 noOpenSSL: true,
887 },
888 {
889 name: "email host and subdomain constraints",
890 roots: []constraintsSpec{
891 {
892
893 ok: []string{"email:EXAMPLE.com", "email:.EXAMPLE.com"},
894 },
895 },
896 intermediates: [][]constraintsSpec{
897 {
898 {},
899 },
900 },
901 leaf: leafSpec{
902 sans: []string{
903 "email:foo@example.com",
904 "email:foo@sub.example.com",
905 },
906 },
907 },
908 {
909 name: "email subdomain constraint prunes covered host",
910 roots: []constraintsSpec{
911 {
912
913 ok: []string{"email:.EXAMPLE.com", "email:sub.example.com"},
914 },
915 },
916 intermediates: [][]constraintsSpec{
917 {
918 {},
919 },
920 },
921 leaf: leafSpec{
922 sans: []string{
923 "email:foo@sub.example.com",
924 "email:foo@deep.sub.example.com",
925 },
926 },
927 },
928 {
929 name: "email subdomain constraint",
930 roots: []constraintsSpec{
931 {
932 ok: []string{"email:.example.com"},
933 },
934 },
935 intermediates: [][]constraintsSpec{
936 {
937 {},
938 },
939 },
940 leaf: leafSpec{
941 sans: []string{"email:foo@sub.example.com"},
942 },
943 },
944 {
945 name: "email subdomain constraint does not match parent",
946 roots: []constraintsSpec{
947 {
948 ok: []string{"email:.example.com"},
949 },
950 },
951 intermediates: [][]constraintsSpec{
952 {
953 {},
954 },
955 },
956 leaf: leafSpec{
957 sans: []string{"email:foo@example.com"},
958 },
959 expectedError: "\"foo@example.com\" is not permitted",
960 },
961 {
962 name: "email subdomain constraint matches deeper subdomains",
963 roots: []constraintsSpec{
964 {
965 ok: []string{"email:.example.com"},
966 },
967 },
968 intermediates: [][]constraintsSpec{
969 {
970 {},
971 },
972 },
973 leaf: leafSpec{
974 sans: []string{"email:foo@sub.sub.example.com"},
975 },
976 },
977 {
978 name: "email local part is case-sensitive",
979 roots: []constraintsSpec{
980 {
981 ok: []string{"email:foo@example.com"},
982 },
983 },
984 intermediates: [][]constraintsSpec{
985 {
986 {},
987 },
988 },
989 leaf: leafSpec{
990 sans: []string{"email:Foo@example.com"},
991 },
992 expectedError: "\"Foo@example.com\" is not permitted",
993 },
994 {
995 name: "email domain part is case-insensitive",
996 roots: []constraintsSpec{
997 {
998 ok: []string{"email:foo@EXAMPLE.com"},
999 },
1000 },
1001 intermediates: [][]constraintsSpec{
1002 {
1003 {},
1004 },
1005 },
1006 leaf: leafSpec{
1007 sans: []string{"email:foo@example.com"},
1008 },
1009 },
1010 {
1011 name: "DNS domain is case-insensitive",
1012 roots: []constraintsSpec{
1013 {
1014 ok: []string{"dns:EXAMPLE.com"},
1015 },
1016 },
1017 intermediates: [][]constraintsSpec{
1018 {
1019 {},
1020 },
1021 },
1022 leaf: leafSpec{
1023 sans: []string{"dns:example.com"},
1024 },
1025 },
1026 {
1027 name: "URI constraint covers host",
1028 roots: []constraintsSpec{
1029 {
1030 ok: []string{"uri:example.com"},
1031 },
1032 },
1033 intermediates: [][]constraintsSpec{
1034 {
1035 {},
1036 },
1037 },
1038 leaf: leafSpec{
1039 sans: []string{
1040 "uri:http://example.com/bar",
1041 "uri:http://example.com:8080/",
1042 "uri:https://example.com/wibble#bar",
1043 },
1044 },
1045 },
1046 {
1047 name: "URI host constraint does not match subdomains",
1048 roots: []constraintsSpec{
1049 {
1050 ok: []string{"uri:example.com"},
1051 },
1052 },
1053 intermediates: [][]constraintsSpec{
1054 {
1055 {},
1056 },
1057 },
1058 leaf: leafSpec{
1059 sans: []string{"uri:http://sub.example.com/"},
1060 },
1061 expectedError: "\"http://sub.example.com/\" is not permitted",
1062 },
1063 {
1064 name: "URI with IP is rejected",
1065 roots: []constraintsSpec{
1066 {
1067 ok: []string{"uri:example.com"},
1068 },
1069 },
1070 intermediates: [][]constraintsSpec{
1071 {
1072 {},
1073 },
1074 },
1075 leaf: leafSpec{
1076 sans: []string{"uri:http://1.2.3.4/"},
1077 },
1078 expectedError: "URI with IP",
1079 },
1080 {
1081 name: "URI with IP and port is rejected",
1082 roots: []constraintsSpec{
1083 {
1084 ok: []string{"uri:example.com"},
1085 },
1086 },
1087 intermediates: [][]constraintsSpec{
1088 {
1089 {},
1090 },
1091 },
1092 leaf: leafSpec{
1093 sans: []string{"uri:http://1.2.3.4:43/"},
1094 },
1095 expectedError: "URI with IP",
1096 },
1097 {
1098 name: "URI with IPv6 is rejected",
1099 roots: []constraintsSpec{
1100 {
1101 ok: []string{"uri:example.com"},
1102 },
1103 },
1104 intermediates: [][]constraintsSpec{
1105 {
1106 {},
1107 },
1108 },
1109 leaf: leafSpec{
1110 sans: []string{"uri:http://[2006:abcd::1]/"},
1111 },
1112 expectedError: "URI with IP",
1113 },
1114 {
1115 name: "URI with IPv6 and port is rejected",
1116 roots: []constraintsSpec{
1117 {
1118 ok: []string{"uri:example.com"},
1119 },
1120 },
1121 intermediates: [][]constraintsSpec{
1122 {
1123 {},
1124 },
1125 },
1126 leaf: leafSpec{
1127 sans: []string{"uri:http://[2006:abcd::1]:16/"},
1128 },
1129 expectedError: "URI with IP",
1130 },
1131 {
1132 name: "URI permitted constraint is effective",
1133 roots: []constraintsSpec{
1134 {
1135 ok: []string{"uri:example.com"},
1136 },
1137 },
1138 intermediates: [][]constraintsSpec{
1139 {
1140 {},
1141 },
1142 },
1143 leaf: leafSpec{
1144 sans: []string{"uri:http://bar.com/"},
1145 },
1146 expectedError: "\"http://bar.com/\" is not permitted",
1147 },
1148 {
1149 name: "URI excluded constraint is effective",
1150 roots: []constraintsSpec{
1151 {
1152 bad: []string{"uri:foo.com"},
1153 },
1154 },
1155 intermediates: [][]constraintsSpec{
1156 {
1157 {},
1158 },
1159 },
1160 leaf: leafSpec{
1161 sans: []string{"uri:http://foo.com/"},
1162 },
1163 expectedError: "\"http://foo.com/\" is excluded",
1164 },
1165 {
1166 name: "excluded URI host constraint does not match subdomains",
1167 roots: []constraintsSpec{
1168 {
1169 bad: []string{"uri:foo.com"},
1170 },
1171 },
1172 intermediates: [][]constraintsSpec{
1173 {
1174 {},
1175 },
1176 },
1177 leaf: leafSpec{
1178 sans: []string{"uri:http://sub.foo.com/"},
1179 },
1180 },
1181 {
1182 name: "excluded URI subdomain constraint does not match parent",
1183 roots: []constraintsSpec{
1184 {
1185 bad: []string{"uri:.example.com"},
1186 },
1187 },
1188 intermediates: [][]constraintsSpec{
1189 {
1190 {},
1191 },
1192 },
1193 leaf: leafSpec{
1194 sans: []string{"uri:https://example.com/"},
1195 },
1196 },
1197 {
1198 name: "excluded URI host constraint treats wildcard literally",
1199 roots: []constraintsSpec{
1200 {
1201 bad: []string{"uri:example.com"},
1202 },
1203 },
1204 intermediates: [][]constraintsSpec{
1205 {
1206 {},
1207 },
1208 },
1209 leaf: leafSpec{
1210 sans: []string{"uri:https://*.example.com/"},
1211 },
1212 noOpenSSL: true,
1213 },
1214 {
1215 name: "URI host and subdomain constraints",
1216 roots: []constraintsSpec{
1217 {
1218
1219 ok: []string{"uri:EXAMPLE.com", "uri:.EXAMPLE.com"},
1220 },
1221 },
1222 intermediates: [][]constraintsSpec{
1223 {
1224 {},
1225 },
1226 },
1227 leaf: leafSpec{
1228 sans: []string{
1229 "uri:https://example.com/",
1230 "uri:https://sub.example.com/",
1231 },
1232 },
1233 },
1234 {
1235 name: "URI subdomain constraint",
1236 roots: []constraintsSpec{
1237 {
1238 ok: []string{"uri:.foo.com"},
1239 },
1240 },
1241 intermediates: [][]constraintsSpec{
1242 {
1243 {},
1244 },
1245 },
1246 leaf: leafSpec{
1247 sans: []string{"uri:http://www.foo.com/"},
1248 },
1249 },
1250 {
1251 name: "URI subdomain constraint does not match parent",
1252 roots: []constraintsSpec{
1253 {
1254 ok: []string{"uri:.foo.com"},
1255 },
1256 },
1257 intermediates: [][]constraintsSpec{
1258 {
1259 {},
1260 },
1261 },
1262 leaf: leafSpec{
1263 sans: []string{"uri:http://foo.com/"},
1264 },
1265 expectedError: "\"http://foo.com/\" is not permitted",
1266 },
1267 {
1268 name: "URI subdomain constraint matches deeper subdomains",
1269 roots: []constraintsSpec{
1270 {
1271 ok: []string{"uri:.foo.com"},
1272 },
1273 },
1274 intermediates: [][]constraintsSpec{
1275 {
1276 {},
1277 },
1278 },
1279 leaf: leafSpec{
1280 sans: []string{"uri:http://one.two.foo.com/"},
1281 },
1282 },
1283 {
1284 name: "URI constraint not matched by URN",
1285 roots: []constraintsSpec{
1286 {
1287 ok: []string{"uri:example.com"},
1288 },
1289 },
1290 intermediates: [][]constraintsSpec{
1291 {
1292 {},
1293 },
1294 },
1295 leaf: leafSpec{
1296 sans: []string{"uri:urn:example"},
1297 },
1298 expectedError: "URI with empty host",
1299 },
1300 {
1301 name: "IPv6 exclusion does not exclude all IPv4",
1302 roots: []constraintsSpec{
1303 {
1304 ok: []string{"ip:1.2.3.0/24"},
1305 bad: []string{"ip:::0/0"},
1306 },
1307 },
1308 intermediates: [][]constraintsSpec{
1309 {
1310 {},
1311 },
1312 },
1313 leaf: leafSpec{
1314 sans: []string{"ip:1.2.3.4"},
1315 },
1316 },
1317 {
1318 name: "empty EKU in CA means any is ok",
1319 roots: make([]constraintsSpec, 1),
1320 intermediates: [][]constraintsSpec{
1321 {
1322 {},
1323 },
1324 },
1325 leaf: leafSpec{
1326 sans: []string{"dns:example.com"},
1327 ekus: []string{"serverAuth", "other"},
1328 },
1329 },
1330 {
1331 name: "any EKU means any is ok",
1332 roots: make([]constraintsSpec, 1),
1333 intermediates: [][]constraintsSpec{
1334 {
1335 {
1336 ekus: []string{"any"},
1337 },
1338 },
1339 },
1340 leaf: leafSpec{
1341 sans: []string{"dns:example.com"},
1342 ekus: []string{"serverAuth", "other"},
1343 },
1344 },
1345
1346 {
1347 name: "intermediate with enumerated EKUs",
1348 roots: make([]constraintsSpec, 1),
1349 intermediates: [][]constraintsSpec{
1350 {
1351 {
1352 ekus: []string{"email"},
1353 },
1354 },
1355 },
1356 leaf: leafSpec{
1357 sans: []string{"dns:example.com"},
1358 ekus: []string{"serverAuth"},
1359 },
1360 expectedError: "incompatible key usage",
1361 },
1362 {
1363 name: "unknown EKU in leaf",
1364 roots: make([]constraintsSpec, 1),
1365 intermediates: [][]constraintsSpec{
1366 {
1367 {
1368 ekus: []string{"email"},
1369 },
1370 },
1371 },
1372 leaf: leafSpec{
1373 sans: []string{"dns:example.com"},
1374 ekus: []string{"other"},
1375 },
1376 requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
1377 },
1378
1379 {
1380 name: "intermediate cannot add EKUs not in root if leaf uses them",
1381 roots: []constraintsSpec{
1382 {
1383 ekus: []string{"serverAuth"},
1384 },
1385 },
1386 intermediates: [][]constraintsSpec{
1387 {
1388 {
1389 ekus: []string{"serverAuth", "email"},
1390 },
1391 },
1392 },
1393 leaf: leafSpec{
1394 sans: []string{"dns:example.com"},
1395 ekus: []string{"serverAuth"},
1396 },
1397 },
1398 {
1399 name: "EKUs in root are effective",
1400 roots: []constraintsSpec{
1401 {
1402 ekus: []string{"email"},
1403 },
1404 },
1405 intermediates: [][]constraintsSpec{
1406 {
1407 {
1408 ekus: []string{"serverAuth"},
1409 },
1410 },
1411 },
1412 leaf: leafSpec{
1413 sans: []string{"dns:example.com"},
1414 ekus: []string{"serverAuth"},
1415 },
1416 expectedError: "incompatible key usage",
1417 },
1418 {
1419 name: "netscapeSGC EKU does not permit server/client auth",
1420 roots: []constraintsSpec{
1421 {},
1422 },
1423 intermediates: [][]constraintsSpec{
1424 {
1425 {
1426 ekus: []string{"netscapeSGC"},
1427 },
1428 },
1429 },
1430 leaf: leafSpec{
1431 sans: []string{"dns:example.com"},
1432 ekus: []string{"serverAuth", "clientAuth"},
1433 },
1434 expectedError: "incompatible key usage",
1435 },
1436 {
1437 name: "msSGC EKU does not permit server/client auth",
1438 roots: make([]constraintsSpec, 1),
1439 intermediates: [][]constraintsSpec{
1440 {
1441 {
1442 ekus: []string{"msSGC"},
1443 },
1444 },
1445 },
1446 leaf: leafSpec{
1447 sans: []string{"dns:example.com"},
1448 ekus: []string{"serverAuth", "clientAuth"},
1449 },
1450 expectedError: "incompatible key usage",
1451 },
1452 {
1453 name: "empty DNS permitted constraint allows anything",
1454 roots: []constraintsSpec{
1455 {
1456 ok: []string{"dns:"},
1457 },
1458 },
1459 intermediates: [][]constraintsSpec{
1460 {
1461 {},
1462 },
1463 },
1464 leaf: leafSpec{
1465 sans: []string{"dns:example.com"},
1466 },
1467 },
1468 {
1469 name: "empty DNS excluded constraint rejects everything",
1470 roots: []constraintsSpec{
1471 {
1472 bad: []string{"dns:"},
1473 },
1474 },
1475 intermediates: [][]constraintsSpec{
1476 {
1477 {},
1478 },
1479 },
1480 leaf: leafSpec{
1481 sans: []string{"dns:example.com"},
1482 },
1483 expectedError: "\"example.com\" is excluded",
1484 },
1485 {
1486 name: "empty email permitted constraint allows anything",
1487 roots: []constraintsSpec{
1488 {
1489 ok: []string{"email:"},
1490 },
1491 },
1492 intermediates: [][]constraintsSpec{
1493 {
1494 {},
1495 },
1496 },
1497 leaf: leafSpec{
1498 sans: []string{"email:foo@example.com"},
1499 },
1500 },
1501 {
1502 name: "empty email excluded constraint rejects everything",
1503 roots: []constraintsSpec{
1504 {
1505 bad: []string{"email:"},
1506 },
1507 },
1508 intermediates: [][]constraintsSpec{
1509 {
1510 {},
1511 },
1512 },
1513 leaf: leafSpec{
1514 sans: []string{"email:foo@example.com"},
1515 },
1516 expectedError: "\"foo@example.com\" is excluded",
1517 },
1518 {
1519 name: "empty URI permitted constraint allows anything",
1520 roots: []constraintsSpec{
1521 {
1522 ok: []string{"uri:"},
1523 },
1524 },
1525 intermediates: [][]constraintsSpec{
1526 {
1527 {},
1528 },
1529 },
1530 leaf: leafSpec{
1531 sans: []string{"uri:https://example.com/test"},
1532 },
1533 },
1534 {
1535 name: "empty URI excluded constraint rejects everything",
1536 roots: []constraintsSpec{
1537 {
1538 bad: []string{"uri:"},
1539 },
1540 },
1541 intermediates: [][]constraintsSpec{
1542 {
1543 {},
1544 },
1545 },
1546 leaf: leafSpec{
1547 sans: []string{"uri:https://example.com/test"},
1548 },
1549 expectedError: "\"https://example.com/test\" is excluded",
1550 },
1551 {
1552 name: "serverAuth EKU does not permit clientAuth",
1553 roots: make([]constraintsSpec, 1),
1554 intermediates: [][]constraintsSpec{
1555 {
1556 {},
1557 },
1558 },
1559 leaf: leafSpec{
1560 sans: []string{"dns:example.com"},
1561 ekus: []string{"serverAuth"},
1562 },
1563 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
1564 expectedError: "incompatible key usage",
1565 },
1566 {
1567 name: "msSGC EKU does not permit serverAuth",
1568 roots: make([]constraintsSpec, 1),
1569 intermediates: [][]constraintsSpec{
1570 {
1571 {},
1572 },
1573 },
1574 leaf: leafSpec{
1575 sans: []string{"dns:example.com"},
1576 ekus: []string{"msSGC"},
1577 },
1578 requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
1579 expectedError: "incompatible key usage",
1580 },
1581 {
1582
1583
1584
1585 name: "invalid SANs are ignored with no constraints",
1586 roots: make([]constraintsSpec, 1),
1587 intermediates: [][]constraintsSpec{
1588 {
1589 {},
1590 },
1591 },
1592 leaf: leafSpec{
1593 sans: []string{"dns:this is invalid", "email:this @ is invalid"},
1594 },
1595 },
1596 {
1597 name: "invalid DNS SAN detected with constraints",
1598 roots: []constraintsSpec{
1599 {
1600 bad: []string{"uri:"},
1601 },
1602 },
1603 intermediates: [][]constraintsSpec{
1604 {
1605 {},
1606 },
1607 },
1608 leaf: leafSpec{
1609 sans: []string{"dns:this is invalid"},
1610 },
1611 expectedError: "cannot parse dnsName",
1612 },
1613 {
1614 name: "invalid email SAN detected with constraints",
1615 roots: []constraintsSpec{
1616 {
1617 bad: []string{"uri:"},
1618 },
1619 },
1620 intermediates: [][]constraintsSpec{
1621 {
1622 {},
1623 },
1624 },
1625 leaf: leafSpec{
1626 sans: []string{"email:this @ is invalid"},
1627 },
1628 expectedError: "cannot parse rfc822Name",
1629 },
1630 {
1631 name: "any requested EKU is sufficient",
1632 roots: make([]constraintsSpec, 1),
1633 intermediates: [][]constraintsSpec{
1634 {
1635 {},
1636 },
1637 },
1638 leaf: leafSpec{
1639 sans: []string{"dns:example.com"},
1640 ekus: []string{"email"},
1641 },
1642 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
1643 },
1644 {
1645 name: "unrequested EKUs not required to be nested",
1646 roots: make([]constraintsSpec, 1),
1647 intermediates: [][]constraintsSpec{
1648 {
1649 {
1650 ekus: []string{"serverAuth"},
1651 },
1652 },
1653 },
1654 leaf: leafSpec{
1655 sans: []string{"dns:example.com"},
1656
1657
1658 ekus: []string{"email", "serverAuth"},
1659 },
1660 },
1661 {
1662 name: "empty leaf is accepted in constrained chain",
1663 roots: []constraintsSpec{
1664 {
1665 ok: []string{"dns:foo.com", "dns:.foo.com"},
1666 },
1667 },
1668 intermediates: [][]constraintsSpec{
1669 {
1670 {},
1671 },
1672 },
1673 leaf: leafSpec{
1674 sans: []string{},
1675 },
1676 },
1677 {
1678 name: "no SANs and non-hostname CN is accepted in constrained chain",
1679 roots: []constraintsSpec{
1680 {
1681 ok: []string{"dns:foo.com", "dns:.foo.com"},
1682 },
1683 },
1684 intermediates: [][]constraintsSpec{
1685 {
1686 {},
1687 },
1688 },
1689 leaf: leafSpec{
1690 sans: []string{},
1691 cn: "foo.bar",
1692 },
1693 },
1694 {
1695 name: "constraints don't apply to CN",
1696 roots: []constraintsSpec{
1697 {
1698 ok: []string{"dns:foo.com", "dns:.foo.com"},
1699 },
1700 },
1701 intermediates: [][]constraintsSpec{
1702 {
1703 {},
1704 },
1705 },
1706 leaf: leafSpec{
1707 sans: []string{"dns:foo.com"},
1708 cn: "foo.bar",
1709 },
1710 },
1711 {
1712 name: "DNS SAN cannot use leading period form",
1713 roots: []constraintsSpec{{ok: []string{"dns:example.com"}}},
1714 leaf: leafSpec{sans: []string{"dns:.example.com"}},
1715 expectedError: "cannot parse dnsName \".example.com\"",
1716 },
1717 {
1718 name: "URI with IPv6 and zone is rejected",
1719 roots: []constraintsSpec{
1720 {
1721 ok: []string{"uri:example.com"},
1722 },
1723 },
1724 intermediates: [][]constraintsSpec{
1725 {
1726 {},
1727 },
1728 },
1729 leaf: leafSpec{
1730 sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
1731 },
1732 expectedError: "URI with IP",
1733 },
1734 {
1735 name: "intermediate can narrow permitted dns scope",
1736 roots: []constraintsSpec{
1737 {
1738 ok: []string{"dns:"},
1739 },
1740 },
1741 intermediates: [][]constraintsSpec{
1742 {
1743 {
1744 ok: []string{"dns:example.com"},
1745 },
1746 },
1747 },
1748 leaf: leafSpec{
1749 sans: []string{"dns:test.com"},
1750 },
1751 expectedError: "\"test.com\" is not permitted",
1752 },
1753 {
1754 name: "intermediate cannot narrow excluded dns scope",
1755 roots: []constraintsSpec{
1756 {
1757 bad: []string{"dns:"},
1758 },
1759 },
1760 intermediates: [][]constraintsSpec{
1761 {
1762 {
1763 bad: []string{"dns:example.com"},
1764 },
1765 },
1766 },
1767 leaf: leafSpec{
1768 sans: []string{"dns:test.com"},
1769 },
1770 expectedError: "\"test.com\" is excluded by constraint \"\"",
1771 },
1772 {
1773 name: "intermediate can narrow excluded dns scope",
1774 roots: []constraintsSpec{
1775 {
1776 bad: []string{"dns:example.com"},
1777 },
1778 },
1779 intermediates: [][]constraintsSpec{
1780 {
1781 {
1782 bad: []string{"dns:"},
1783 },
1784 },
1785 },
1786 leaf: leafSpec{
1787 sans: []string{"dns:test.com"},
1788 },
1789 expectedError: "\"test.com\" is excluded by constraint \"\"",
1790 },
1791 {
1792 name: "permitted dns constraint is not a prefix match",
1793 roots: []constraintsSpec{
1794 {
1795 ok: []string{"dns:example.com"},
1796 },
1797 },
1798 intermediates: [][]constraintsSpec{
1799 {
1800 {},
1801 },
1802 },
1803 leaf: leafSpec{
1804 sans: []string{"dns:testexample.com"},
1805 },
1806 expectedError: "\"testexample.com\" is not permitted",
1807 },
1808 {
1809 name: "subdomain constraint does not allow wildcard",
1810 roots: []constraintsSpec{
1811 {
1812 ok: []string{"dns:a.com", "dns:foo.example.com", "dns:z.com"},
1813 },
1814 },
1815 intermediates: [][]constraintsSpec{
1816 {
1817 {},
1818 },
1819 },
1820 leaf: leafSpec{
1821 sans: []string{"dns:*.example.com"},
1822 },
1823 expectedError: "\"*.example.com\" is not permitted",
1824 },
1825 {
1826 name: "excluded dns constraint is not a prefix match",
1827 roots: []constraintsSpec{
1828 {
1829 bad: []string{"dns:example.com"},
1830 },
1831 },
1832 intermediates: [][]constraintsSpec{
1833 {
1834 {},
1835 },
1836 },
1837 leaf: leafSpec{
1838 sans: []string{"dns:testexample.com"},
1839 },
1840 },
1841 {
1842 name: "excluded email constraint, multiple email with matching local portion",
1843 roots: []constraintsSpec{
1844 {
1845 bad: []string{"email:a@example.com", "email:a@test.com"},
1846 },
1847 },
1848 intermediates: [][]constraintsSpec{
1849 {
1850 {},
1851 },
1852 },
1853 leaf: leafSpec{
1854 sans: []string{"email:a@example.com"},
1855 },
1856 expectedError: "\"a@example.com\" is excluded by constraint \"a@example.com\"",
1857 },
1858 {
1859 name: "email_case_check",
1860 roots: []constraintsSpec{
1861 {
1862 ok: []string{"email:a@example.com"},
1863 },
1864 },
1865 intermediates: [][]constraintsSpec{
1866 {
1867 {},
1868 },
1869 },
1870 leaf: leafSpec{
1871 sans: []string{"email:a@ExAmple.com"},
1872 },
1873 },
1874 {
1875 name: "excluded constraint, empty DNS san",
1876 roots: []constraintsSpec{
1877 {
1878 bad: []string{"dns:example.com"},
1879 },
1880 },
1881 leaf: leafSpec{
1882 sans: []string{"dns:"},
1883 },
1884 },
1885
1886 {
1887 name: "subdomain excluded constraints preclude outer wildcard names",
1888 roots: []constraintsSpec{
1889 {
1890 bad: []string{"dns:foo.example.com"},
1891 },
1892 },
1893 intermediates: [][]constraintsSpec{
1894 {
1895 {},
1896 },
1897 },
1898 leaf: leafSpec{
1899 sans: []string{"dns:*.example.com"},
1900 },
1901 expectedError: "\"*.example.com\" is excluded by constraint \"foo.example.com\"",
1902 },
1903 {
1904 name: "subdomain excluded constraints do not preclude far outer wildcard names",
1905 roots: []constraintsSpec{
1906 {
1907 bad: []string{"dns:foo.example.com"},
1908 },
1909 },
1910 intermediates: [][]constraintsSpec{
1911 {
1912 {},
1913 },
1914 },
1915 leaf: leafSpec{
1916 sans: []string{"dns:*.com"},
1917 },
1918 },
1919 {
1920 name: "subdomain excluded constraints preclude inner wildcard names",
1921 roots: []constraintsSpec{
1922 {
1923 bad: []string{"dns:foo.example.com"},
1924 },
1925 },
1926 intermediates: [][]constraintsSpec{
1927 {
1928 {},
1929 },
1930 },
1931 leaf: leafSpec{
1932 sans: []string{"dns:*.foo.example.com"},
1933 },
1934 expectedError: "\"*.foo.example.com\" is excluded by constraint \"foo.example.com\"",
1935 },
1936 {
1937 name: "subdomain excluded constraints preclude far inner wildcard names",
1938 roots: []constraintsSpec{
1939 {
1940 bad: []string{"dns:foo.example.com"},
1941 },
1942 },
1943 intermediates: [][]constraintsSpec{
1944 {
1945 {},
1946 },
1947 },
1948 leaf: leafSpec{
1949 sans: []string{"dns:*.bar.foo.example.com"},
1950 },
1951 expectedError: "\"*.bar.foo.example.com\" is excluded by constraint \"foo.example.com\"",
1952 },
1953 {
1954 name: "outer wildcard names are not matched by subdomain permitted constraints",
1955 roots: []constraintsSpec{
1956 {
1957 ok: []string{"dns:foo.example.com"},
1958 },
1959 },
1960 intermediates: [][]constraintsSpec{
1961 {
1962 {},
1963 },
1964 },
1965 leaf: leafSpec{
1966 sans: []string{"dns:*.example.com"},
1967 },
1968 expectedError: "\"*.example.com\" is not permitted",
1969 },
1970 {
1971 name: "far outer wildcard names are not matched by subdomain permitted constraints",
1972 roots: []constraintsSpec{
1973 {
1974 ok: []string{"dns:foo.example.com"},
1975 },
1976 },
1977 intermediates: [][]constraintsSpec{
1978 {
1979 {},
1980 },
1981 },
1982 leaf: leafSpec{
1983 sans: []string{"dns:*.com"},
1984 },
1985 expectedError: "\"*.com\" is not permitted",
1986 },
1987 {
1988 name: "inner wildcard names are matched by subdomain permitted constraints",
1989 roots: []constraintsSpec{
1990 {
1991 ok: []string{"dns:foo.example.com"},
1992 },
1993 },
1994 intermediates: [][]constraintsSpec{
1995 {
1996 {},
1997 },
1998 },
1999 leaf: leafSpec{
2000 sans: []string{"dns:*.foo.example.com"},
2001 },
2002 },
2003 {
2004 name: "far inner wildcard names are matched by subdomain permitted constraints",
2005 roots: []constraintsSpec{
2006 {
2007 ok: []string{"dns:foo.example.com"},
2008 },
2009 },
2010 intermediates: [][]constraintsSpec{
2011 {
2012 {},
2013 },
2014 },
2015 leaf: leafSpec{
2016 sans: []string{"dns:*.bar.foo.example.com"},
2017 },
2018 },
2019
2020 {
2021 name: "cross include should not match",
2022 roots: []constraintsSpec{
2023 {
2024 ok: []string{"dns:foo.example.com"},
2025 },
2026 },
2027 intermediates: [][]constraintsSpec{
2028 {
2029 {},
2030 },
2031 },
2032 leaf: leafSpec{
2033 sans: []string{"dns:*.bar.example.com"},
2034 },
2035 expectedError: "\"*.bar.example.com\" is not permitted by any constraint",
2036 },
2037 {
2038 name: "cross exclude should not match",
2039 roots: []constraintsSpec{
2040 {
2041 bad: []string{"dns:foo.example.com"},
2042 },
2043 },
2044 intermediates: [][]constraintsSpec{
2045 {
2046 {},
2047 },
2048 },
2049 leaf: leafSpec{
2050 sans: []string{"dns:*.bar.example.com"},
2051 },
2052 },
2053 {
2054 name: "subdomain exclusion blocks uppercase wildcard",
2055 roots: []constraintsSpec{{
2056 bad: []string{"dns:sub.example.com"},
2057 }},
2058 intermediates: [][]constraintsSpec{{{}}},
2059 leaf: leafSpec{
2060 sans: []string{"dns:*.EXAMPLE.COM"},
2061 },
2062 expectedError: "\"*.EXAMPLE.COM\" is excluded by constraint \"sub.example.com\"",
2063 },
2064 {
2065 name: "uppercase subdomain exclusion blocks lowercase wildcard",
2066 roots: []constraintsSpec{{
2067 bad: []string{"dns:SUB.EXAMPLE.COM"},
2068 }},
2069 intermediates: [][]constraintsSpec{{{}}},
2070 leaf: leafSpec{
2071 sans: []string{"dns:*.example.com"},
2072 },
2073 expectedError: "\"*.example.com\" is excluded by constraint \"sub.example.com\"",
2074 },
2075 }
2076
2077 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
2078 var serialBytes [16]byte
2079 rand.Read(serialBytes[:])
2080
2081 template := &Certificate{
2082 SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
2083 Subject: pkix.Name{
2084 CommonName: name,
2085 },
2086 NotBefore: time.Unix(1000, 0),
2087 NotAfter: time.Unix(2000, 0),
2088 KeyUsage: KeyUsageCertSign,
2089 BasicConstraintsValid: true,
2090 IsCA: true,
2091 }
2092
2093 if err := addConstraintsToTemplate(constraints, template); err != nil {
2094 return nil, err
2095 }
2096
2097 if parent == nil {
2098 parent = template
2099 }
2100 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
2101 if err != nil {
2102 return nil, err
2103 }
2104
2105 caCert, err := ParseCertificate(derBytes)
2106 if err != nil {
2107 return nil, err
2108 }
2109
2110 return caCert, nil
2111 }
2112
2113 func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
2114 var serialBytes [16]byte
2115 rand.Read(serialBytes[:])
2116
2117 template := &Certificate{
2118 SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
2119 Subject: pkix.Name{
2120 OrganizationalUnit: []string{"Leaf"},
2121 CommonName: leaf.cn,
2122 },
2123 NotBefore: time.Unix(1000, 0),
2124 NotAfter: time.Unix(2000, 0),
2125 KeyUsage: KeyUsageDigitalSignature,
2126 BasicConstraintsValid: true,
2127 IsCA: false,
2128 }
2129
2130 for _, name := range leaf.sans {
2131 switch {
2132 case strings.HasPrefix(name, "dns:"):
2133 template.DNSNames = append(template.DNSNames, name[4:])
2134
2135 case strings.HasPrefix(name, "ip:"):
2136 ip := net.ParseIP(name[3:])
2137 if ip == nil {
2138 return nil, fmt.Errorf("cannot parse IP %q", name[3:])
2139 }
2140 template.IPAddresses = append(template.IPAddresses, ip)
2141
2142 case strings.HasPrefix(name, "invalidip:"):
2143 ipBytes, err := hex.DecodeString(name[10:])
2144 if err != nil {
2145 return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
2146 }
2147 template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
2148
2149 case strings.HasPrefix(name, "email:"):
2150 template.EmailAddresses = append(template.EmailAddresses, name[6:])
2151
2152 case strings.HasPrefix(name, "uri:"):
2153 uri, err := url.Parse(name[4:])
2154 if err != nil {
2155 return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
2156 }
2157 template.URIs = append(template.URIs, uri)
2158
2159 case strings.HasPrefix(name, "unknown:"):
2160
2161
2162
2163 if len(leaf.sans) != 1 {
2164 panic("when using unknown name types, it must be the sole name")
2165 }
2166
2167 template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
2168 Id: []int{2, 5, 29, 17},
2169 Value: []byte{
2170 0x30,
2171 3,
2172 9,
2173 1,
2174 1,
2175 },
2176 })
2177
2178 default:
2179 return nil, fmt.Errorf("unknown name type %q", name)
2180 }
2181 }
2182
2183 var err error
2184 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
2185 return nil, err
2186 }
2187
2188 if parent == nil {
2189 parent = template
2190 }
2191
2192 derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
2193 if err != nil {
2194 return nil, err
2195 }
2196
2197 return ParseCertificate(derBytes)
2198 }
2199
2200 func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
2201 appendConstraint := func(contents []byte, tag uint8) []byte {
2202 contents = append(contents, tag|32 |0x80 )
2203 contents = append(contents, byte(4+len(constraint)) )
2204 contents = append(contents, 0x30 )
2205 contents = append(contents, byte(2+len(constraint)) )
2206 contents = append(contents, byte(typeNum) )
2207 contents = append(contents, byte(len(constraint)))
2208 return append(contents, constraint...)
2209 }
2210
2211 var contents []byte
2212 if !isExcluded {
2213 contents = appendConstraint(contents, 0 )
2214 } else {
2215 contents = appendConstraint(contents, 1 )
2216 }
2217
2218 var value []byte
2219 value = append(value, 0x30 )
2220 value = append(value, byte(len(contents)))
2221 value = append(value, contents...)
2222
2223 return pkix.Extension{
2224 Id: []int{2, 5, 29, 30},
2225 Value: value,
2226 }
2227 }
2228
2229 func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
2230 parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
2231 for _, constraint := range constraints {
2232 switch {
2233 case strings.HasPrefix(constraint, "dns:"):
2234 dnsNames = append(dnsNames, constraint[4:])
2235
2236 case strings.HasPrefix(constraint, "ip:"):
2237 _, ipNet, err := net.ParseCIDR(constraint[3:])
2238 if err != nil {
2239 return nil, nil, nil, nil, err
2240 }
2241 ips = append(ips, ipNet)
2242
2243 case strings.HasPrefix(constraint, "email:"):
2244 emailAddrs = append(emailAddrs, constraint[6:])
2245
2246 case strings.HasPrefix(constraint, "uri:"):
2247 uriDomains = append(uriDomains, constraint[4:])
2248
2249 default:
2250 return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
2251 }
2252 }
2253
2254 return dnsNames, ips, emailAddrs, uriDomains, err
2255 }
2256
2257 handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
2258 switch {
2259 case constraint == "unknown:":
2260 template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 , []byte{1}, isExcluded))
2261
2262 default:
2263 return false
2264 }
2265
2266 return true
2267 }
2268
2269 if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
2270 if handleSpecialConstraint(constraints.ok[0], false) {
2271 return nil
2272 }
2273 }
2274
2275 if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
2276 if handleSpecialConstraint(constraints.bad[0], true) {
2277 return nil
2278 }
2279 }
2280
2281 var err error
2282 template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
2283 if err != nil {
2284 return err
2285 }
2286
2287 template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
2288 if err != nil {
2289 return err
2290 }
2291
2292 if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
2293 return err
2294 }
2295
2296 return nil
2297 }
2298
2299 func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
2300 for _, s := range ekuStrs {
2301 switch s {
2302 case "serverAuth":
2303 ekus = append(ekus, ExtKeyUsageServerAuth)
2304 case "clientAuth":
2305 ekus = append(ekus, ExtKeyUsageClientAuth)
2306 case "email":
2307 ekus = append(ekus, ExtKeyUsageEmailProtection)
2308 case "netscapeSGC":
2309 ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
2310 case "msSGC":
2311 ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
2312 case "any":
2313 ekus = append(ekus, ExtKeyUsageAny)
2314 case "other":
2315 unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
2316 default:
2317 return nil, nil, fmt.Errorf("unknown EKU %q", s)
2318 }
2319 }
2320
2321 return
2322 }
2323
2324 func TestConstraintCases(t *testing.T) {
2325 privateKeys := sync.Pool{
2326 New: func() any {
2327 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2328 if err != nil {
2329 panic(err)
2330 }
2331 return priv
2332 },
2333 }
2334
2335 for i, test := range nameConstraintsTests {
2336 t.Run(test.name, func(t *testing.T) {
2337 rootPool := NewCertPool()
2338 rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
2339 rootName := "Root " + strconv.Itoa(i)
2340
2341
2342
2343 keys := []*ecdsa.PrivateKey{rootKey}
2344
2345
2346
2347
2348
2349
2350
2351 var parent *Certificate
2352 parentKey := rootKey
2353
2354 for _, root := range test.roots {
2355 rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
2356 if err != nil {
2357 t.Fatalf("failed to create root: %s", err)
2358 }
2359
2360 parent = rootCert
2361 rootPool.AddCert(rootCert)
2362 }
2363
2364 intermediatePool := NewCertPool()
2365
2366 for level, intermediates := range test.intermediates {
2367 levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
2368 keys = append(keys, levelKey)
2369 levelName := "Intermediate level " + strconv.Itoa(level)
2370 var last *Certificate
2371
2372 for _, intermediate := range intermediates {
2373 caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
2374 if err != nil {
2375 t.Fatalf("failed to create %q: %s", levelName, err)
2376 }
2377
2378 last = caCert
2379 intermediatePool.AddCert(caCert)
2380 }
2381
2382 parent = last
2383 parentKey = levelKey
2384 }
2385
2386 leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
2387 keys = append(keys, leafKey)
2388
2389 leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
2390 if err != nil {
2391 t.Fatalf("cannot create leaf: %s", err)
2392 }
2393
2394
2395
2396 if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
2397 output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
2398 if err == nil && len(test.expectedError) > 0 {
2399 t.Error("unexpectedly succeeded against OpenSSL")
2400 if debugOpenSSLFailure {
2401 return
2402 }
2403 }
2404
2405 if err != nil {
2406 if _, ok := err.(*exec.ExitError); !ok {
2407 t.Errorf("OpenSSL failed to run: %s", err)
2408 } else if len(test.expectedError) == 0 {
2409 t.Errorf("OpenSSL unexpectedly failed: %v", output)
2410 if debugOpenSSLFailure {
2411 return
2412 }
2413 }
2414 }
2415 }
2416
2417 verifyOpts := VerifyOptions{
2418 Roots: rootPool,
2419 Intermediates: intermediatePool,
2420 CurrentTime: time.Unix(1500, 0),
2421 KeyUsages: test.requestedEKUs,
2422 }
2423 _, err = leafCert.Verify(verifyOpts)
2424
2425 logInfo := false
2426 if len(test.expectedError) == 0 {
2427 if err != nil {
2428 t.Errorf("unexpected failure: %s", err)
2429 } else {
2430 logInfo = false
2431 }
2432 } else {
2433 if err == nil {
2434 t.Error("unexpected success")
2435 } else if !strings.Contains(err.Error(), test.expectedError) {
2436 t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
2437 } else {
2438 logInfo = false
2439 }
2440 }
2441
2442 if logInfo {
2443 certAsPEM := func(cert *Certificate) string {
2444 var buf bytes.Buffer
2445 pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
2446 return buf.String()
2447 }
2448 t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
2449 if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
2450 for ii, intermediate := range intermediates {
2451 t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
2452 }
2453 }
2454 t.Errorf("leaf:\n%s", certAsPEM(leafCert))
2455 }
2456
2457 for _, key := range keys {
2458 privateKeys.Put(key)
2459 }
2460 })
2461 }
2462 }
2463
2464 func TestNameConstraintIPNonZeroHostBits(t *testing.T) {
2465 rootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2466 if err != nil {
2467 t.Fatal(err)
2468 }
2469 leafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2470 if err != nil {
2471 t.Fatal(err)
2472 }
2473
2474
2475
2476
2477 subtree := func(b ...byte) []byte {
2478 gn := append([]byte{0x87, byte(len(b))}, b...)
2479 return append([]byte{0x30, byte(len(gn))}, gn...)
2480 }
2481 var subtrees []byte
2482 subtrees = append(subtrees, subtree(10, 0, 0, 0, 255, 255, 255, 252)...)
2483 subtrees = append(subtrees, subtree(10, 10, 10, 10, 255, 255, 0, 0)...)
2484 excluded := append([]byte{0xa1, byte(len(subtrees))}, subtrees...)
2485 ncValue := append([]byte{0x30, byte(len(excluded))}, excluded...)
2486
2487 var serial [16]byte
2488 rand.Read(serial[:])
2489 rootTmpl := &Certificate{
2490 SerialNumber: new(big.Int).SetBytes(serial[:]),
2491 Subject: pkix.Name{CommonName: "Root"},
2492 NotBefore: time.Unix(1000, 0),
2493 NotAfter: time.Unix(2000, 0),
2494 KeyUsage: KeyUsageCertSign,
2495 BasicConstraintsValid: true,
2496 IsCA: true,
2497 ExtraExtensions: []pkix.Extension{
2498 {Id: []int{2, 5, 29, 30}, Critical: true, Value: ncValue},
2499 },
2500 }
2501 rootDER, err := CreateCertificate(rand.Reader, rootTmpl, rootTmpl, &rootKey.PublicKey, rootKey)
2502 if err != nil {
2503 t.Fatal(err)
2504 }
2505 root, err := ParseCertificate(rootDER)
2506 if err != nil {
2507 t.Fatal(err)
2508 }
2509
2510
2511 if len(root.ExcludedIPRanges) != 2 {
2512 t.Fatalf("got %d excluded IP ranges, want 2", len(root.ExcludedIPRanges))
2513 }
2514 if got := root.ExcludedIPRanges[1].IP; !got.Equal(net.IP{10, 10, 10, 10}) {
2515 t.Errorf("excluded range IP = %v, want 10.10.10.10", got)
2516 }
2517
2518 leaf, err := makeConstraintsLeafCert(leafSpec{sans: []string{"ip:10.10.0.1"}}, leafKey, root, rootKey)
2519 if err != nil {
2520 t.Fatal(err)
2521 }
2522
2523 roots := NewCertPool()
2524 roots.AddCert(root)
2525 if _, err := leaf.Verify(VerifyOptions{Roots: roots, CurrentTime: time.Unix(1500, 0)}); err == nil {
2526 t.Error("leaf with IP SAN inside excluded range was accepted")
2527 } else if !strings.Contains(err.Error(), "excluded by constraint") {
2528 t.Errorf("got error %q, want excluded-by-constraint", err)
2529 }
2530 }
2531
2532 func writePEMsToTempFile(certs []*Certificate) *os.File {
2533 file, err := os.CreateTemp("", "name_constraints_test")
2534 if err != nil {
2535 panic("cannot create tempfile")
2536 }
2537
2538 pemBlock := &pem.Block{Type: "CERTIFICATE"}
2539 for _, cert := range certs {
2540 pemBlock.Bytes = cert.Raw
2541 pem.Encode(file, pemBlock)
2542 }
2543
2544 return file
2545 }
2546
2547 func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
2548 args := []string{"verify", "-no_check_time"}
2549
2550 rootsFile := writePEMsToTempFile(allCerts(t, roots))
2551 if debugOpenSSLFailure {
2552 println("roots file:", rootsFile.Name())
2553 } else {
2554 defer os.Remove(rootsFile.Name())
2555 }
2556 args = append(args, "-CAfile", rootsFile.Name())
2557
2558 if intermediates.len() > 0 {
2559 intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
2560 if debugOpenSSLFailure {
2561 println("intermediates file:", intermediatesFile.Name())
2562 } else {
2563 defer os.Remove(intermediatesFile.Name())
2564 }
2565 args = append(args, "-untrusted", intermediatesFile.Name())
2566 }
2567
2568 leafFile := writePEMsToTempFile([]*Certificate{leaf})
2569 if debugOpenSSLFailure {
2570 println("leaf file:", leafFile.Name())
2571 } else {
2572 defer os.Remove(leafFile.Name())
2573 }
2574 args = append(args, leafFile.Name())
2575
2576 cmd := testenv.Command(t, "openssl", args...)
2577 out, err := cmd.CombinedOutput()
2578 return string(out), err
2579 }
2580
2581 var rfc2821Tests = []struct {
2582 in string
2583 localPart, domain string
2584 }{
2585 {"foo@example.com", "foo", "example.com"},
2586 {"@example.com", "", ""},
2587 {"\"@example.com", "", ""},
2588 {"\"\"@example.com", "", "example.com"},
2589 {"\"a\"@example.com", "a", "example.com"},
2590 {"\"\\a\"@example.com", "a", "example.com"},
2591 {"a\"@example.com", "", ""},
2592 {"foo..bar@example.com", "", ""},
2593 {".foo.bar@example.com", "", ""},
2594 {"foo.bar.@example.com", "", ""},
2595 {"|{}?'@example.com", "|{}?'", "example.com"},
2596 {"a@b@c.com", "", ""},
2597
2598
2599 {"Abc\\@def@example.com", "Abc@def", "example.com"},
2600 {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
2601 {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
2602 {"\"Abc@def\"@example.com", "Abc@def", "example.com"},
2603 {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
2604 {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
2605 {"$A12345@example.com", "$A12345", "example.com"},
2606 {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
2607 {"_somename@example.com", "_somename", "example.com"},
2608 }
2609
2610 func TestRFC2821Parsing(t *testing.T) {
2611 for i, test := range rfc2821Tests {
2612 mailbox, ok := parseRFC2821Mailbox(test.in)
2613 expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
2614
2615 if ok && expectedFailure {
2616 t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
2617 continue
2618 }
2619
2620 if !ok && !expectedFailure {
2621 t.Errorf("#%d: unexpected failure for %q", i, test.in)
2622 continue
2623 }
2624
2625 if !ok {
2626 continue
2627 }
2628
2629 if mailbox.local != test.localPart || mailbox.domain != test.domain {
2630 t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
2631 }
2632 }
2633 }
2634
2635 func TestBadNamesInConstraints(t *testing.T) {
2636 constraintParseError := func(err error) bool {
2637 str := err.Error()
2638 return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
2639 }
2640
2641 encodingError := func(err error) bool {
2642 return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
2643 }
2644
2645
2646 badNames := []struct {
2647 name string
2648 matcher func(error) bool
2649 }{
2650 {"dns:foo.com.", constraintParseError},
2651 {"email:abc@foo.com.", constraintParseError},
2652 {"email:foo.com.", constraintParseError},
2653 {"uri:example.com.", constraintParseError},
2654 {"uri:1.2.3.4", constraintParseError},
2655 {"uri:ffff::1", constraintParseError},
2656 {"dns:not–hyphen.com", encodingError},
2657 {"email:foo@not–hyphen.com", encodingError},
2658 {"uri:not–hyphen.com", encodingError},
2659 }
2660
2661 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2662 if err != nil {
2663 panic(err)
2664 }
2665
2666 for _, test := range badNames {
2667 _, err := makeConstraintsCACert(constraintsSpec{
2668 ok: []string{test.name},
2669 }, "TestAbsoluteNamesInConstraints", priv, nil, priv)
2670
2671 if err == nil {
2672 t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
2673 continue
2674 } else {
2675 if !test.matcher(err) {
2676 t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
2677 }
2678 }
2679 }
2680 }
2681
2682 func TestBadNamesInSANs(t *testing.T) {
2683
2684
2685
2686 badNames := []string{
2687 "uri:https://example.com./dsf",
2688 "invalidip:0102",
2689 "invalidip:0102030405",
2690 }
2691
2692 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2693 if err != nil {
2694 panic(err)
2695 }
2696
2697 for _, badName := range badNames {
2698 _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
2699
2700 if err == nil {
2701 t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
2702 continue
2703 }
2704
2705 if str := err.Error(); !strings.Contains(str, "cannot parse ") {
2706 t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
2707 }
2708 }
2709 }
2710
View as plain text