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.
31 // testNameConstraintsAgainstOpenSSL can be set to true to run tests
32 // against the system OpenSSL. This is disabled by default because Go
33 // cannot depend on having OpenSSL installed at testing time.
34 testNameConstraintsAgainstOpenSSL
= false
36 // debugOpenSSLFailure can be set to true, when
37 // testNameConstraintsAgainstOpenSSL is also true, to cause
38 // intermediate files to be preserved for debugging.
39 debugOpenSSLFailure
= false
42 type nameConstraintsTest
struct {
43 roots
[]constraintsSpec
44 intermediates
[][]constraintsSpec
46 requestedEKUs
[]ExtKeyUsage
51 type constraintsSpec
struct {
57 type leafSpec
struct {
62 var nameConstraintsTests
= []nameConstraintsTest
{
63 // #0: dummy test for the certificate generation process itself.
65 roots
: []constraintsSpec
{
69 sans
: []string{"dns:example.com"},
73 // #1: dummy test for the certificate generation process itself: single
74 // level of intermediate.
76 roots
: []constraintsSpec
{
79 intermediates
: [][]constraintsSpec
{
85 sans
: []string{"dns:example.com"},
89 // #2: dummy test for the certificate generation process itself: two
90 // levels of intermediates.
92 roots
: []constraintsSpec
{
95 intermediates
: [][]constraintsSpec
{
104 sans
: []string{"dns:example.com"},
108 // #3: matching DNS constraint in root
110 roots
: []constraintsSpec
{
112 ok
: []string{"dns:example.com"},
115 intermediates
: [][]constraintsSpec
{
121 sans
: []string{"dns:example.com"},
125 // #4: matching DNS constraint in intermediate.
127 roots
: []constraintsSpec
{
130 intermediates
: [][]constraintsSpec
{
133 ok
: []string{"dns:example.com"},
138 sans
: []string{"dns:example.com"},
142 // #5: .example.com only matches subdomains.
144 roots
: []constraintsSpec
{
146 ok
: []string{"dns:.example.com"},
149 intermediates
: [][]constraintsSpec
{
155 sans
: []string{"dns:example.com"},
157 expectedError
: "\"example.com\" is not permitted",
160 // #6: .example.com matches subdomains.
162 roots
: []constraintsSpec
{
165 intermediates
: [][]constraintsSpec
{
168 ok
: []string{"dns:.example.com"},
173 sans
: []string{"dns:foo.example.com"},
177 // #7: .example.com matches multiple levels of subdomains
179 roots
: []constraintsSpec
{
181 ok
: []string{"dns:.example.com"},
184 intermediates
: [][]constraintsSpec
{
190 sans
: []string{"dns:foo.bar.example.com"},
194 // #8: specifying a permitted list of names does not exclude other name
197 roots
: []constraintsSpec
{
199 ok
: []string{"dns:.example.com"},
202 intermediates
: [][]constraintsSpec
{
208 sans
: []string{"ip:10.1.1.1"},
212 // #9: specifying a permitted list of names does not exclude other name
215 roots
: []constraintsSpec
{
217 ok
: []string{"ip:10.0.0.0/8"},
220 intermediates
: [][]constraintsSpec
{
226 sans
: []string{"dns:example.com"},
230 // #10: intermediates can try to permit other names, which isn't
231 // forbidden if the leaf doesn't mention them. I.e. name constraints
232 // apply to names, not constraints themselves.
234 roots
: []constraintsSpec
{
236 ok
: []string{"dns:example.com"},
239 intermediates
: [][]constraintsSpec
{
242 ok
: []string{"dns:example.com", "dns:foo.com"},
247 sans
: []string{"dns:example.com"},
251 // #11: intermediates cannot add permitted names that the root doesn't
254 roots
: []constraintsSpec
{
256 ok
: []string{"dns:example.com"},
259 intermediates
: [][]constraintsSpec
{
262 ok
: []string{"dns:example.com", "dns:foo.com"},
267 sans
: []string{"dns:foo.com"},
269 expectedError
: "\"foo.com\" is not permitted",
272 // #12: intermediates can further limit their scope if they wish.
274 roots
: []constraintsSpec
{
276 ok
: []string{"dns:.example.com"},
279 intermediates
: [][]constraintsSpec
{
282 ok
: []string{"dns:.bar.example.com"},
287 sans
: []string{"dns:foo.bar.example.com"},
291 // #13: intermediates can further limit their scope and that limitation
294 roots
: []constraintsSpec
{
296 ok
: []string{"dns:.example.com"},
299 intermediates
: [][]constraintsSpec
{
302 ok
: []string{"dns:.bar.example.com"},
307 sans
: []string{"dns:foo.notbar.example.com"},
309 expectedError
: "\"foo.notbar.example.com\" is not permitted",
312 // #14: roots can exclude subtrees and that doesn't affect other names.
314 roots
: []constraintsSpec
{
316 bad
: []string{"dns:.example.com"},
319 intermediates
: [][]constraintsSpec
{
325 sans
: []string{"dns:foo.com"},
329 // #15: roots exclusions are effective.
331 roots
: []constraintsSpec
{
333 bad
: []string{"dns:.example.com"},
336 intermediates
: [][]constraintsSpec
{
342 sans
: []string{"dns:foo.example.com"},
344 expectedError
: "\"foo.example.com\" is excluded",
347 // #16: intermediates can also exclude names and that doesn't affect
350 roots
: []constraintsSpec
{
353 intermediates
: [][]constraintsSpec
{
356 bad
: []string{"dns:.example.com"},
361 sans
: []string{"dns:foo.com"},
365 // #17: intermediate exclusions are effective.
367 roots
: []constraintsSpec
{
370 intermediates
: [][]constraintsSpec
{
373 bad
: []string{"dns:.example.com"},
378 sans
: []string{"dns:foo.example.com"},
380 expectedError
: "\"foo.example.com\" is excluded",
383 // #18: having an exclusion doesn't prohibit other types of names.
385 roots
: []constraintsSpec
{
387 bad
: []string{"dns:.example.com"},
390 intermediates
: [][]constraintsSpec
{
396 sans
: []string{"dns:foo.com", "ip:10.1.1.1"},
400 // #19: IP-based exclusions are permitted and don't affect unrelated IP
403 roots
: []constraintsSpec
{
405 bad
: []string{"ip:10.0.0.0/8"},
408 intermediates
: [][]constraintsSpec
{
414 sans
: []string{"ip:192.168.1.1"},
418 // #20: IP-based exclusions are effective
420 roots
: []constraintsSpec
{
422 bad
: []string{"ip:10.0.0.0/8"},
425 intermediates
: [][]constraintsSpec
{
431 sans
: []string{"ip:10.0.0.1"},
433 expectedError
: "\"10.0.0.1\" is excluded",
436 // #21: intermediates can further constrain IP ranges.
438 roots
: []constraintsSpec
{
440 bad
: []string{"ip:0.0.0.0/1"},
443 intermediates
: [][]constraintsSpec
{
446 bad
: []string{"ip:11.0.0.0/8"},
451 sans
: []string{"ip:11.0.0.1"},
453 expectedError
: "\"11.0.0.1\" is excluded",
456 // #22: when multiple intermediates are present, chain building can
457 // avoid intermediates with incompatible constraints.
459 roots
: []constraintsSpec
{
462 intermediates
: [][]constraintsSpec
{
465 ok
: []string{"dns:.foo.com"},
468 ok
: []string{"dns:.example.com"},
473 sans
: []string{"dns:foo.example.com"},
475 noOpenSSL
: true, // OpenSSL's chain building is not informed by constraints.
478 // #23: (same as the previous test, but in the other order in ensure
479 // that we don't pass it by luck.)
481 roots
: []constraintsSpec
{
484 intermediates
: [][]constraintsSpec
{
487 ok
: []string{"dns:.example.com"},
490 ok
: []string{"dns:.foo.com"},
495 sans
: []string{"dns:foo.example.com"},
497 noOpenSSL
: true, // OpenSSL's chain building is not informed by constraints.
500 // #24: when multiple roots are valid, chain building can avoid roots
501 // with incompatible constraints.
503 roots
: []constraintsSpec
{
506 ok
: []string{"dns:foo.com"},
509 intermediates
: [][]constraintsSpec
{
515 sans
: []string{"dns:example.com"},
517 noOpenSSL
: true, // OpenSSL's chain building is not informed by constraints.
520 // #25: (same as the previous test, but in the other order in ensure
521 // that we don't pass it by luck.)
523 roots
: []constraintsSpec
{
525 ok
: []string{"dns:foo.com"},
529 intermediates
: [][]constraintsSpec
{
535 sans
: []string{"dns:example.com"},
537 noOpenSSL
: true, // OpenSSL's chain building is not informed by constraints.
540 // #26: chain building can find a valid path even with multiple levels
541 // of alternative intermediates and alternative roots.
543 roots
: []constraintsSpec
{
545 ok
: []string{"dns:foo.com"},
548 ok
: []string{"dns:example.com"},
552 intermediates
: [][]constraintsSpec
{
556 ok
: []string{"dns:foo.com"},
562 ok
: []string{"dns:foo.com"},
567 sans
: []string{"dns:bar.com"},
569 noOpenSSL
: true, // OpenSSL's chain building is not informed by constraints.
572 // #27: chain building doesn't get stuck when there is no valid path.
574 roots
: []constraintsSpec
{
576 ok
: []string{"dns:foo.com"},
579 ok
: []string{"dns:example.com"},
582 intermediates
: [][]constraintsSpec
{
586 ok
: []string{"dns:foo.com"},
591 ok
: []string{"dns:bar.com"},
594 ok
: []string{"dns:foo.com"},
599 sans
: []string{"dns:bar.com"},
601 expectedError
: "\"bar.com\" is not permitted",
604 // #28: unknown name types don't cause a problem without constraints.
606 roots
: []constraintsSpec
{
609 intermediates
: [][]constraintsSpec
{
615 sans
: []string{"unknown:"},
619 // #29: unknown name types are allowed even in constrained chains.
621 roots
: []constraintsSpec
{
623 ok
: []string{"dns:foo.com", "dns:.foo.com"},
626 intermediates
: [][]constraintsSpec
{
632 sans
: []string{"unknown:"},
636 // #30: without SANs, a certificate is rejected in a constrained chain.
638 roots
: []constraintsSpec
{
640 ok
: []string{"dns:foo.com", "dns:.foo.com"},
643 intermediates
: [][]constraintsSpec
{
651 expectedError
: "leaf doesn't have a SAN extension",
652 noOpenSSL
: true, // OpenSSL doesn't require SANs in this case.
655 // #31: IPv6 addresses work in constraints: roots can permit them as
658 roots
: []constraintsSpec
{
660 ok
: []string{"ip:2000:abcd::/32"},
663 intermediates
: [][]constraintsSpec
{
669 sans
: []string{"ip:2000:abcd:1234::"},
673 // #32: IPv6 addresses work in constraints: root restrictions are
676 roots
: []constraintsSpec
{
678 ok
: []string{"ip:2000:abcd::/32"},
681 intermediates
: [][]constraintsSpec
{
687 sans
: []string{"ip:2000:1234:abcd::"},
689 expectedError
: "\"2000:1234:abcd::\" is not permitted",
692 // #33: An IPv6 permitted subtree doesn't affect DNS names.
694 roots
: []constraintsSpec
{
696 ok
: []string{"ip:2000:abcd::/32"},
699 intermediates
: [][]constraintsSpec
{
705 sans
: []string{"ip:2000:abcd::", "dns:foo.com"},
709 // #34: IPv6 exclusions don't affect unrelated addresses.
711 roots
: []constraintsSpec
{
713 bad
: []string{"ip:2000:abcd::/32"},
716 intermediates
: [][]constraintsSpec
{
722 sans
: []string{"ip:2000:1234::"},
726 // #35: IPv6 exclusions are effective.
728 roots
: []constraintsSpec
{
730 bad
: []string{"ip:2000:abcd::/32"},
733 intermediates
: [][]constraintsSpec
{
739 sans
: []string{"ip:2000:abcd::"},
741 expectedError
: "\"2000:abcd::\" is excluded",
744 // #36: IPv6 constraints do not permit IPv4 addresses.
746 roots
: []constraintsSpec
{
748 ok
: []string{"ip:2000:abcd::/32"},
751 intermediates
: [][]constraintsSpec
{
757 sans
: []string{"ip:10.0.0.1"},
759 expectedError
: "\"10.0.0.1\" is not permitted",
762 // #37: IPv4 constraints do not permit IPv6 addresses.
764 roots
: []constraintsSpec
{
766 ok
: []string{"ip:10.0.0.0/8"},
769 intermediates
: [][]constraintsSpec
{
775 sans
: []string{"ip:2000:abcd::"},
777 expectedError
: "\"2000:abcd::\" is not permitted",
780 // #38: an exclusion of an unknown type doesn't affect other names.
782 roots
: []constraintsSpec
{
784 bad
: []string{"unknown:"},
787 intermediates
: [][]constraintsSpec
{
793 sans
: []string{"dns:example.com"},
797 // #39: a permitted subtree of an unknown type doesn't affect other
800 roots
: []constraintsSpec
{
802 ok
: []string{"unknown:"},
805 intermediates
: [][]constraintsSpec
{
811 sans
: []string{"dns:example.com"},
815 // #40: exact email constraints work
817 roots
: []constraintsSpec
{
819 ok
: []string{"email:foo@example.com"},
822 intermediates
: [][]constraintsSpec
{
828 sans
: []string{"email:foo@example.com"},
832 // #41: exact email constraints are effective
834 roots
: []constraintsSpec
{
836 ok
: []string{"email:foo@example.com"},
839 intermediates
: [][]constraintsSpec
{
845 sans
: []string{"email:bar@example.com"},
847 expectedError
: "\"bar@example.com\" is not permitted",
850 // #42: email canonicalisation works.
852 roots
: []constraintsSpec
{
854 ok
: []string{"email:foo@example.com"},
857 intermediates
: [][]constraintsSpec
{
863 sans
: []string{"email:\"\\f\\o\\o\"@example.com"},
865 noOpenSSL
: true, // OpenSSL doesn't canonicalise email addresses before matching
868 // #43: limiting email addresses to a host works.
870 roots
: []constraintsSpec
{
872 ok
: []string{"email:example.com"},
875 intermediates
: [][]constraintsSpec
{
881 sans
: []string{"email:foo@example.com"},
885 // #44: a leading dot matches hosts one level deep
887 roots
: []constraintsSpec
{
889 ok
: []string{"email:.example.com"},
892 intermediates
: [][]constraintsSpec
{
898 sans
: []string{"email:foo@sub.example.com"},
902 // #45: a leading dot does not match the host itself
904 roots
: []constraintsSpec
{
906 ok
: []string{"email:.example.com"},
909 intermediates
: [][]constraintsSpec
{
915 sans
: []string{"email:foo@example.com"},
917 expectedError
: "\"foo@example.com\" is not permitted",
920 // #46: a leading dot also matches two (or more) levels deep.
922 roots
: []constraintsSpec
{
924 ok
: []string{"email:.example.com"},
927 intermediates
: [][]constraintsSpec
{
933 sans
: []string{"email:foo@sub.sub.example.com"},
937 // #47: the local part of an email is case-sensitive
939 roots
: []constraintsSpec
{
941 ok
: []string{"email:foo@example.com"},
944 intermediates
: [][]constraintsSpec
{
950 sans
: []string{"email:Foo@example.com"},
952 expectedError
: "\"Foo@example.com\" is not permitted",
955 // #48: the domain part of an email is not case-sensitive
957 roots
: []constraintsSpec
{
959 ok
: []string{"email:foo@EXAMPLE.com"},
962 intermediates
: [][]constraintsSpec
{
968 sans
: []string{"email:foo@example.com"},
972 // #49: the domain part of a DNS constraint is also not case-sensitive.
974 roots
: []constraintsSpec
{
976 ok
: []string{"dns:EXAMPLE.com"},
979 intermediates
: [][]constraintsSpec
{
985 sans
: []string{"dns:example.com"},
989 // #50: URI constraints only cover the host part of the URI
991 roots
: []constraintsSpec
{
993 ok
: []string{"uri:example.com"},
996 intermediates
: [][]constraintsSpec
{
1003 "uri:http://example.com/bar",
1004 "uri:http://example.com:8080/",
1005 "uri:https://example.com/wibble#bar",
1010 // #51: URIs with IPs are rejected
1011 nameConstraintsTest
{
1012 roots
: []constraintsSpec
{
1014 ok
: []string{"uri:example.com"},
1017 intermediates
: [][]constraintsSpec
{
1023 sans
: []string{"uri:http://1.2.3.4/"},
1025 expectedError
: "URI with IP",
1028 // #52: URIs with IPs and ports are rejected
1029 nameConstraintsTest
{
1030 roots
: []constraintsSpec
{
1032 ok
: []string{"uri:example.com"},
1035 intermediates
: [][]constraintsSpec
{
1041 sans
: []string{"uri:http://1.2.3.4:43/"},
1043 expectedError
: "URI with IP",
1046 // #53: URIs with IPv6 addresses are also rejected
1047 nameConstraintsTest
{
1048 roots
: []constraintsSpec
{
1050 ok
: []string{"uri:example.com"},
1053 intermediates
: [][]constraintsSpec
{
1059 sans
: []string{"uri:http://[2006:abcd::1]/"},
1061 expectedError
: "URI with IP",
1064 // #54: URIs with IPv6 addresses with ports are also rejected
1065 nameConstraintsTest
{
1066 roots
: []constraintsSpec
{
1068 ok
: []string{"uri:example.com"},
1071 intermediates
: [][]constraintsSpec
{
1077 sans
: []string{"uri:http://[2006:abcd::1]:16/"},
1079 expectedError
: "URI with IP",
1082 // #55: URI constraints are effective
1083 nameConstraintsTest
{
1084 roots
: []constraintsSpec
{
1086 ok
: []string{"uri:example.com"},
1089 intermediates
: [][]constraintsSpec
{
1095 sans
: []string{"uri:http://bar.com/"},
1097 expectedError
: "\"http://bar.com/\" is not permitted",
1100 // #56: URI constraints are effective
1101 nameConstraintsTest
{
1102 roots
: []constraintsSpec
{
1104 bad
: []string{"uri:foo.com"},
1107 intermediates
: [][]constraintsSpec
{
1113 sans
: []string{"uri:http://foo.com/"},
1115 expectedError
: "\"http://foo.com/\" is excluded",
1118 // #57: URI constraints can allow subdomains
1119 nameConstraintsTest
{
1120 roots
: []constraintsSpec
{
1122 ok
: []string{"uri:.foo.com"},
1125 intermediates
: [][]constraintsSpec
{
1131 sans
: []string{"uri:http://www.foo.com/"},
1135 // #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4
1136 // version of that address.
1137 nameConstraintsTest
{
1138 roots
: []constraintsSpec
{
1140 bad
: []string{"ip:::ffff:1.2.3.4/128"},
1143 intermediates
: [][]constraintsSpec
{
1149 sans
: []string{"ip:1.2.3.4"},
1153 // #59: a URI constraint isn't matched by a URN.
1154 nameConstraintsTest
{
1155 roots
: []constraintsSpec
{
1157 ok
: []string{"uri:example.com"},
1160 intermediates
: [][]constraintsSpec
{
1166 sans
: []string{"uri:urn:example"},
1168 expectedError
: "URI with empty host",
1171 // #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses
1172 // too, even though IPv4 is mapped into the IPv6 range.
1173 nameConstraintsTest
{
1174 roots
: []constraintsSpec
{
1176 ok
: []string{"ip:1.2.3.0/24"},
1177 bad
: []string{"ip:::0/0"},
1180 intermediates
: [][]constraintsSpec
{
1186 sans
: []string{"ip:1.2.3.4"},
1190 // #61: omitting extended key usage in a CA certificate implies that
1192 nameConstraintsTest
{
1193 roots
: []constraintsSpec
{
1196 intermediates
: [][]constraintsSpec
{
1202 sans
: []string{"dns:example.com"},
1203 ekus
: []string{"serverAuth", "other"},
1207 // #62: The “any” EKU also means that any usage is ok.
1208 nameConstraintsTest
{
1209 roots
: []constraintsSpec
{
1212 intermediates
: [][]constraintsSpec
{
1215 ekus
: []string{"any"},
1220 sans
: []string{"dns:example.com"},
1221 ekus
: []string{"serverAuth", "other"},
1225 // #63: An intermediate with enumerated EKUs causes a failure if we
1226 // test for an EKU not in that set. (ServerAuth is required by
1228 nameConstraintsTest
{
1229 roots
: []constraintsSpec
{
1232 intermediates
: [][]constraintsSpec
{
1235 ekus
: []string{"email"},
1240 sans
: []string{"dns:example.com"},
1241 ekus
: []string{"serverAuth"},
1243 expectedError
: "incompatible key usage",
1246 // #64: an unknown EKU in the leaf doesn't break anything, even if it's not
1247 // correctly nested.
1248 nameConstraintsTest
{
1249 roots
: []constraintsSpec
{
1252 intermediates
: [][]constraintsSpec
{
1255 ekus
: []string{"email"},
1260 sans
: []string{"dns:example.com"},
1261 ekus
: []string{"other"},
1263 requestedEKUs
: []ExtKeyUsage
{ExtKeyUsageAny
},
1266 // #65: trying to add extra permitted key usages in an intermediate
1267 // (after a limitation in the root) is acceptable so long as the leaf
1268 // certificate doesn't use them.
1269 nameConstraintsTest
{
1270 roots
: []constraintsSpec
{
1272 ekus
: []string{"serverAuth"},
1275 intermediates
: [][]constraintsSpec
{
1278 ekus
: []string{"serverAuth", "email"},
1283 sans
: []string{"dns:example.com"},
1284 ekus
: []string{"serverAuth"},
1288 // #66: EKUs in roots are not ignored.
1289 nameConstraintsTest
{
1290 roots
: []constraintsSpec
{
1292 ekus
: []string{"email"},
1295 intermediates
: [][]constraintsSpec
{
1298 ekus
: []string{"serverAuth"},
1303 sans
: []string{"dns:example.com"},
1304 ekus
: []string{"serverAuth"},
1306 expectedError
: "incompatible key usage",
1309 // #67: in order to support COMODO chains, SGC key usages permit
1310 // serverAuth and clientAuth.
1311 nameConstraintsTest
{
1312 roots
: []constraintsSpec
{
1315 intermediates
: [][]constraintsSpec
{
1318 ekus
: []string{"netscapeSGC"},
1323 sans
: []string{"dns:example.com"},
1324 ekus
: []string{"serverAuth", "clientAuth"},
1328 // #68: in order to support COMODO chains, SGC key usages permit
1329 // serverAuth and clientAuth.
1330 nameConstraintsTest
{
1331 roots
: []constraintsSpec
{
1334 intermediates
: [][]constraintsSpec
{
1337 ekus
: []string{"msSGC"},
1342 sans
: []string{"dns:example.com"},
1343 ekus
: []string{"serverAuth", "clientAuth"},
1347 // #69: an empty DNS constraint should allow anything.
1348 nameConstraintsTest
{
1349 roots
: []constraintsSpec
{
1351 ok
: []string{"dns:"},
1354 intermediates
: [][]constraintsSpec
{
1360 sans
: []string{"dns:example.com"},
1364 // #70: an empty DNS constraint should also reject everything.
1365 nameConstraintsTest
{
1366 roots
: []constraintsSpec
{
1368 bad
: []string{"dns:"},
1371 intermediates
: [][]constraintsSpec
{
1377 sans
: []string{"dns:example.com"},
1379 expectedError
: "\"example.com\" is excluded",
1382 // #71: an empty email constraint should allow anything
1383 nameConstraintsTest
{
1384 roots
: []constraintsSpec
{
1386 ok
: []string{"email:"},
1389 intermediates
: [][]constraintsSpec
{
1395 sans
: []string{"email:foo@example.com"},
1399 // #72: an empty email constraint should also reject everything.
1400 nameConstraintsTest
{
1401 roots
: []constraintsSpec
{
1403 bad
: []string{"email:"},
1406 intermediates
: [][]constraintsSpec
{
1412 sans
: []string{"email:foo@example.com"},
1414 expectedError
: "\"foo@example.com\" is excluded",
1417 // #73: an empty URI constraint should allow anything
1418 nameConstraintsTest
{
1419 roots
: []constraintsSpec
{
1421 ok
: []string{"uri:"},
1424 intermediates
: [][]constraintsSpec
{
1430 sans
: []string{"uri:https://example.com/test"},
1434 // #74: an empty URI constraint should also reject everything.
1435 nameConstraintsTest
{
1436 roots
: []constraintsSpec
{
1438 bad
: []string{"uri:"},
1441 intermediates
: [][]constraintsSpec
{
1447 sans
: []string{"uri:https://example.com/test"},
1449 expectedError
: "\"https://example.com/test\" is excluded",
1452 // #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
1454 nameConstraintsTest
{
1455 roots
: []constraintsSpec
{
1458 intermediates
: [][]constraintsSpec
{
1464 sans
: []string{"dns:example.com"},
1465 ekus
: []string{"serverAuth"},
1467 requestedEKUs
: []ExtKeyUsage
{ExtKeyUsageClientAuth
},
1468 expectedError
: "incompatible key usage",
1471 // #76: However, MSSGC in a leaf should match a request for serverAuth.
1472 nameConstraintsTest
{
1473 roots
: []constraintsSpec
{
1476 intermediates
: [][]constraintsSpec
{
1482 sans
: []string{"dns:example.com"},
1483 ekus
: []string{"msSGC"},
1485 requestedEKUs
: []ExtKeyUsage
{ExtKeyUsageServerAuth
},
1488 // An invalid DNS SAN should be detected only at validation time so
1489 // that we can process CA certificates in the wild that have invalid SANs.
1490 // See https://github.com/golang/go/issues/23995
1492 // #77: an invalid DNS or mail SAN will not be detected if name constaint
1493 // checking is not triggered.
1494 nameConstraintsTest
{
1495 roots
: []constraintsSpec
{
1498 intermediates
: [][]constraintsSpec
{
1504 sans
: []string{"dns:this is invalid", "email:this @ is invalid"},
1508 // #78: an invalid DNS SAN will be detected if any name constraint checking
1510 nameConstraintsTest
{
1511 roots
: []constraintsSpec
{
1513 bad
: []string{"uri:"},
1516 intermediates
: [][]constraintsSpec
{
1522 sans
: []string{"dns:this is invalid"},
1524 expectedError
: "cannot parse dnsName",
1527 // #79: an invalid email SAN will be detected if any name constraint
1528 // checking is triggered.
1529 nameConstraintsTest
{
1530 roots
: []constraintsSpec
{
1532 bad
: []string{"uri:"},
1535 intermediates
: [][]constraintsSpec
{
1541 sans
: []string{"email:this @ is invalid"},
1543 expectedError
: "cannot parse rfc822Name",
1546 // #80: if several EKUs are requested, satisfying any of them is sufficient.
1547 nameConstraintsTest
{
1548 roots
: []constraintsSpec
{
1551 intermediates
: [][]constraintsSpec
{
1557 sans
: []string{"dns:example.com"},
1558 ekus
: []string{"email"},
1560 requestedEKUs
: []ExtKeyUsage
{ExtKeyUsageClientAuth
, ExtKeyUsageEmailProtection
},
1563 // #81: EKUs that are not asserted in VerifyOpts are not required to be
1565 nameConstraintsTest
{
1566 roots
: []constraintsSpec
{
1569 intermediates
: [][]constraintsSpec
{
1572 ekus
: []string{"serverAuth"},
1577 sans
: []string{"dns:example.com"},
1578 // There's no email EKU in the intermediate. This would be rejected if
1579 // full nesting was required.
1580 ekus
: []string{"email", "serverAuth"},
1585 func makeConstraintsCACert(constraints constraintsSpec
, name
string, key
*ecdsa
.PrivateKey
, parent
*Certificate
, parentKey
*ecdsa
.PrivateKey
) (*Certificate
, error
) {
1586 var serialBytes
[16]byte
1587 rand
.Read(serialBytes
[:])
1589 template
:= &Certificate
{
1590 SerialNumber
: new(big
.Int
).SetBytes(serialBytes
[:]),
1594 NotBefore
: time
.Unix(1000, 0),
1595 NotAfter
: time
.Unix(2000, 0),
1596 KeyUsage
: KeyUsageCertSign
,
1597 BasicConstraintsValid
: true,
1601 if err
:= addConstraintsToTemplate(constraints
, template
); err
!= nil {
1608 derBytes
, err
:= CreateCertificate(rand
.Reader
, template
, parent
, &key
.PublicKey
, parentKey
)
1613 caCert
, err
:= ParseCertificate(derBytes
)
1621 func makeConstraintsLeafCert(leaf leafSpec
, key
*ecdsa
.PrivateKey
, parent
*Certificate
, parentKey
*ecdsa
.PrivateKey
) (*Certificate
, error
) {
1622 var serialBytes
[16]byte
1623 rand
.Read(serialBytes
[:])
1625 template
:= &Certificate
{
1626 SerialNumber
: new(big
.Int
).SetBytes(serialBytes
[:]),
1628 // Don't set a CommonName because OpenSSL (at least) will try to
1629 // match it against name constraints.
1630 OrganizationalUnit
: []string{"Leaf"},
1632 NotBefore
: time
.Unix(1000, 0),
1633 NotAfter
: time
.Unix(2000, 0),
1634 KeyUsage
: KeyUsageDigitalSignature
,
1635 BasicConstraintsValid
: true,
1639 for _
, name
:= range leaf
.sans
{
1641 case strings
.HasPrefix(name
, "dns:"):
1642 template
.DNSNames
= append(template
.DNSNames
, name
[4:])
1644 case strings
.HasPrefix(name
, "ip:"):
1645 ip
:= net
.ParseIP(name
[3:])
1647 return nil, fmt
.Errorf("cannot parse IP %q", name
[3:])
1649 template
.IPAddresses
= append(template
.IPAddresses
, ip
)
1651 case strings
.HasPrefix(name
, "invalidip:"):
1652 ipBytes
, err
:= hex
.DecodeString(name
[10:])
1654 return nil, fmt
.Errorf("cannot parse invalid IP: %s", err
)
1656 template
.IPAddresses
= append(template
.IPAddresses
, net
.IP(ipBytes
))
1658 case strings
.HasPrefix(name
, "email:"):
1659 template
.EmailAddresses
= append(template
.EmailAddresses
, name
[6:])
1661 case strings
.HasPrefix(name
, "uri:"):
1662 uri
, err
:= url
.Parse(name
[4:])
1664 return nil, fmt
.Errorf("cannot parse URI %q: %s", name
[4:], err
)
1666 template
.URIs
= append(template
.URIs
, uri
)
1668 case strings
.HasPrefix(name
, "unknown:"):
1669 // This is a special case for testing unknown
1670 // name types. A custom SAN extension is
1671 // injected into the certificate.
1672 if len(leaf
.sans
) != 1 {
1673 panic("when using unknown name types, it must be the sole name")
1676 template
.ExtraExtensions
= append(template
.ExtraExtensions
, pkix
.Extension
{
1677 Id
: []int{2, 5, 29, 17},
1681 9, // undefined GeneralName type 9
1688 return nil, fmt
.Errorf("unknown name type %q", name
)
1693 if template
.ExtKeyUsage
, template
.UnknownExtKeyUsage
, err
= parseEKUs(leaf
.ekus
); err
!= nil {
1701 derBytes
, err
:= CreateCertificate(rand
.Reader
, template
, parent
, &key
.PublicKey
, parentKey
)
1706 return ParseCertificate(derBytes
)
1709 func customConstraintsExtension(typeNum
int, constraint
[]byte, isExcluded
bool) pkix
.Extension
{
1710 appendConstraint
:= func(contents
[]byte, tag
uint8) []byte {
1711 contents
= append(contents
, tag|
32 /* constructed */ |
0x80 /* context-specific */)
1712 contents
= append(contents
, byte(4+len(constraint
)) /* length */)
1713 contents
= append(contents
, 0x30 /* SEQUENCE */)
1714 contents
= append(contents
, byte(2+len(constraint
)) /* length */)
1715 contents
= append(contents
, byte(typeNum
) /* GeneralName type */)
1716 contents
= append(contents
, byte(len(constraint
)))
1717 return append(contents
, constraint
...)
1722 contents
= appendConstraint(contents
, 0 /* tag 0 for permitted */)
1724 contents
= appendConstraint(contents
, 1 /* tag 1 for excluded */)
1728 value
= append(value
, 0x30 /* SEQUENCE */)
1729 value
= append(value
, byte(len(contents
)))
1730 value
= append(value
, contents
...)
1732 return pkix
.Extension
{
1733 Id
: []int{2, 5, 29, 30},
1738 func addConstraintsToTemplate(constraints constraintsSpec
, template
*Certificate
) error
{
1739 parse
:= func(constraints
[]string) (dnsNames
[]string, ips
[]*net
.IPNet
, emailAddrs
[]string, uriDomains
[]string, err error
) {
1740 for _
, constraint
:= range constraints
{
1742 case strings
.HasPrefix(constraint
, "dns:"):
1743 dnsNames
= append(dnsNames
, constraint
[4:])
1745 case strings
.HasPrefix(constraint
, "ip:"):
1746 _
, ipNet
, err
:= net
.ParseCIDR(constraint
[3:])
1748 return nil, nil, nil, nil, err
1750 ips
= append(ips
, ipNet
)
1752 case strings
.HasPrefix(constraint
, "email:"):
1753 emailAddrs
= append(emailAddrs
, constraint
[6:])
1755 case strings
.HasPrefix(constraint
, "uri:"):
1756 uriDomains
= append(uriDomains
, constraint
[4:])
1759 return nil, nil, nil, nil, fmt
.Errorf("unknown constraint %q", constraint
)
1763 return dnsNames
, ips
, emailAddrs
, uriDomains
, err
1766 handleSpecialConstraint
:= func(constraint
string, isExcluded
bool) bool {
1768 case constraint
== "unknown:":
1769 template
.ExtraExtensions
= append(template
.ExtraExtensions
, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded
))
1778 if len(constraints
.ok
) == 1 && len(constraints
.bad
) == 0 {
1779 if handleSpecialConstraint(constraints
.ok
[0], false) {
1784 if len(constraints
.bad
) == 1 && len(constraints
.ok
) == 0 {
1785 if handleSpecialConstraint(constraints
.bad
[0], true) {
1791 template
.PermittedDNSDomains
, template
.PermittedIPRanges
, template
.PermittedEmailAddresses
, template
.PermittedURIDomains
, err
= parse(constraints
.ok
)
1796 template
.ExcludedDNSDomains
, template
.ExcludedIPRanges
, template
.ExcludedEmailAddresses
, template
.ExcludedURIDomains
, err
= parse(constraints
.bad
)
1801 if template
.ExtKeyUsage
, template
.UnknownExtKeyUsage
, err
= parseEKUs(constraints
.ekus
); err
!= nil {
1808 func parseEKUs(ekuStrs
[]string) (ekus
[]ExtKeyUsage
, unknowns
[]asn1
.ObjectIdentifier
, err error
) {
1809 for _
, s
:= range ekuStrs
{
1812 ekus
= append(ekus
, ExtKeyUsageServerAuth
)
1814 ekus
= append(ekus
, ExtKeyUsageClientAuth
)
1816 ekus
= append(ekus
, ExtKeyUsageEmailProtection
)
1818 ekus
= append(ekus
, ExtKeyUsageNetscapeServerGatedCrypto
)
1820 ekus
= append(ekus
, ExtKeyUsageMicrosoftServerGatedCrypto
)
1822 ekus
= append(ekus
, ExtKeyUsageAny
)
1824 unknowns
= append(unknowns
, asn1
.ObjectIdentifier
{2, 4, 1, 2, 3})
1826 return nil, nil, fmt
.Errorf("unknown EKU %q", s
)
1833 func TestConstraintCases(t
*testing
.T
) {
1834 privateKeys
:= sync
.Pool
{
1835 New
: func() interface{} {
1836 priv
, err
:= ecdsa
.GenerateKey(elliptic
.P256(), rand
.Reader
)
1844 for i
, test
:= range nameConstraintsTests
{
1845 rootPool
:= NewCertPool()
1846 rootKey
:= privateKeys
.Get().(*ecdsa
.PrivateKey
)
1847 rootName
:= "Root " + strconv
.Itoa(i
)
1849 // keys keeps track of all the private keys used in a given
1850 // test and puts them back in the privateKeys pool at the end.
1851 keys
:= []*ecdsa
.PrivateKey
{rootKey
}
1853 // At each level (root, intermediate(s), leaf), parent points to
1854 // an example parent certificate and parentKey the key for the
1855 // parent level. Since all certificates at a given level have
1856 // the same name and public key, any parent certificate is
1857 // sufficient to get the correct issuer name and authority
1859 var parent
*Certificate
1860 parentKey
:= rootKey
1862 for _
, root
:= range test
.roots
{
1863 rootCert
, err
:= makeConstraintsCACert(root
, rootName
, rootKey
, nil, rootKey
)
1865 t
.Fatalf("#%d: failed to create root: %s", i
, err
)
1869 rootPool
.AddCert(rootCert
)
1872 intermediatePool
:= NewCertPool()
1874 for level
, intermediates
:= range test
.intermediates
{
1875 levelKey
:= privateKeys
.Get().(*ecdsa
.PrivateKey
)
1876 keys
= append(keys
, levelKey
)
1877 levelName
:= "Intermediate level " + strconv
.Itoa(level
)
1878 var last
*Certificate
1880 for _
, intermediate
:= range intermediates
{
1881 caCert
, err
:= makeConstraintsCACert(intermediate
, levelName
, levelKey
, parent
, parentKey
)
1883 t
.Fatalf("#%d: failed to create %q: %s", i
, levelName
, err
)
1887 intermediatePool
.AddCert(caCert
)
1891 parentKey
= levelKey
1894 leafKey
:= privateKeys
.Get().(*ecdsa
.PrivateKey
)
1895 keys
= append(keys
, leafKey
)
1897 leafCert
, err
:= makeConstraintsLeafCert(test
.leaf
, leafKey
, parent
, parentKey
)
1899 t
.Fatalf("#%d: cannot create leaf: %s", i
, err
)
1902 if !test
.noOpenSSL
&& testNameConstraintsAgainstOpenSSL
{
1903 output
, err
:= testChainAgainstOpenSSL(leafCert
, intermediatePool
, rootPool
)
1904 if err
== nil && len(test
.expectedError
) > 0 {
1905 t
.Errorf("#%d: unexpectedly succeeded against OpenSSL", i
)
1906 if debugOpenSSLFailure
{
1912 if _
, ok
:= err
.(*exec
.ExitError
); !ok
{
1913 t
.Errorf("#%d: OpenSSL failed to run: %s", i
, err
)
1914 } else if len(test
.expectedError
) == 0 {
1915 t
.Errorf("#%d: OpenSSL unexpectedly failed: %q", i
, output
)
1916 if debugOpenSSLFailure
{
1923 verifyOpts
:= VerifyOptions
{
1925 Intermediates
: intermediatePool
,
1926 CurrentTime
: time
.Unix(1500, 0),
1927 KeyUsages
: test
.requestedEKUs
,
1929 _
, err
= leafCert
.Verify(verifyOpts
)
1932 if len(test
.expectedError
) == 0 {
1934 t
.Errorf("#%d: unexpected failure: %s", i
, err
)
1940 t
.Errorf("#%d: unexpected success", i
)
1941 } else if !strings
.Contains(err
.Error(), test
.expectedError
) {
1942 t
.Errorf("#%d: expected error containing %q, but got: %s", i
, test
.expectedError
, err
)
1949 certAsPEM
:= func(cert
*Certificate
) string {
1950 var buf bytes
.Buffer
1951 pem
.Encode(&buf
, &pem
.Block
{Type
: "CERTIFICATE", Bytes
: cert
.Raw
})
1952 return string(buf
.Bytes())
1954 t
.Errorf("#%d: root:\n%s", i
, certAsPEM(rootPool
.certs
[0]))
1955 t
.Errorf("#%d: leaf:\n%s", i
, certAsPEM(leafCert
))
1958 for _
, key
:= range keys
{
1959 privateKeys
.Put(key
)
1965 func writePEMsToTempFile(certs
[]*Certificate
) *os
.File
{
1966 file
, err
:= ioutil
.TempFile("", "name_constraints_test")
1968 panic("cannot create tempfile")
1971 pemBlock
:= &pem
.Block
{Type
: "CERTIFICATE"}
1972 for _
, cert
:= range certs
{
1973 pemBlock
.Bytes
= cert
.Raw
1974 pem
.Encode(file
, pemBlock
)
1980 func testChainAgainstOpenSSL(leaf
*Certificate
, intermediates
, roots
*CertPool
) (string, error
) {
1981 args
:= []string{"verify", "-no_check_time"}
1983 rootsFile
:= writePEMsToTempFile(roots
.certs
)
1984 if debugOpenSSLFailure
{
1985 println("roots file:", rootsFile
.Name())
1987 defer os
.Remove(rootsFile
.Name())
1989 args
= append(args
, "-CAfile", rootsFile
.Name())
1991 if len(intermediates
.certs
) > 0 {
1992 intermediatesFile
:= writePEMsToTempFile(intermediates
.certs
)
1993 if debugOpenSSLFailure
{
1994 println("intermediates file:", intermediatesFile
.Name())
1996 defer os
.Remove(intermediatesFile
.Name())
1998 args
= append(args
, "-untrusted", intermediatesFile
.Name())
2001 leafFile
:= writePEMsToTempFile([]*Certificate
{leaf
})
2002 if debugOpenSSLFailure
{
2003 println("leaf file:", leafFile
.Name())
2005 defer os
.Remove(leafFile
.Name())
2007 args
= append(args
, leafFile
.Name())
2009 var output bytes
.Buffer
2010 cmd
:= exec
.Command("openssl", args
...)
2011 cmd
.Stdout
= &output
2012 cmd
.Stderr
= &output
2015 return string(output
.Bytes()), err
2018 var rfc2821Tests
= []struct {
2020 localPart
, domain
string
2022 {"foo@example.com", "foo", "example.com"},
2023 {"@example.com", "", ""},
2024 {"\"@example.com", "", ""},
2025 {"\"\"@example.com", "", "example.com"},
2026 {"\"a\"@example.com", "a", "example.com"},
2027 {"\"\\a\"@example.com", "a", "example.com"},
2028 {"a\"@example.com", "", ""},
2029 {"foo..bar@example.com", "", ""},
2030 {".foo.bar@example.com", "", ""},
2031 {"foo.bar.@example.com", "", ""},
2032 {"|{}?'@example.com", "|{}?'", "example.com"},
2034 // Examples from RFC 3696
2035 {"Abc\\@def@example.com", "Abc@def", "example.com"},
2036 {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
2037 {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
2038 {"\"Abc@def\"@example.com", "Abc@def", "example.com"},
2039 {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
2040 {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
2041 {"$A12345@example.com", "$A12345", "example.com"},
2042 {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
2043 {"_somename@example.com", "_somename", "example.com"},
2046 func TestRFC2821Parsing(t
*testing
.T
) {
2047 for i
, test
:= range rfc2821Tests
{
2048 mailbox
, ok
:= parseRFC2821Mailbox(test
.in
)
2049 expectedFailure
:= len(test
.localPart
) == 0 && len(test
.domain
) == 0
2051 if ok
&& expectedFailure
{
2052 t
.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i
, test
.in
, mailbox
.local
, mailbox
.domain
)
2056 if !ok
&& !expectedFailure
{
2057 t
.Errorf("#%d: unexpected failure for %q", i
, test
.in
)
2065 if mailbox
.local
!= test
.localPart || mailbox
.domain
!= test
.domain
{
2066 t
.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i
, test
.in
, mailbox
.local
, mailbox
.domain
, test
.localPart
, test
.domain
)
2071 func TestBadNamesInConstraints(t
*testing
.T
) {
2072 constraintParseError
:= func(err error
) bool {
2074 return strings
.Contains(str
, "failed to parse ") && strings
.Contains(str
, "constraint")
2077 encodingError
:= func(err error
) bool {
2078 return strings
.Contains(err
.Error(), "cannot be encoded as an IA5String")
2081 // Bad names in constraints should not parse.
2082 badNames
:= []struct {
2084 matcher
func(error
) bool
2086 {"dns:foo.com.", constraintParseError
},
2087 {"email:abc@foo.com.", constraintParseError
},
2088 {"email:foo.com.", constraintParseError
},
2089 {"uri:example.com.", constraintParseError
},
2090 {"uri:1.2.3.4", constraintParseError
},
2091 {"uri:ffff::1", constraintParseError
},
2092 {"dns:not–hyphen.com", encodingError
},
2093 {"email:foo@not–hyphen.com", encodingError
},
2094 {"uri:not–hyphen.com", encodingError
},
2097 priv
, err
:= ecdsa
.GenerateKey(elliptic
.P256(), rand
.Reader
)
2102 for _
, test
:= range badNames
{
2103 _
, err
:= makeConstraintsCACert(constraintsSpec
{
2104 ok
: []string{test
.name
},
2105 }, "TestAbsoluteNamesInConstraints", priv
, nil, priv
)
2108 t
.Errorf("bad name %q unexpectedly accepted in name constraint", test
.name
)
2111 if !test
.matcher(err
) {
2112 t
.Errorf("bad name %q triggered unrecognised error: %s", test
.name
, err
)
2118 func TestBadNamesInSANs(t
*testing
.T
) {
2119 // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
2120 // will parse and are tested in name constraint tests at the top of this
2122 badNames
:= []string{
2123 "uri:https://example.com./dsf",
2125 "invalidip:0102030405",
2128 priv
, err
:= ecdsa
.GenerateKey(elliptic
.P256(), rand
.Reader
)
2133 for _
, badName
:= range badNames
{
2134 _
, err
:= makeConstraintsLeafCert(leafSpec
{sans
: []string{badName
}}, priv
, nil, priv
)
2137 t
.Errorf("bad name %q unexpectedly accepted in SAN", badName
)
2142 if str
:= err
.Error(); !strings
.Contains(str
, "cannot parse ") {
2143 t
.Errorf("bad name %q triggered unrecognised error: %s", badName
, str
)