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