Source file
src/crypto/x509/verify_test.go
1
2
3
4
5 package x509
6
7 import (
8 "crypto"
9 "crypto/ecdsa"
10 "crypto/elliptic"
11 "crypto/rand"
12 "crypto/x509/pkix"
13 "encoding/asn1"
14 "encoding/pem"
15 "errors"
16 "fmt"
17 "internal/testenv"
18 "math/big"
19 "os"
20 "os/exec"
21 "runtime"
22 "slices"
23 "strconv"
24 "strings"
25 "testing"
26 "time"
27 )
28
29 type verifyTest struct {
30 name string
31 leaf string
32 intermediates []string
33 roots []string
34 currentTime int64
35 dnsName string
36 systemSkip bool
37 systemLax bool
38 keyUsages []ExtKeyUsage
39
40 errorCallback func(*testing.T, error)
41 expectedChains [][]string
42 }
43
44 var verifyTests = []verifyTest{
45 {
46 name: "Valid",
47 leaf: googleLeaf,
48 intermediates: []string{gtsIntermediate},
49 roots: []string{gtsRoot},
50 currentTime: 1677615892,
51 dnsName: "www.google.com",
52
53 expectedChains: [][]string{
54 {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
55 },
56 },
57 {
58 name: "Valid (fqdn)",
59 leaf: googleLeaf,
60 intermediates: []string{gtsIntermediate},
61 roots: []string{gtsRoot},
62 currentTime: 1677615892,
63 dnsName: "www.google.com.",
64
65 expectedChains: [][]string{
66 {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
67 },
68 },
69 {
70 name: "MixedCase",
71 leaf: googleLeaf,
72 intermediates: []string{gtsIntermediate},
73 roots: []string{gtsRoot},
74 currentTime: 1677615892,
75 dnsName: "WwW.GooGLE.coM",
76
77 expectedChains: [][]string{
78 {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
79 },
80 },
81 {
82 name: "HostnameMismatch",
83 leaf: googleLeaf,
84 intermediates: []string{gtsIntermediate},
85 roots: []string{gtsRoot},
86 currentTime: 1677615892,
87 dnsName: "www.example.com",
88
89 errorCallback: expectHostnameError("certificate is valid for"),
90 },
91 {
92 name: "IPMissing",
93 leaf: googleLeaf,
94 intermediates: []string{gtsIntermediate},
95 roots: []string{gtsRoot},
96 currentTime: 1677615892,
97 dnsName: "1.2.3.4",
98
99 errorCallback: expectHostnameError("doesn't contain any IP SANs"),
100 },
101 {
102 name: "Expired",
103 leaf: googleLeaf,
104 intermediates: []string{gtsIntermediate},
105 roots: []string{gtsRoot},
106 currentTime: 1,
107 dnsName: "www.example.com",
108
109 errorCallback: expectExpired,
110 },
111 {
112 name: "MissingIntermediate",
113 leaf: googleLeaf,
114 roots: []string{gtsRoot},
115 currentTime: 1677615892,
116 dnsName: "www.google.com",
117
118
119
120 systemSkip: true,
121 errorCallback: expectAuthorityUnknown,
122 },
123 {
124 name: "RootInIntermediates",
125 leaf: googleLeaf,
126 intermediates: []string{gtsRoot, gtsIntermediate},
127 roots: []string{gtsRoot},
128 currentTime: 1677615892,
129 dnsName: "www.google.com",
130
131 expectedChains: [][]string{
132 {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
133 },
134
135
136 systemLax: true,
137 },
138 {
139 name: "InvalidHash",
140 leaf: googleLeafWithInvalidHash,
141 intermediates: []string{gtsIntermediate},
142 roots: []string{gtsRoot},
143 currentTime: 1677615892,
144 dnsName: "www.google.com",
145
146
147
148 systemLax: true,
149 errorCallback: expectHashError,
150 },
151
152
153
154 {
155 name: "EKULeaf",
156 leaf: smimeLeaf,
157 intermediates: []string{smimeIntermediate},
158 roots: []string{smimeRoot},
159 currentTime: 1594673418,
160
161 errorCallback: expectUsageError,
162 },
163 {
164 name: "EKULeafExplicit",
165 leaf: smimeLeaf,
166 intermediates: []string{smimeIntermediate},
167 roots: []string{smimeRoot},
168 currentTime: 1594673418,
169 keyUsages: []ExtKeyUsage{ExtKeyUsageServerAuth},
170
171 errorCallback: expectUsageError,
172 },
173 {
174 name: "EKULeafValid",
175 leaf: smimeLeaf,
176 intermediates: []string{smimeIntermediate},
177 roots: []string{smimeRoot},
178 currentTime: 1594673418,
179 keyUsages: []ExtKeyUsage{ExtKeyUsageEmailProtection},
180
181 expectedChains: [][]string{
182 {"CORPORATIVO FICTICIO ACTIVO", "EAEko Herri Administrazioen CA - CA AAPP Vascas (2)", "IZENPE S.A."},
183 },
184 },
185 {
186
187
188 name: "MultipleConstraints",
189 leaf: nameConstraintsLeaf,
190 intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
191 roots: []string{globalSignRoot},
192 currentTime: 1524771953,
193 dnsName: "udctest.ads.vt.edu",
194
195 expectedChains: [][]string{
196 {
197 "udctest.ads.vt.edu",
198 "Virginia Tech Global Qualified Server CA",
199 "Trusted Root CA SHA256 G2",
200 "GlobalSign",
201 },
202 },
203 },
204 {
205
206
207 name: "SHA-384",
208 leaf: trustAsiaLeaf,
209 intermediates: []string{trustAsiaSHA384Intermediate},
210 roots: []string{digicertRoot},
211 currentTime: 1558051200,
212 dnsName: "tm.cn",
213
214
215 systemLax: true,
216
217 expectedChains: [][]string{
218 {
219 "tm.cn",
220 "TrustAsia ECC OV TLS Pro CA",
221 "DigiCert Global Root CA",
222 },
223 },
224 },
225 {
226
227
228 name: "LeafInRoots",
229 leaf: selfSigned,
230 roots: []string{selfSigned},
231 currentTime: 1471624472,
232 dnsName: "foo.example",
233 systemSkip: true,
234
235 expectedChains: [][]string{
236 {"Acme Co"},
237 },
238 },
239 {
240
241
242 name: "LeafInRootsInvalid",
243 leaf: selfSigned,
244 roots: []string{selfSigned},
245 currentTime: 1471624472,
246 dnsName: "notfoo.example",
247 systemSkip: true,
248
249 errorCallback: expectHostnameError("certificate is valid for"),
250 },
251 {
252
253
254 name: "X509v1Intermediate",
255 leaf: x509v1TestLeaf,
256 intermediates: []string{x509v1TestIntermediate},
257 roots: []string{x509v1TestRoot},
258 currentTime: 1481753183,
259 systemSkip: true,
260
261 errorCallback: expectNotAuthorizedError,
262 },
263 {
264 name: "IgnoreCNWithSANs",
265 leaf: ignoreCNWithSANLeaf,
266 dnsName: "foo.example.com",
267 roots: []string{ignoreCNWithSANRoot},
268 currentTime: 1486684488,
269 systemSkip: true,
270
271 errorCallback: expectHostnameError("certificate is not valid for any names"),
272 },
273 {
274
275 name: "ExcludedNames",
276 leaf: excludedNamesLeaf,
277 dnsName: "bender.local",
278 intermediates: []string{excludedNamesIntermediate},
279 roots: []string{excludedNamesRoot},
280 currentTime: 1486684488,
281 systemSkip: true,
282
283 errorCallback: expectNameConstraintsError,
284 },
285 {
286
287
288 name: "CriticalExtLeaf",
289 leaf: criticalExtLeafWithExt,
290 intermediates: []string{criticalExtIntermediate},
291 roots: []string{criticalExtRoot},
292 currentTime: 1486684488,
293 systemSkip: true,
294
295 errorCallback: expectUnhandledCriticalExtension,
296 },
297 {
298
299
300 name: "CriticalExtIntermediate",
301 leaf: criticalExtLeaf,
302 intermediates: []string{criticalExtIntermediateWithExt},
303 roots: []string{criticalExtRoot},
304 currentTime: 1486684488,
305 systemSkip: true,
306
307 errorCallback: expectUnhandledCriticalExtension,
308 },
309 {
310 name: "ValidCN",
311 leaf: validCNWithoutSAN,
312 dnsName: "foo.example.com",
313 roots: []string{invalidCNRoot},
314 currentTime: 1540000000,
315 systemSkip: true,
316
317 errorCallback: expectHostnameError("certificate relies on legacy Common Name field"),
318 },
319 {
320
321
322 name: "AKIDNoSKID",
323 leaf: leafWithAKID,
324 roots: []string{rootWithoutSKID},
325 currentTime: 1550000000,
326 dnsName: "example",
327 systemSkip: true,
328
329 expectedChains: [][]string{
330 {"Acme LLC", "Acme Co"},
331 },
332 },
333 {
334
335
336
337 leaf: leafMatchingAKIDMatchingIssuer,
338 roots: []string{rootMatchingSKIDMismatchingSubject, rootMismatchingSKIDMatchingSubject},
339 currentTime: 1550000000,
340 dnsName: "example",
341 systemSkip: true,
342
343 expectedChains: [][]string{
344 {"Leaf", "Root B"},
345 },
346 },
347 }
348
349 func expectHostnameError(msg string) func(*testing.T, error) {
350 return func(t *testing.T, err error) {
351 if _, ok := err.(HostnameError); !ok {
352 t.Fatalf("error was not a HostnameError: %v", err)
353 }
354 if !strings.Contains(err.Error(), msg) {
355 t.Fatalf("HostnameError did not contain %q: %v", msg, err)
356 }
357 }
358 }
359
360 func expectExpired(t *testing.T, err error) {
361 if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
362 t.Fatalf("error was not Expired: %v", err)
363 }
364 }
365
366 func expectUsageError(t *testing.T, err error) {
367 if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage {
368 t.Fatalf("error was not IncompatibleUsage: %v", err)
369 }
370 }
371
372 func expectAuthorityUnknown(t *testing.T, err error) {
373 e, ok := err.(UnknownAuthorityError)
374 if !ok {
375 t.Fatalf("error was not UnknownAuthorityError: %v", err)
376 }
377 if e.Cert == nil {
378 t.Fatalf("error was UnknownAuthorityError, but missing Cert: %v", err)
379 }
380 }
381
382 func expectHashError(t *testing.T, err error) {
383 if err == nil {
384 t.Fatalf("no error resulted from invalid hash")
385 }
386 if expected := "algorithm unimplemented"; !strings.Contains(err.Error(), expected) {
387 t.Fatalf("error resulting from invalid hash didn't contain '%s', rather it was: %v", expected, err)
388 }
389 }
390
391 func expectNameConstraintsError(t *testing.T, err error) {
392 if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
393 t.Fatalf("error was not a CANotAuthorizedForThisName: %v", err)
394 }
395 }
396
397 func expectNotAuthorizedError(t *testing.T, err error) {
398 if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign {
399 t.Fatalf("error was not a NotAuthorizedToSign: %v", err)
400 }
401 }
402
403 func expectUnhandledCriticalExtension(t *testing.T, err error) {
404 if _, ok := err.(UnhandledCriticalExtension); !ok {
405 t.Fatalf("error was not an UnhandledCriticalExtension: %v", err)
406 }
407 }
408
409 func certificateFromPEM(pemBytes string) (*Certificate, error) {
410 block, _ := pem.Decode([]byte(pemBytes))
411 if block == nil {
412 return nil, errors.New("failed to decode PEM")
413 }
414 return ParseCertificate(block.Bytes)
415 }
416
417 func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
418 opts := VerifyOptions{
419 Intermediates: NewCertPool(),
420 DNSName: test.dnsName,
421 CurrentTime: time.Unix(test.currentTime, 0),
422 KeyUsages: test.keyUsages,
423 }
424
425 if !useSystemRoots {
426 opts.Roots = NewCertPool()
427 for j, root := range test.roots {
428 ok := opts.Roots.AppendCertsFromPEM([]byte(root))
429 if !ok {
430 t.Fatalf("failed to parse root #%d", j)
431 }
432 }
433 }
434
435 for j, intermediate := range test.intermediates {
436 ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
437 if !ok {
438 t.Fatalf("failed to parse intermediate #%d", j)
439 }
440 }
441
442 leaf, err := certificateFromPEM(test.leaf)
443 if err != nil {
444 t.Fatalf("failed to parse leaf: %v", err)
445 }
446
447 chains, err := leaf.Verify(opts)
448
449 if test.errorCallback == nil && err != nil {
450 if runtime.GOOS == "windows" && strings.HasSuffix(testenv.Builder(), "-2008") && err.Error() == "x509: certificate signed by unknown authority" {
451 testenv.SkipFlaky(t, 19564)
452 }
453 t.Fatalf("unexpected error: %v", err)
454 }
455 if test.errorCallback != nil {
456 if useSystemRoots && test.systemLax {
457 if err == nil {
458 t.Fatalf("expected error")
459 }
460 } else {
461 test.errorCallback(t, err)
462 }
463 }
464
465 doesMatch := func(expectedChain []string, chain []*Certificate) bool {
466 if len(chain) != len(expectedChain) {
467 return false
468 }
469
470 for k, cert := range chain {
471 if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
472 return false
473 }
474 }
475 return true
476 }
477
478
479
480
481
482 for _, expectedChain := range test.expectedChains {
483 var match bool
484 for _, chain := range chains {
485 if doesMatch(expectedChain, chain) {
486 match = true
487 break
488 }
489 }
490
491 if !match {
492 t.Errorf("No match found for %v", expectedChain)
493 }
494 }
495
496
497 for _, chain := range chains {
498 nMatched := 0
499 for _, expectedChain := range test.expectedChains {
500 if doesMatch(expectedChain, chain) {
501 nMatched++
502 }
503 }
504
505 if nMatched == 0 && test.systemLax == false || nMatched > 1 {
506 t.Errorf("Got %v matches for chain %v", nMatched, chainToDebugString(chain))
507 for _, expectedChain := range test.expectedChains {
508 if doesMatch(expectedChain, chain) {
509 t.Errorf("\t matched %v", expectedChain)
510 }
511 }
512 }
513 }
514 }
515
516 func TestGoVerify(t *testing.T) {
517 for _, test := range verifyTests {
518 t.Run(test.name, func(t *testing.T) {
519 testVerify(t, test, false)
520 })
521 }
522 }
523
524 func TestSystemVerify(t *testing.T) {
525 if runtime.GOOS != "windows" {
526 t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
527 }
528
529 for _, test := range verifyTests {
530 t.Run(test.name, func(t *testing.T) {
531 if test.systemSkip {
532 t.SkipNow()
533 }
534 testVerify(t, test, true)
535 })
536 }
537 }
538
539 func chainToDebugString(chain []*Certificate) string {
540 var chainStr string
541 for _, cert := range chain {
542 if len(chainStr) > 0 {
543 chainStr += " -> "
544 }
545 chainStr += nameToKey(&cert.Subject)
546 }
547 return chainStr
548 }
549
550 func nameToKey(name *pkix.Name) string {
551 return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
552 }
553
554 const gtsIntermediate = `-----BEGIN CERTIFICATE-----
555 MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
556 CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
557 MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
558 MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
559 Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
560 ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
561 kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
562 lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
563 BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
564 gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
565 tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
566 DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
567 AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
568 VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
569 CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
570 AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
571 MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
572 A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
573 aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
574 AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
575 cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
576 RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
577 +o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
578 PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
579 lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
580 Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
581 z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
582 AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
583 juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
584 1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
585 -----END CERTIFICATE-----`
586
587 const gtsRoot = `-----BEGIN CERTIFICATE-----
588 MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
589 CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
590 MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
591 MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
592 Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
593 A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
594 27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
595 Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
596 TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
597 qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
598 szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
599 Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
600 MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
601 wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
602 aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
603 VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
604 AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
605 FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
606 C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
607 QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
608 h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
609 7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
610 ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
611 MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
612 Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
613 6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
614 0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
615 2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
616 bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
617 -----END CERTIFICATE-----`
618
619 const googleLeaf = `-----BEGIN CERTIFICATE-----
620 MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG
621 MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
622 QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
623 ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
624 AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
625 wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
626 55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
627 N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
628 KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
629 WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
630 DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
631 MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
632 f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
633 aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
634 cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
635 b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
636 VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
637 TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
638 4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
639 3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
640 1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
641 hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
642 IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF
643 AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
644 MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
645 VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
646 zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
647 c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
648 i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
649 -----END CERTIFICATE-----`
650
651
652
653 const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
654 MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG
655 MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
656 QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
657 ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
658 AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
659 wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
660 55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
661 N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
662 KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
663 WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
664 DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
665 MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
666 f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
667 aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
668 cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
669 b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
670 VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
671 TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
672 4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
673 3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
674 1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
675 hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
676 IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F
677 AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
678 MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
679 VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
680 zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
681 c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
682 i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
683 -----END CERTIFICATE-----`
684
685 const smimeLeaf = `-----BEGIN CERTIFICATE-----
686 MIIIPDCCBiSgAwIBAgIQaMDxFS0pOMxZZeOBxoTJtjANBgkqhkiG9w0BAQsFADCB
687 nTELMAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTowOAYDVQQLDDFB
688 WlogWml1cnRhZ2lyaSBwdWJsaWtvYSAtIENlcnRpZmljYWRvIHB1YmxpY28gU0NB
689 MTwwOgYDVQQDDDNFQUVrbyBIZXJyaSBBZG1pbmlzdHJhemlvZW4gQ0EgLSBDQSBB
690 QVBQIFZhc2NhcyAoMikwHhcNMTcwNzEyMDg1MzIxWhcNMjEwNzEyMDg1MzIxWjCC
691 AQwxDzANBgNVBAoMBklaRU5QRTE4MDYGA1UECwwvWml1cnRhZ2lyaSBrb3Jwb3Jh
692 dGlib2EtQ2VydGlmaWNhZG8gY29ycG9yYXRpdm8xQzBBBgNVBAsMOkNvbmRpY2lv
693 bmVzIGRlIHVzbyBlbiB3d3cuaXplbnBlLmNvbSBub2xhIGVyYWJpbGkgamFraXRl
694 a28xFzAVBgNVBC4TDi1kbmkgOTk5OTk5ODlaMSQwIgYDVQQDDBtDT1JQT1JBVElW
695 TyBGSUNUSUNJTyBBQ1RJVk8xFDASBgNVBCoMC0NPUlBPUkFUSVZPMREwDwYDVQQE
696 DAhGSUNUSUNJTzESMBAGA1UEBRMJOTk5OTk5ODlaMIIBIjANBgkqhkiG9w0BAQEF
697 AAOCAQ8AMIIBCgKCAQEAwVOMwUDfBtsH0XuxYnb+v/L774jMH8valX7RPH8cl2Lb
698 SiqSo0RchW2RGA2d1yuYHlpChC9jGmt0X/g66/E/+q2hUJlfJtqVDJFwtFYV4u2S
699 yzA3J36V4PRkPQrKxAsbzZriFXAF10XgiHQz9aVeMMJ9GBhmh9+DK8Tm4cMF6i8l
700 +AuC35KdngPF1x0ealTYrYZplpEJFO7CiW42aLi6vQkDR2R7nmZA4AT69teqBWsK
701 0DZ93/f0G/3+vnWwNTBF0lB6dIXoaz8OMSyHLqGnmmAtMrzbjAr/O/WWgbB/BqhR
702 qjJQ7Ui16cuDldXaWQ/rkMzsxmsAox0UF+zdQNvXUQIDAQABo4IDBDCCAwAwgccG
703 A1UdEgSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j
704 b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S
705 TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh
706 IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H
707 YXN0ZWl6MB4GA1UdEQQXMBWBE2ZpY3RpY2lvQGl6ZW5wZS5ldXMwDgYDVR0PAQH/
708 BAQDAgXgMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC
709 AjAdBgNVHQ4EFgQUyeoOD4cgcljKY0JvrNuX2waFQLAwHwYDVR0jBBgwFoAUwKlK
710 90clh/+8taaJzoLSRqiJ66MwggEnBgNVHSAEggEeMIIBGjCCARYGCisGAQQB8zkB
711 AQEwggEGMDMGCCsGAQUFBwIBFidodHRwOi8vd3d3Lml6ZW5wZS5jb20vcnBhc2Nh
712 Y29ycG9yYXRpdm8wgc4GCCsGAQUFBwICMIHBGoG+Wml1cnRhZ2lyaWEgRXVza2Fs
713 IEF1dG9ub21pYSBFcmtpZGVnb2tvIHNla3RvcmUgcHVibGlrb2tvIGVyYWt1bmRl
714 ZW4gYmFybmUtc2FyZWV0YW4gYmFrYXJyaWsgZXJhYmlsIGRhaXRla2UuIFVzbyBy
715 ZXN0cmluZ2lkbyBhbCBhbWJpdG8gZGUgcmVkZXMgaW50ZXJuYXMgZGUgRW50aWRh
716 ZGVzIGRlbCBTZWN0b3IgUHVibGljbyBWYXNjbzAyBggrBgEFBQcBAQQmMCQwIgYI
717 KwYBBQUHMAGGFmh0dHA6Ly9vY3NwLml6ZW5wZS5jb20wOgYDVR0fBDMwMTAvoC2g
718 K4YpaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vY3JsaW50ZXJuYTIwDQYJ
719 KoZIhvcNAQELBQADggIBAIy5PQ+UZlCRq6ig43vpHwlwuD9daAYeejV0Q+ZbgWAE
720 GtO0kT/ytw95ZEJMNiMw3fYfPRlh27ThqiT0VDXZJDlzmn7JZd6QFcdXkCsiuv4+
721 ZoXAg/QwnA3SGUUO9aVaXyuOIIuvOfb9MzoGp9xk23SMV3eiLAaLMLqwB5DTfBdt
722 BGI7L1MnGJBv8RfP/TL67aJ5bgq2ri4S8vGHtXSjcZ0+rCEOLJtmDNMnTZxancg3
723 /H5edeNd+n6Z48LO+JHRxQufbC4mVNxVLMIP9EkGUejlq4E4w6zb5NwCQczJbSWL
724 i31rk2orsNsDlyaLGsWZp3JSNX6RmodU4KAUPor4jUJuUhrrm3Spb73gKlV/gcIw
725 bCE7mML1Kss3x1ySaXsis6SZtLpGWKkW2iguPWPs0ydV6RPhmsCxieMwPPIJ87vS
726 5IejfgyBae7RSuAIHyNFy4uI5xwvwUFf6OZ7az8qtW7ImFOgng3Ds+W9k1S2CNTx
727 d0cnKTfA6IpjGo8EeHcxnIXT8NPImWaRj0qqonvYady7ci6U4m3lkNSdXNn1afgw
728 mYust+gxVtOZs1gk2MUCgJ1V1X+g7r/Cg7viIn6TLkLrpS1kS1hvMqkl9M+7XqPo
729 Qd95nJKOkusQpy99X4dF/lfbYAQnnjnqh3DLD2gvYObXFaAYFaiBKTiMTV2X72F+
730 -----END CERTIFICATE-----`
731
732 const smimeIntermediate = `-----BEGIN CERTIFICATE-----
733 MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL
734 MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu
735 cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV
736 BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0
737 YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE
738 AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj
739 YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h
740 rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2
741 To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU
742 ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD
743 PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr
744 PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn
745 soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM
746 8IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL
747 MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg
748 jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk
749 3LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb
750 KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w
751 gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO
752 MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0
753 b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk
754 aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP
755 BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl
756 h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw
757 OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl
758 bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v
759 b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny
760 bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM
761 3DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS
762 M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E
763 3TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL
764 xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4
765 VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR
766 0oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK
767 b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi
768 1tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS
769 FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM
770 5tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw
771 k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7
772 -----END CERTIFICATE-----`
773
774 const smimeRoot = `-----BEGIN CERTIFICATE-----
775 MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
776 MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
777 ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
778 VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
779 b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
780 scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
781 xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
782 LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
783 uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
784 yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
785 JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
786 rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
787 BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
788 hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
789 QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
790 HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
791 Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
792 QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
793 BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
794 MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
795 AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
796 A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
797 laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
798 awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
799 JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
800 LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
801 VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
802 LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
803 UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
804 QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
805 naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
806 QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
807 -----END CERTIFICATE-----`
808
809 var nameConstraintsLeaf = `-----BEGIN CERTIFICATE-----
810 MIIG+jCCBOKgAwIBAgIQWj9gbtPPkZs65N6TKyutRjANBgkqhkiG9w0BAQsFADCB
811 yzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYDVQQHEwpCbGFj
812 a3NidXJnMSMwIQYDVQQLExpHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTE8MDoG
813 A1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBTdGF0ZSBV
814 bml2ZXJzaXR5MTEwLwYDVQQDEyhWaXJnaW5pYSBUZWNoIEdsb2JhbCBRdWFsaWZp
815 ZWQgU2VydmVyIENBMB4XDTE4MDQyNjE5NDU1M1oXDTE5MTIxMDAwMDAwMFowgZAx
816 CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tz
817 YnVyZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFu
818 ZCBTdGF0ZSBVbml2ZXJzaXR5MRswGQYDVQQDExJ1ZGN0ZXN0LmFkcy52dC5lZHUw
819 ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcoVBeV3AzdSGMzRWH0tuM
820 VluEj+sq4r9PuLDBAdgjjHi4ED8npT2/fgOalswInXspRvFS+pkEwTrmeZ7HPzRJ
821 HUE5YlX5Nc6WI8ZXPVg5E6GyoMy6gNlALwqsIvDCvqxBMc39oG6yOuGmQXdF6s0N
822 BJMrXc4aPz60s4QMWNO2OHL0pmnZqE1TxYRBHUY/dk3cfsIepIDDuSxRsNE/P/MI
823 pxm/uVOyiLEnPmOMsL430SZ7nC8PxUMqya9ok6Zaf7k54g7JJXDjE96VMCjMszIv
824 Ud9qe1PbokTOxlG/4QW7Qm0dPbiJhTUuoBzVAxzlOOkSFdXqSYKjC9tFcbr8y+pT
825 AgMBAAGjggIRMIICDTCBtgYIKwYBBQUHAQEEgakwgaYwXwYIKwYBBQUHMAKGU2h0
826 dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9iYWxxdWFsaWZpZWRzZXJ2ZXIvY2FjZXJ0
827 L2dsb2JhbHF1YWxpZmllZHNlcnZlcl9zaGEyNTYuY3J0MEMGCCsGAQUFBzABhjdo
828 dHRwOi8vdnRjYS5wa2kudnQuZWR1OjgwODAvZWpiY2EvcHVibGljd2ViL3N0YXR1
829 cy9vY3NwMB0GA1UdDgQWBBSzDLXee0wbgXpVQxvBQCophQDZbTAMBgNVHRMBAf8E
830 AjAAMB8GA1UdIwQYMBaAFLxiYCfV4zVIF+lLq0Vq0Miod3GMMGoGA1UdIARjMGEw
831 DgYMKwYBBAG0aAUCAgIBMA4GDCsGAQQBtGgFAgIBATA/BgwrBgEEAbRoBQICAwEw
832 LzAtBggrBgEFBQcCARYhaHR0cDovL3d3dy5wa2kudnQuZWR1L2dsb2JhbC9jcHMv
833 MEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9iYWxx
834 dWFsaWZpZWRzZXJ2ZXIvY3JsL2NhY3JsLmNybDAOBgNVHQ8BAf8EBAMCBeAwHQYD
835 VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB0GA1UdEQQWMBSCEnVkY3Rlc3Qu
836 YWRzLnZ0LmVkdTANBgkqhkiG9w0BAQsFAAOCAgEAD79kuyZbwQJCSBOVq9lA0lj4
837 juHM7RMBfp2GuWvhk5F90OMKQCNdITva3oq4uQzt013TtwposYXq/d0Jobk6RHxj
838 OJzRZVvEPsXLvKm8oLhz7/qgI8gcVeJFR9WgdNhjN1upn++EnABHUdDR77fgixuH
839 FFwNC0WSZ6G0+WgYV7MKD4jYWh1DXEaJtQCN763IaWGxgvQaLUwS423xgwsx+8rw
840 hCRYns5u8myTbUlEu2b+GYimiogtDFMT01A7y88vKl9g+3bx42dJHQNNmSzmYPfs
841 IljtQbVwJIyNL/rwjoz7BTk8e9WY0qUK7ZYh+oGK8kla8yfPKtkvOJV29KdFKzTm
842 42kNm6cH+U5gGwEEg+Xj66Q2yFH5J9kAoBazTepgQ/13wwTY0mU9PtKVBtMH5Y/u
843 MoNVZz6p7vWWRrY5qSXIaW9qyF3bZnmPEHHYTplWsyAyh8blGlqPnpayDflPiQF/
844 9y37kax5yhT0zPZW1ZwIZ5hDTO7pu5i83bYh3pzhvJNHtv74Nn/SX1dTZrWBi/HG
845 OSWK3CLz8qAEBe72XGoBjBzuk9VQxg6k52qjxCyYf7CBSQpTZhsNMf0gzu+JNATc
846 b+XaOqJT6uI/RfqAJVe16ZeXZIFZgQlzIwRS9vobq9fqTIpH/QxqgXROGqAlbBVp
847 /ByH6FEe6+oH1UCklhg=
848 -----END CERTIFICATE-----`
849
850 var nameConstraintsIntermediate1 = `-----BEGIN CERTIFICATE-----
851 MIIHVTCCBj2gAwIBAgINAecHzcaPEeFvu7X4TTANBgkqhkiG9w0BAQsFADBjMQsw
852 CQYDVQQGEwJCRTEVMBMGA1UECxMMVHJ1c3RlZCBSb290MRkwFwYDVQQKExBHbG9i
853 YWxTaWduIG52LXNhMSIwIAYDVQQDExlUcnVzdGVkIFJvb3QgQ0EgU0hBMjU2IEcy
854 MB4XDTE3MTIwNjAwMDAwMFoXDTIyMTIwNjAwMDAwMFowgcsxCzAJBgNVBAYTAlVT
855 MREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEjMCEGA1UE
856 CxMaR2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1Zpcmdpbmlh
857 IFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTExMC8G
858 A1UEAxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTCC
859 AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALgIZhEaptBWADBqdJ45ueFG
860 zMXaGHnzNxoxR1fQIaaRQNdCg4cw3A4dWKMeEgYLtsp65ai3Xfw62Qaus0+KJ3Rh
861 gV+rihqK81NUzkls78fJlADVDI4fCTlothsrE1CTOMiy97jKHai5mVTiWxmcxpmj
862 v7fm5Nhc+uHgh2hIz6npryq495mD51ZrUTIaqAQN6Pw/VHfAmR524vgriTOjtp1t
863 4lA9pXGWjF/vkhAKFFheOQSQ00rngo2wHgCqMla64UTN0oz70AsCYNZ3jDLx0kOP
864 0YmMR3Ih91VA63kLqPXA0R6yxmmhhxLZ5bcyAy1SLjr1N302MIxLM/pSy6aquEnb
865 ELhzqyp9yGgRyGJay96QH7c4RJY6gtcoPDbldDcHI9nXngdAL4DrZkJ9OkDkJLyq
866 G66WZTF5q4EIs6yMdrywz0x7QP+OXPJrjYpbeFs6tGZCFnWPFfmHCRJF8/unofYr
867 heq+9J7Jx3U55S/k57NXbAM1RAJOuMTlfn9Etf9Dpoac9poI4Liav6rBoUQk3N3J
868 WqnVHNx/NdCyJ1/6UbKMJUZsStAVglsi6lVPo289HHOE4f7iwl3SyekizVOp01wU
869 in3ycnbZB/rXmZbwapSxTTSBf0EIOr9i4EGfnnhCAVA9U5uLrI5OEB69IY8PNX00
870 71s3Z2a2fio5c8m3JkdrAgMBAAGjggKdMIICmTAOBgNVHQ8BAf8EBAMCAQYwHQYD
871 VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw
872 HQYDVR0OBBYEFLxiYCfV4zVIF+lLq0Vq0Miod3GMMB8GA1UdIwQYMBaAFMhjmwhp
873 VMKYyNnN4zO3UF74yQGbMIGNBggrBgEFBQcBAQSBgDB+MDcGCCsGAQUFBzABhito
874 dHRwOi8vb2NzcDIuZ2xvYmFsc2lnbi5jb20vdHJ1c3Ryb290c2hhMmcyMEMGCCsG
875 AQUFBzAChjdodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90cnVz
876 dHJvb3RzaGEyZzIuY3J0MIHyBgNVHR4EgeowgeeggbIwCIEGdnQuZWR1MAmCB2Jl
877 di5uZXQwCoIIdmNvbS5lZHUwCIIGdnQuZWR1MAyCCnZ0Y2dpdC5jb20wd6R1MHMx
878 CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tz
879 YnVyZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFu
880 ZCBTdGF0ZSBVbml2ZXJzaXR5oTAwCocIAAAAAAAAAAAwIocgAAAAAAAAAAAAAAAA
881 AAAAAAAAAAAAAAAAAAAAAAAAAAAwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2Ny
882 bC5nbG9iYWxzaWduLmNvbS9ncy90cnVzdHJvb3RzaGEyZzIuY3JsMEwGA1UdIARF
883 MEMwQQYJKwYBBAGgMgE8MDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2Jh
884 bHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQArHocpEKTv
885 DW1Hw0USj60KN96aLJXTLm05s0LbjloeTePtDFtuisrbE85A0IhCwxdIl/VsQMZB
886 7mQZBEmLzR+NK1/Luvs7C6WTmkqrE8H7D73dSOab5fMZIXS91V/aEtEQGpJMhwi1
887 svd9TiiQrVkagrraeRWmTTz9BtUA3CeujuW2tShxF1ew4Q4prYw97EsE4HnKDJtu
888 RtyTqKsuh/rRvKMmgUdEPZbVI23yzUKhi/mTbyml/35x/f6f5p7OYIKcQ/34sts8
889 xoW9dfkWBQKAXCstXat3WJVilGXBFub6GoVZdnxTDipyMZhUT/vzXq2bPphjcdR5
890 YGbmwyYmChfa
891 -----END CERTIFICATE-----`
892
893 var nameConstraintsIntermediate2 = `-----BEGIN CERTIFICATE-----
894 MIIEXDCCA0SgAwIBAgILBAAAAAABNumCOV0wDQYJKoZIhvcNAQELBQAwTDEgMB4G
895 A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
896 Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIwNDI1MTEwMDAwWhcNMjcwNDI1
897 MTEwMDAwWjBjMQswCQYDVQQGEwJCRTEVMBMGA1UECxMMVHJ1c3RlZCBSb290MRkw
898 FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSIwIAYDVQQDExlUcnVzdGVkIFJvb3Qg
899 Q0EgU0hBMjU2IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz80+
900 /Q2PAhLuYwe04YTLBLGKr1/JScHtDvAY5E94GjGxCbSR1/1VhL880UPJyN85tddO
901 oxZPgtIyZixDvvK+CgpT5webyBBbqK/ap7aoByghAJ7X520XZMRwKA6cEWa6tjCL
902 WH1zscxQxGzgtV50rn2ux2SapoCPxMpM4+tpEVwWJf3KP3NT+jd9GRaXWgNei5JK
903 Quo9l+cZkSeuoWijvaer5hcLCufPywMMQd0r6XXIM/l7g9DjMaE24d+fa2bWxQXC
904 8WT/PZ+D1KUEkdtn/ixADqsoiIibGn7M84EE9/NLjbzPrwROlBUJFz6cuw+II0rZ
905 8OFFeZ/OkHHYZq2h9wIDAQABo4IBJjCCASIwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
906 EwEB/wQFMAMBAf8wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0
907 dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMB0GA1UdDgQWBBTI
908 Y5sIaVTCmMjZzeMzt1Be+MkBmzA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3Js
909 Lmdsb2JhbHNpZ24ubmV0L3Jvb3QtcjMuY3JsMD4GCCsGAQUFBwEBBDIwMDAuBggr
910 BgEFBQcwAYYiaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzAfBgNV
911 HSMEGDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDANBgkqhkiG9w0BAQsFAAOCAQEA
912 XzbLwBjJiY6j3WEcxD3eVnsIY4pY3bl6660tgpxCuLVx4o1xyiVkS/BcQFD7GIoX
913 FBRrf5HibO1uSEOw0QZoRwlsio1VPg1PRaccG5C1sB51l/TL1XH5zldZBCnRYrrF
914 qCPorxi0xoRogj8kqkS2xyzYLElhx9X7jIzfZ8dC4mgOeoCtVvwM9xvmef3n6Vyb
915 7/hl3w/zWwKxWyKJNaF7tScD5nvtLUzyBpr++aztiyJ1WliWcS6W+V2gKg9rxEC/
916 rc2yJS70DvfkPiEnBJ2x2AHZV3yKTALUqurkV705JledqUT9I5frAwYNXZ8pNzde
917 n+DIcSIo7yKy6MX9czbFWQ==
918 -----END CERTIFICATE-----`
919
920 var globalSignRoot = `-----BEGIN CERTIFICATE-----
921 MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
922 A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
923 Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
924 MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
925 A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
926 hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
927 RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
928 gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
929 KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
930 QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
931 XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
932 DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
933 LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
934 RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
935 jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
936 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
937 mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
938 Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
939 WD9f
940 -----END CERTIFICATE-----`
941
942 const digicertRoot = `-----BEGIN CERTIFICATE-----
943 MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
944 MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
945 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
946 QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
947 MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
948 b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
949 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
950 CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
951 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
952 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
953 T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
954 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
955 BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
956 TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
957 DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
958 hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
959 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
960 PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
961 YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
962 CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
963 -----END CERTIFICATE-----`
964
965 const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE-----
966 MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh
967 MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
968 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
969 QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO
970 MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD
971 ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
972 IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR
973 xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v
974 Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD
975 VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G
976 A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA
977 MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl
978 cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt
979 Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG
980 SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v
981 Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd
982 j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV
983 OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk
984 GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa
985 SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq
986 PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6
987 rRzZxAYN36q1SX8=
988 -----END CERTIFICATE-----`
989
990 const trustAsiaLeaf = `-----BEGIN CERTIFICATE-----
991 MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw
992 CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j
993 LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx
994 NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI
995 DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo
996 5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm
997 nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
998 AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL
999 TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/
1000 +LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud
1001 EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
1002 BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny
1003 bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD
1004 VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu
1005 ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG
1006 AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG
1007 OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM
1008 U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv
1009 AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA
1010 RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8
1011 leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K
1012 tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx
1013 x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw
1014 CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z
1015 0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364
1016 EEeHB9vhZAEjQSePAfjR9aAGhXRa
1017 -----END CERTIFICATE-----`
1018
1019 const selfSigned = `-----BEGIN CERTIFICATE-----
1020 MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
1021 EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
1022 NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
1023 ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
1024 pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
1025 w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
1026 WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
1027 YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
1028 NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
1029 oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
1030 C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
1031 4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
1032 UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
1033 pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
1034 vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
1035 cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
1036 -----END CERTIFICATE-----`
1037
1038 const issuerSubjectMatchRoot = `-----BEGIN CERTIFICATE-----
1039 MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
1040 ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
1041 MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
1042 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
1043 siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
1044 +QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
1045 JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
1046 FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
1047 EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG
1048 VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn
1049 RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
1050 eyfm5ITdK/WT9TzYhsU4AVZcn20=
1051 -----END CERTIFICATE-----`
1052
1053 const issuerSubjectMatchLeaf = `-----BEGIN CERTIFICATE-----
1054 MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
1055 BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
1056 NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
1057 nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e
1058 UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx
1059 0ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU
1060 Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
1061 CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf
1062 Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
1063 hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
1064 ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
1065 vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
1066 -----END CERTIFICATE-----`
1067
1068 const x509v1TestRoot = `-----BEGIN CERTIFICATE-----
1069 MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
1070 ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
1071 MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
1072 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
1073 siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
1074 +QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
1075 JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
1076 FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
1077 EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm
1078 YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md
1079 h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB
1080 /1JmacUUofl+HusHuLkDxmadogI=
1081 -----END CERTIFICATE-----`
1082
1083 const x509v1TestIntermediate = `-----BEGIN CERTIFICATE-----
1084 MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
1085 b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
1086 MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
1087 ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL
1088 jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM
1089 k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8
1090 UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab
1091 DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR
1092 zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur
1093 x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
1094 -----END CERTIFICATE-----`
1095
1096 const x509v1TestLeaf = `-----BEGIN CERTIFICATE-----
1097 MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
1098 BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
1099 MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
1100 BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
1101 gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR
1102 +RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG
1103 Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD
1104 VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
1105 HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB
1106 CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9
1107 5R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL
1108 /jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
1109 -----END CERTIFICATE-----`
1110
1111 const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE-----
1112 MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
1113 ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
1114 MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
1115 BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
1116 DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW
1117 P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY
1118 VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf
1119 2FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3
1120 KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w
1121 OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE
1122 AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
1123 AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC
1124 AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j
1125 fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I
1126 VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy
1127 nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU
1128 aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu
1129 BJ6bvwEAasFiLGP6Zbdmxb2hIA==
1130 -----END CERTIFICATE-----`
1131
1132 const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE-----
1133 MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
1134 BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
1135 MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
1136 FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
1137 ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS
1138 ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3
1139 rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ
1140 hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW
1141 S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV
1142 nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD
1143 AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
1144 MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4
1145 HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ
1146 ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI
1147 Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv
1148 AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR
1149 sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY
1150 j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn
1151 xZbqP3Krgjj4XNaXjg==
1152 -----END CERTIFICATE-----`
1153
1154 const excludedNamesLeaf = `-----BEGIN CERTIFICATE-----
1155 MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
1156 BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
1157 MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
1158 ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv
1159 ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV
1160 BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx
1161 FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0
1162 eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G
1163 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA
1164 zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8
1165 Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu
1166 /9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP
1167 /Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB
1168 UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj
1169 LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB
1170 MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq
1171 sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP
1172 hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt
1173 qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+
1174 VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4
1175 oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A
1176 -----END CERTIFICATE-----`
1177
1178 const excludedNamesIntermediate = `-----BEGIN CERTIFICATE-----
1179 MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE
1180 BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
1181 MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
1182 ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5
1183 MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV
1184 UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD
1185 VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3
1186 MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz
1187 OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx
1188 3FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I
1189 CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE
1190 1AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL
1191 7oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS
1192 nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y
1193 E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
1194 ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA
1195 V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI
1196 JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7
1197 A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z
1198 LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS
1199 zMBX1/lk4wkFckeUIlkD55Y=
1200 -----END CERTIFICATE-----`
1201
1202 const excludedNamesRoot = `-----BEGIN CERTIFICATE-----
1203 MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
1204 BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
1205 MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
1206 ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU
1207 ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL
1208 MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH
1209 YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl
1210 Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm
1211 b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc
1212 7+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+
1213 8TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4
1214 gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb
1215 5Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb
1216 smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV
1217 m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww
1218 CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu
1219 ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs
1220 n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+
1221 Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ
1222 yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT
1223 6mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o
1224 +NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy
1225 -----END CERTIFICATE-----`
1226
1227 const invalidCNRoot = `-----BEGIN CERTIFICATE-----
1228 MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg
1229 cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM
1230 CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj
1231 QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg
1232 oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI
1233 XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6
1234 -----END CERTIFICATE-----`
1235
1236 const validCNWithoutSAN = `-----BEGIN CERTIFICATE-----
1237 MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG
1238 A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow
1239 GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
1240 AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr
1241 p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR
1242 cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0
1243 h7olHCpY9yMRiz0=
1244 -----END CERTIFICATE-----`
1245
1246 const rootWithoutSKID = `-----BEGIN CERTIFICATE-----
1247 MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw
1248 DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow
1249 EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm
1250 jGlTr4dLOWT+BCTm2PzWRjk1DpLcSAh+Al8eB1Nc2eBWxYIH9qPirfatvqBOA4c5
1251 ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
1252 BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI
1253 KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA
1254 AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec=
1255 -----END CERTIFICATE-----`
1256
1257 const leafWithAKID = `-----BEGIN CERTIFICATE-----
1258 MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ
1259 MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa
1260 MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
1261 Wk5N+/8X97YT6ClFNIE5/4yc2YwKn921l0wrIJEcT2u+Uydm7EqtCJNtZjYMAnBd
1262 Acp/wynpTwC6tBTsxcM0s6NqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
1263 CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R
1264 ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
1265 4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
1266 ZZMqeJS7JldLx91sPUArY5A=
1267 -----END CERTIFICATE-----`
1268
1269 const rootMatchingSKIDMismatchingSubject = `-----BEGIN CERTIFICATE-----
1270 MIIBQjCB6aADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQTAe
1271 Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
1272 QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPK4p1uXq2aAeDtKDHIokg2rTcPM
1273 2gq3N9Y96wiW6/7puBK1+INEW//cO9x6FpzkcsHw/TriAqy4sck/iDAvf9WjMjAw
1274 MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAMBgNVHQ4EBQQDAQID
1275 MAoGCCqGSM49BAMCA0gAMEUCIQDgtAp7iVHxMnKxZPaLQPC+Tv2r7+DJc88k2SKH
1276 MPs/wQIgFjjNvBoQEl7vSHTcRGCCcFMdlN4l0Dqc9YwGa9fyrQs=
1277 -----END CERTIFICATE-----`
1278
1279 const rootMismatchingSKIDMatchingSubject = `-----BEGIN CERTIFICATE-----
1280 MIIBNDCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
1281 Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
1282 QjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI1YRFcIlkWzm9BdEVrIsEQJ2dT6
1283 qiW8/WV9GoIhmDtX9SEDHospc0Cgm+TeD2QYW2iMrS5mvNe4GSw0Jezg/bOjJDAi
1284 MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNI
1285 ADBFAiEAukWOiuellx8bugRiwCS5XQ6IOJ1SZcjuZxj76WojwxkCIHqa71qNw8FM
1286 DtA5yoL9M2pDFF6ovFWnaCe+KlzSwAW/
1287 -----END CERTIFICATE-----`
1288
1289 const leafMatchingAKIDMatchingIssuer = `-----BEGIN CERTIFICATE-----
1290 MIIBNTCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
1291 Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMA8xDTALBgNVBAMTBExlYWYw
1292 WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNWERXCJZFs5vQXRFayLBECdnU+qol
1293 vP1lfRqCIZg7V/UhAx6LKXNAoJvk3g9kGFtojK0uZrzXuBksNCXs4P2zoyYwJDAO
1294 BgNVHSMEBzAFgAMBAgMwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNJ
1295 ADBGAiEAnV9XV7a4h0nfJB8pWv+pBUXRlRFA2uZz3mXEpee8NYACIQCWa+wL70GL
1296 ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
1297 -----END CERTIFICATE-----`
1298
1299 var unknownAuthorityErrorTests = []struct {
1300 name string
1301 cert string
1302 expected string
1303 }{
1304 {"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
1305 {"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
1306 {"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
1307 }
1308
1309 func TestUnknownAuthorityError(t *testing.T) {
1310 for i, tt := range unknownAuthorityErrorTests {
1311 t.Run(tt.name, func(t *testing.T) {
1312 der, _ := pem.Decode([]byte(tt.cert))
1313 if der == nil {
1314 t.Fatalf("#%d: Unable to decode PEM block", i)
1315 }
1316 c, err := ParseCertificate(der.Bytes)
1317 if err != nil {
1318 t.Fatalf("#%d: Unable to parse certificate -> %v", i, err)
1319 }
1320 uae := &UnknownAuthorityError{
1321 Cert: c,
1322 hintErr: fmt.Errorf("empty"),
1323 hintCert: c,
1324 }
1325 actual := uae.Error()
1326 if actual != tt.expected {
1327 t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
1328 }
1329 })
1330 }
1331 }
1332
1333 var nameConstraintTests = []struct {
1334 constraint, domain string
1335 expectError bool
1336 shouldMatch bool
1337 }{
1338 {"", "anything.com", false, true},
1339 {"example.com", "example.com", false, true},
1340 {"example.com.", "example.com", true, false},
1341 {"example.com", "example.com.", true, false},
1342 {"example.com", "ExAmPle.coM", false, true},
1343 {"example.com", "exampl1.com", false, false},
1344 {"example.com", "www.ExAmPle.coM", false, true},
1345 {"example.com", "sub.www.ExAmPle.coM", false, true},
1346 {"example.com", "notexample.com", false, false},
1347 {".example.com", "example.com", false, false},
1348 {".example.com", "www.example.com", false, true},
1349 {".example.com", "www..example.com", true, false},
1350 }
1351
1352 func TestNameConstraints(t *testing.T) {
1353 for i, test := range nameConstraintTests {
1354 result, err := matchDomainConstraint(test.domain, test.constraint)
1355
1356 if err != nil && !test.expectError {
1357 t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err)
1358 continue
1359 }
1360
1361 if err == nil && test.expectError {
1362 t.Errorf("unexpected success for test #%d: domain=%s, constraint=%s", i, test.domain, test.constraint)
1363 continue
1364 }
1365
1366 if result != test.shouldMatch {
1367 t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
1368 }
1369 }
1370 }
1371
1372 const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
1373 MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1374 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
1375 CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
1376 ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
1377 gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
1378 8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
1379 +G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
1380 czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
1381 tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
1382 AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
1383 MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
1384 XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
1385 dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
1386 v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
1387 jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
1388 fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
1389 IuYkJwt6w+LH/9HZgf8=
1390 -----END CERTIFICATE-----`
1391 const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
1392 MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1393 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
1394 CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
1395 7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
1396 8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
1397 gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
1398 xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
1399 g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
1400 46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
1401 CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
1402 A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
1403 bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
1404 wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
1405 rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
1406 DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
1407 29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
1408 -----END CERTIFICATE-----`
1409 const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
1410 MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1411 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
1412 IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
1413 fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
1414 35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
1415 2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
1416 S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
1417 kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
1418 AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
1419 AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
1420 BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
1421 4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
1422 9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
1423 w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
1424 4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
1425 8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
1426 -----END CERTIFICATE-----`
1427
1428 const criticalExtRoot = `-----BEGIN CERTIFICATE-----
1429 MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1430 A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1431 MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
1432 CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
1433 gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
1434 BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
1435 /zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
1436 uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
1437 FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
1438 -----END CERTIFICATE-----`
1439
1440 const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
1441 MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1442 A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1443 MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
1444 KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
1445 rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
1446 AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
1447 Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
1448 EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
1449 cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
1450 xXbdbm27KQ==
1451 -----END CERTIFICATE-----`
1452
1453 const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
1454 MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
1455 A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
1456 MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
1457 bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
1458 6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
1459 gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
1460 AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
1461 IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
1462 SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
1463 I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
1464 -----END CERTIFICATE-----`
1465
1466 const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
1467 MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
1468 T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
1469 MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
1470 cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
1471 mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
1472 oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
1473 BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
1474 UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
1475 BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
1476 c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
1477 -----END CERTIFICATE-----`
1478
1479 const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
1480 MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
1481 A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
1482 aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
1483 T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
1484 A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
1485 GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
1486 FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
1487 UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
1488 CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
1489 2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
1490 -----END CERTIFICATE-----`
1491
1492 func TestValidHostname(t *testing.T) {
1493 tests := []struct {
1494 host string
1495 validInput, validPattern bool
1496 }{
1497 {host: "example.com", validInput: true, validPattern: true},
1498 {host: "eXample123-.com", validInput: true, validPattern: true},
1499 {host: "-eXample123-.com"},
1500 {host: ""},
1501 {host: "."},
1502 {host: "example..com"},
1503 {host: ".example.com"},
1504 {host: "example.com.", validInput: true},
1505 {host: "*.example.com."},
1506 {host: "*.example.com", validPattern: true},
1507 {host: "*foo.example.com"},
1508 {host: "foo.*.example.com"},
1509 {host: "exa_mple.com", validInput: true, validPattern: true},
1510 {host: "foo,bar"},
1511 {host: "project-dev:us-central1:main"},
1512 }
1513 for _, tt := range tests {
1514 if got := validHostnamePattern(tt.host); got != tt.validPattern {
1515 t.Errorf("validHostnamePattern(%q) = %v, want %v", tt.host, got, tt.validPattern)
1516 }
1517 if got := validHostnameInput(tt.host); got != tt.validInput {
1518 t.Errorf("validHostnameInput(%q) = %v, want %v", tt.host, got, tt.validInput)
1519 }
1520 }
1521 }
1522
1523 func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
1524 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1525 if err != nil {
1526 return nil, nil, err
1527 }
1528
1529 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
1530 serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
1531
1532 template := &Certificate{
1533 SerialNumber: serialNumber,
1534 Subject: pkix.Name{CommonName: cn},
1535 NotBefore: time.Now().Add(-1 * time.Hour),
1536 NotAfter: time.Now().Add(24 * time.Hour),
1537
1538 KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
1539 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
1540 BasicConstraintsValid: true,
1541 IsCA: isCA,
1542 }
1543 if issuer == nil {
1544 issuer = template
1545 issuerKey = priv
1546 }
1547
1548 derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
1549 if err != nil {
1550 return nil, nil, err
1551 }
1552 cert, err := ParseCertificate(derBytes)
1553 if err != nil {
1554 return nil, nil, err
1555 }
1556
1557 return cert, priv, nil
1558 }
1559
1560 func TestPathologicalChain(t *testing.T) {
1561 if testing.Short() {
1562 t.Skip("skipping generation of a long chain of certificates in short mode")
1563 }
1564
1565
1566
1567 roots, intermediates := NewCertPool(), NewCertPool()
1568
1569 parent, parentKey, err := generateCert("Root CA", true, nil, nil)
1570 if err != nil {
1571 t.Fatal(err)
1572 }
1573 roots.AddCert(parent)
1574
1575 for i := 1; i < 100; i++ {
1576 parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
1577 if err != nil {
1578 t.Fatal(err)
1579 }
1580 intermediates.AddCert(parent)
1581 }
1582
1583 leaf, _, err := generateCert("Leaf", false, parent, parentKey)
1584 if err != nil {
1585 t.Fatal(err)
1586 }
1587
1588 start := time.Now()
1589 _, err = leaf.Verify(VerifyOptions{
1590 Roots: roots,
1591 Intermediates: intermediates,
1592 })
1593 t.Logf("verification took %v", time.Since(start))
1594
1595 if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
1596 t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
1597 }
1598 }
1599
1600 func TestLongChain(t *testing.T) {
1601 if testing.Short() {
1602 t.Skip("skipping generation of a long chain of certificates in short mode")
1603 }
1604
1605 roots, intermediates := NewCertPool(), NewCertPool()
1606
1607 parent, parentKey, err := generateCert("Root CA", true, nil, nil)
1608 if err != nil {
1609 t.Fatal(err)
1610 }
1611 roots.AddCert(parent)
1612
1613 for i := 1; i < 15; i++ {
1614 name := fmt.Sprintf("Intermediate CA #%d", i)
1615 parent, parentKey, err = generateCert(name, true, parent, parentKey)
1616 if err != nil {
1617 t.Fatal(err)
1618 }
1619 intermediates.AddCert(parent)
1620 }
1621
1622 leaf, _, err := generateCert("Leaf", false, parent, parentKey)
1623 if err != nil {
1624 t.Fatal(err)
1625 }
1626
1627 start := time.Now()
1628 if _, err := leaf.Verify(VerifyOptions{
1629 Roots: roots,
1630 Intermediates: intermediates,
1631 }); err != nil {
1632 t.Error(err)
1633 }
1634 t.Logf("verification took %v", time.Since(start))
1635 }
1636
1637 func TestSystemRootsError(t *testing.T) {
1638 if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
1639 t.Skip("Windows and darwin do not use (or support) systemRoots")
1640 }
1641
1642 defer func(oldSystemRoots *CertPool) { systemRoots = oldSystemRoots }(systemRootsPool())
1643
1644 opts := VerifyOptions{
1645 Intermediates: NewCertPool(),
1646 DNSName: "www.google.com",
1647 CurrentTime: time.Unix(1677615892, 0),
1648 }
1649
1650 if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
1651 t.Fatalf("failed to parse intermediate")
1652 }
1653
1654 leaf, err := certificateFromPEM(googleLeaf)
1655 if err != nil {
1656 t.Fatalf("failed to parse leaf: %v", err)
1657 }
1658
1659 systemRoots = nil
1660
1661 _, err = leaf.Verify(opts)
1662 if _, ok := err.(SystemRootsError); !ok {
1663 t.Errorf("error was not SystemRootsError: %v", err)
1664 }
1665 }
1666
1667 func TestSystemRootsErrorUnwrap(t *testing.T) {
1668 var err1 = errors.New("err1")
1669 err := SystemRootsError{Err: err1}
1670 if !errors.Is(err, err1) {
1671 t.Error("errors.Is failed, wanted success")
1672 }
1673 }
1674
1675 func macosMajorVersion(t *testing.T) (int, error) {
1676 cmd := testenv.Command(t, "sw_vers", "-productVersion")
1677 out, err := cmd.Output()
1678 if err != nil {
1679 if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
1680 return 0, fmt.Errorf("%v: %v\n%s", cmd, err, ee.Stderr)
1681 }
1682 return 0, fmt.Errorf("%v: %v", cmd, err)
1683 }
1684 before, _, ok := strings.Cut(string(out), ".")
1685 major, err := strconv.Atoi(before)
1686 if !ok || err != nil {
1687 return 0, fmt.Errorf("%v: unexpected output: %q", cmd, out)
1688 }
1689
1690 return major, nil
1691 }
1692
1693 func TestIssue51759(t *testing.T) {
1694 if runtime.GOOS != "darwin" {
1695 t.Skip("only affects darwin")
1696 }
1697
1698 testenv.MustHaveExecPath(t, "sw_vers")
1699 if vers, err := macosMajorVersion(t); err != nil {
1700 if builder := testenv.Builder(); builder != "" {
1701 t.Fatalf("unable to determine macOS version: %s", err)
1702 } else {
1703 t.Skip("unable to determine macOS version")
1704 }
1705 } else if vers < 11 {
1706 t.Skip("behavior only enforced in macOS 11 and after")
1707 }
1708
1709
1710
1711 const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r"
1712 badCert, err := ParseCertificate([]byte(badCertData))
1713 if err != nil {
1714 t.Fatal(err)
1715 }
1716
1717 t.Run("leaf", func(t *testing.T) {
1718 opts := VerifyOptions{}
1719 expectedErr := "invalid leaf certificate"
1720 _, err = badCert.Verify(opts)
1721 if err == nil || err.Error() != expectedErr {
1722 t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
1723 }
1724 })
1725
1726 goodCert, err := certificateFromPEM(googleLeaf)
1727 if err != nil {
1728 t.Fatal(err)
1729 }
1730
1731 t.Run("intermediate", func(t *testing.T) {
1732 opts := VerifyOptions{
1733 Intermediates: NewCertPool(),
1734 }
1735 opts.Intermediates.AddCert(badCert)
1736 expectedErr := "SecCertificateCreateWithData: invalid certificate"
1737 _, err = goodCert.Verify(opts)
1738 if err == nil || err.Error() != expectedErr {
1739 t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
1740 }
1741 })
1742 }
1743
1744 type trustGraphEdge struct {
1745 Issuer string
1746 Subject string
1747 Type int
1748 MutateTemplate func(*Certificate)
1749 Constraint func([]*Certificate) error
1750 }
1751
1752 type rootDescription struct {
1753 Subject string
1754 MutateTemplate func(*Certificate)
1755 Constraint func([]*Certificate) error
1756 }
1757
1758 type trustGraphDescription struct {
1759 Roots []rootDescription
1760 Leaf string
1761 Graph []trustGraphEdge
1762 }
1763
1764 func genCertEdge(t *testing.T, subject string, key crypto.Signer, mutateTmpl func(*Certificate), certType int, issuer *Certificate, signer crypto.Signer) *Certificate {
1765 t.Helper()
1766
1767 serial, err := rand.Int(rand.Reader, big.NewInt(100))
1768 if err != nil {
1769 t.Fatalf("failed to generate test serial: %s", err)
1770 }
1771 tmpl := &Certificate{
1772 SerialNumber: serial,
1773 Subject: pkix.Name{CommonName: subject},
1774 NotBefore: time.Now().Add(-time.Hour),
1775 NotAfter: time.Now().Add(time.Hour),
1776 }
1777 if certType == rootCertificate || certType == intermediateCertificate {
1778 tmpl.IsCA, tmpl.BasicConstraintsValid = true, true
1779 tmpl.KeyUsage = KeyUsageCertSign
1780 } else if certType == leafCertificate {
1781 tmpl.DNSNames = []string{"localhost"}
1782 }
1783 if mutateTmpl != nil {
1784 mutateTmpl(tmpl)
1785 }
1786
1787 if certType == rootCertificate {
1788 issuer = tmpl
1789 signer = key
1790 }
1791
1792 d, err := CreateCertificate(rand.Reader, tmpl, issuer, key.Public(), signer)
1793 if err != nil {
1794 t.Fatalf("failed to generate test cert: %s", err)
1795 }
1796 c, err := ParseCertificate(d)
1797 if err != nil {
1798 t.Fatalf("failed to parse test cert: %s", err)
1799 }
1800 return c
1801 }
1802
1803 func buildTrustGraph(t *testing.T, d trustGraphDescription) (*CertPool, *CertPool, *Certificate) {
1804 t.Helper()
1805
1806 certs := map[string]*Certificate{}
1807 keys := map[string]crypto.Signer{}
1808 rootPool := NewCertPool()
1809 for _, r := range d.Roots {
1810 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1811 if err != nil {
1812 t.Fatalf("failed to generate test key: %s", err)
1813 }
1814 root := genCertEdge(t, r.Subject, k, r.MutateTemplate, rootCertificate, nil, nil)
1815 if r.Constraint != nil {
1816 rootPool.AddCertWithConstraint(root, r.Constraint)
1817 } else {
1818 rootPool.AddCert(root)
1819 }
1820 certs[r.Subject] = root
1821 keys[r.Subject] = k
1822 }
1823
1824 intermediatePool := NewCertPool()
1825 var leaf *Certificate
1826 for _, e := range d.Graph {
1827 issuerCert, ok := certs[e.Issuer]
1828 if !ok {
1829 t.Fatalf("unknown issuer %s", e.Issuer)
1830 }
1831 issuerKey, ok := keys[e.Issuer]
1832 if !ok {
1833 t.Fatalf("unknown issuer %s", e.Issuer)
1834 }
1835
1836 k, ok := keys[e.Subject]
1837 if !ok {
1838 var err error
1839 k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1840 if err != nil {
1841 t.Fatalf("failed to generate test key: %s", err)
1842 }
1843 keys[e.Subject] = k
1844 }
1845 cert := genCertEdge(t, e.Subject, k, e.MutateTemplate, e.Type, issuerCert, issuerKey)
1846 certs[e.Subject] = cert
1847 if e.Subject == d.Leaf {
1848 leaf = cert
1849 } else {
1850 if e.Constraint != nil {
1851 intermediatePool.AddCertWithConstraint(cert, e.Constraint)
1852 } else {
1853 intermediatePool.AddCert(cert)
1854 }
1855 }
1856 }
1857
1858 return rootPool, intermediatePool, leaf
1859 }
1860
1861 func chainsToStrings(chains [][]*Certificate) []string {
1862 chainStrings := []string{}
1863 for _, chain := range chains {
1864 names := []string{}
1865 for _, c := range chain {
1866 names = append(names, c.Subject.String())
1867 }
1868 chainStrings = append(chainStrings, strings.Join(names, " -> "))
1869 }
1870 slices.Sort(chainStrings)
1871 return chainStrings
1872 }
1873
1874 func TestPathBuilding(t *testing.T) {
1875 tests := []struct {
1876 name string
1877 graph trustGraphDescription
1878 expectedChains []string
1879 expectedErr string
1880 }{
1881 {
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907 name: "bad EKU",
1908 graph: trustGraphDescription{
1909 Roots: []rootDescription{{Subject: "root"}},
1910 Leaf: "leaf",
1911 Graph: []trustGraphEdge{
1912 {
1913 Issuer: "root",
1914 Subject: "inter a",
1915 Type: intermediateCertificate,
1916 },
1917 {
1918 Issuer: "root",
1919 Subject: "inter c",
1920 Type: intermediateCertificate,
1921 },
1922 {
1923 Issuer: "inter c",
1924 Subject: "inter a",
1925 Type: intermediateCertificate,
1926 },
1927 {
1928 Issuer: "inter a",
1929 Subject: "inter c",
1930 Type: intermediateCertificate,
1931 },
1932 {
1933 Issuer: "inter c",
1934 Subject: "inter b",
1935 Type: intermediateCertificate,
1936 MutateTemplate: func(t *Certificate) {
1937 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
1938 },
1939 },
1940 {
1941 Issuer: "inter a",
1942 Subject: "inter b",
1943 Type: intermediateCertificate,
1944 },
1945 {
1946 Issuer: "inter b",
1947 Subject: "leaf",
1948 Type: leafCertificate,
1949 },
1950 },
1951 },
1952 expectedChains: []string{
1953 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
1954 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
1955 },
1956 },
1957 {
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983 name: "bad EKU",
1984 graph: trustGraphDescription{
1985 Roots: []rootDescription{{Subject: "root"}},
1986 Leaf: "leaf",
1987 Graph: []trustGraphEdge{
1988 {
1989 Issuer: "root",
1990 Subject: "inter a",
1991 Type: intermediateCertificate,
1992 },
1993 {
1994 Issuer: "root",
1995 Subject: "inter c",
1996 Type: intermediateCertificate,
1997 },
1998 {
1999 Issuer: "inter c",
2000 Subject: "inter a",
2001 Type: intermediateCertificate,
2002 },
2003 {
2004 Issuer: "inter a",
2005 Subject: "inter c",
2006 Type: intermediateCertificate,
2007 },
2008 {
2009 Issuer: "inter c",
2010 Subject: "inter b",
2011 Type: intermediateCertificate,
2012 MutateTemplate: func(t *Certificate) {
2013 t.PermittedDNSDomains = []string{"good"}
2014 t.DNSNames = []string{"bad"}
2015 },
2016 },
2017 {
2018 Issuer: "inter a",
2019 Subject: "inter b",
2020 Type: intermediateCertificate,
2021 },
2022 {
2023 Issuer: "inter b",
2024 Subject: "leaf",
2025 Type: leafCertificate,
2026 },
2027 },
2028 },
2029 expectedChains: []string{
2030 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
2031 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2032 },
2033 },
2034 {
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065 name: "all paths",
2066 graph: trustGraphDescription{
2067 Roots: []rootDescription{{Subject: "root"}},
2068 Leaf: "leaf",
2069 Graph: []trustGraphEdge{
2070 {
2071 Issuer: "root",
2072 Subject: "inter a",
2073 Type: intermediateCertificate,
2074 },
2075 {
2076 Issuer: "inter a",
2077 Subject: "inter b",
2078 Type: intermediateCertificate,
2079 },
2080 {
2081 Issuer: "inter a",
2082 Subject: "inter c",
2083 Type: intermediateCertificate,
2084 },
2085 {
2086 Issuer: "inter b",
2087 Subject: "inter c",
2088 Type: intermediateCertificate,
2089 },
2090 {
2091 Issuer: "inter c",
2092 Subject: "leaf",
2093 Type: leafCertificate,
2094 },
2095 },
2096 },
2097 expectedChains: []string{
2098 "CN=leaf -> CN=inter c -> CN=inter a -> CN=root",
2099 "CN=leaf -> CN=inter c -> CN=inter b -> CN=inter a -> CN=root",
2100 },
2101 },
2102 {
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129 name: "ignore cross-sig loops",
2130 graph: trustGraphDescription{
2131 Roots: []rootDescription{{Subject: "root"}},
2132 Leaf: "leaf",
2133 Graph: []trustGraphEdge{
2134 {
2135 Issuer: "root",
2136 Subject: "inter a",
2137 Type: intermediateCertificate,
2138 },
2139 {
2140 Issuer: "root",
2141 Subject: "inter c",
2142 Type: intermediateCertificate,
2143 },
2144 {
2145 Issuer: "inter c",
2146 Subject: "inter a",
2147 Type: intermediateCertificate,
2148 },
2149 {
2150 Issuer: "inter a",
2151 Subject: "inter c",
2152 Type: intermediateCertificate,
2153 },
2154 {
2155 Issuer: "inter c",
2156 Subject: "inter b",
2157 Type: intermediateCertificate,
2158 },
2159 {
2160 Issuer: "inter a",
2161 Subject: "inter b",
2162 Type: intermediateCertificate,
2163 },
2164 {
2165 Issuer: "inter b",
2166 Subject: "leaf",
2167 Type: leafCertificate,
2168 },
2169 },
2170 },
2171 expectedChains: []string{
2172 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
2173 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2174 "CN=leaf -> CN=inter b -> CN=inter c -> CN=inter a -> CN=root",
2175 "CN=leaf -> CN=inter b -> CN=inter c -> CN=root",
2176 },
2177 },
2178 {
2179
2180
2181
2182 name: "leaf with same subject, key, as parent but with SAN",
2183 graph: trustGraphDescription{
2184 Roots: []rootDescription{{Subject: "root"}},
2185 Leaf: "root",
2186 Graph: []trustGraphEdge{
2187 {
2188 Issuer: "root",
2189 Subject: "root",
2190 Type: leafCertificate,
2191 MutateTemplate: func(c *Certificate) {
2192 c.DNSNames = []string{"localhost"}
2193 },
2194 },
2195 },
2196 },
2197 expectedChains: []string{
2198 "CN=root -> CN=root",
2199 },
2200 },
2201 {
2202
2203
2204 name: "ignore invalid EKU path",
2205 graph: trustGraphDescription{
2206 Roots: []rootDescription{{Subject: "root"}},
2207 Leaf: "leaf",
2208 Graph: []trustGraphEdge{
2209 {
2210 Issuer: "root",
2211 Subject: "inter a",
2212 Type: intermediateCertificate,
2213 },
2214 {
2215 Issuer: "root",
2216 Subject: "inter c",
2217 Type: intermediateCertificate,
2218 },
2219 {
2220 Issuer: "inter c",
2221 Subject: "inter b",
2222 Type: intermediateCertificate,
2223 MutateTemplate: func(t *Certificate) {
2224 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
2225 },
2226 },
2227 {
2228 Issuer: "inter a",
2229 Subject: "inter b",
2230 Type: intermediateCertificate,
2231 MutateTemplate: func(t *Certificate) {
2232 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
2233 },
2234 },
2235 {
2236 Issuer: "inter b",
2237 Subject: "leaf",
2238 Type: leafCertificate,
2239 MutateTemplate: func(t *Certificate) {
2240 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
2241 },
2242 },
2243 },
2244 },
2245 expectedChains: []string{
2246 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2247 },
2248 },
2249 {
2250
2251
2252 name: "constrained root, invalid intermediate",
2253 graph: trustGraphDescription{
2254 Roots: []rootDescription{
2255 {
2256 Subject: "root",
2257 MutateTemplate: func(t *Certificate) {
2258 t.PermittedDNSDomains = []string{"example.com"}
2259 },
2260 },
2261 },
2262 Leaf: "leaf",
2263 Graph: []trustGraphEdge{
2264 {
2265 Issuer: "root",
2266 Subject: "inter",
2267 Type: intermediateCertificate,
2268 MutateTemplate: func(t *Certificate) {
2269 t.DNSNames = []string{"beep.com"}
2270 },
2271 },
2272 {
2273 Issuer: "inter",
2274 Subject: "leaf",
2275 Type: leafCertificate,
2276 MutateTemplate: func(t *Certificate) {
2277 t.DNSNames = []string{"www.example.com"}
2278 },
2279 },
2280 },
2281 },
2282 expectedErr: "x509: a root or intermediate certificate is not authorized to sign for this name: DNS name \"beep.com\" is not permitted by any constraint",
2283 },
2284 {
2285
2286
2287 name: "constrained intermediate, non-matching SAN",
2288 graph: trustGraphDescription{
2289 Roots: []rootDescription{{Subject: "root"}},
2290 Leaf: "leaf",
2291 Graph: []trustGraphEdge{
2292 {
2293 Issuer: "root",
2294 Subject: "inter",
2295 Type: intermediateCertificate,
2296 MutateTemplate: func(t *Certificate) {
2297 t.DNSNames = []string{"beep.com"}
2298 t.PermittedDNSDomains = []string{"example.com"}
2299 },
2300 },
2301 {
2302 Issuer: "inter",
2303 Subject: "leaf",
2304 Type: leafCertificate,
2305 MutateTemplate: func(t *Certificate) {
2306 t.DNSNames = []string{"www.example.com"}
2307 },
2308 },
2309 },
2310 },
2311 expectedChains: []string{"CN=leaf -> CN=inter -> CN=root"},
2312 },
2313 {
2314
2315
2316 name: "code constrained root, two paths, one valid",
2317 graph: trustGraphDescription{
2318 Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
2319 for _, c := range chain {
2320 if c.Subject.CommonName == "inter a" {
2321 return errors.New("bad")
2322 }
2323 }
2324 return nil
2325 }}},
2326 Leaf: "leaf",
2327 Graph: []trustGraphEdge{
2328 {
2329 Issuer: "root",
2330 Subject: "inter a",
2331 Type: intermediateCertificate,
2332 },
2333 {
2334 Issuer: "root",
2335 Subject: "inter b",
2336 Type: intermediateCertificate,
2337 },
2338 {
2339 Issuer: "inter a",
2340 Subject: "inter c",
2341 Type: intermediateCertificate,
2342 },
2343 {
2344 Issuer: "inter b",
2345 Subject: "inter c",
2346 Type: intermediateCertificate,
2347 },
2348 {
2349 Issuer: "inter c",
2350 Subject: "leaf",
2351 Type: leafCertificate,
2352 },
2353 },
2354 },
2355 expectedChains: []string{"CN=leaf -> CN=inter c -> CN=inter b -> CN=root"},
2356 },
2357 {
2358
2359 name: "code constrained root, one invalid path",
2360 graph: trustGraphDescription{
2361 Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
2362 for _, c := range chain {
2363 if c.Subject.CommonName == "leaf" {
2364 return errors.New("bad")
2365 }
2366 }
2367 return nil
2368 }}},
2369 Leaf: "leaf",
2370 Graph: []trustGraphEdge{
2371 {
2372 Issuer: "root",
2373 Subject: "inter",
2374 Type: intermediateCertificate,
2375 },
2376 {
2377 Issuer: "inter",
2378 Subject: "leaf",
2379 Type: leafCertificate,
2380 },
2381 },
2382 },
2383 expectedErr: "x509: certificate signed by unknown authority (possibly because of \"bad\" while trying to verify candidate authority certificate \"root\")",
2384 },
2385 }
2386
2387 for _, tc := range tests {
2388 t.Run(tc.name, func(t *testing.T) {
2389 roots, intermediates, leaf := buildTrustGraph(t, tc.graph)
2390 chains, err := leaf.Verify(VerifyOptions{
2391 Roots: roots,
2392 Intermediates: intermediates,
2393 })
2394 if err != nil && err.Error() != tc.expectedErr {
2395 t.Fatalf("unexpected error: got %q, want %q", err, tc.expectedErr)
2396 }
2397 if len(tc.expectedChains) == 0 {
2398 return
2399 }
2400 gotChains := chainsToStrings(chains)
2401 if !slices.Equal(gotChains, tc.expectedChains) {
2402 t.Errorf("unexpected chains returned:\ngot:\n\t%s\nwant:\n\t%s", strings.Join(gotChains, "\n\t"), strings.Join(tc.expectedChains, "\n\t"))
2403 }
2404 })
2405 }
2406 }
2407
2408 func TestEKUEnforcement(t *testing.T) {
2409 type ekuDescs struct {
2410 EKUs []ExtKeyUsage
2411 Unknown []asn1.ObjectIdentifier
2412 }
2413 tests := []struct {
2414 name string
2415 root ekuDescs
2416 inters []ekuDescs
2417 leaf ekuDescs
2418 verifyEKUs []ExtKeyUsage
2419 err string
2420 }{
2421 {
2422 name: "valid, full chain",
2423 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2424 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}}},
2425 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2426 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2427 },
2428 {
2429 name: "valid, only leaf has EKU",
2430 root: ekuDescs{},
2431 inters: []ekuDescs{ekuDescs{}},
2432 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2433 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2434 },
2435 {
2436 name: "invalid, serverAuth not nested",
2437 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2438 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
2439 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2440 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2441 err: "x509: certificate specifies an incompatible key usage",
2442 },
2443 {
2444 name: "valid, two EKUs, one path",
2445 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2446 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
2447 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2448 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2449 },
2450 {
2451 name: "invalid, ladder",
2452 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2453 inters: []ekuDescs{
2454 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2455 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2456 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2457 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2458 },
2459 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2460 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2461 err: "x509: certificate specifies an incompatible key usage",
2462 },
2463 {
2464 name: "valid, intermediate has no EKU",
2465 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2466 inters: []ekuDescs{ekuDescs{}},
2467 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2468 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2469 },
2470 {
2471 name: "invalid, intermediate has no EKU and no nested path",
2472 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2473 inters: []ekuDescs{ekuDescs{}},
2474 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2475 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2476 err: "x509: certificate specifies an incompatible key usage",
2477 },
2478 {
2479 name: "invalid, intermediate has unknown EKU",
2480 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2481 inters: []ekuDescs{ekuDescs{Unknown: []asn1.ObjectIdentifier{{1, 2, 3}}}},
2482 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2483 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2484 err: "x509: certificate specifies an incompatible key usage",
2485 },
2486 }
2487
2488 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2489 if err != nil {
2490 t.Fatalf("failed to generate test key: %s", err)
2491 }
2492
2493 for _, tc := range tests {
2494 t.Run(tc.name, func(t *testing.T) {
2495 rootPool := NewCertPool()
2496 root := genCertEdge(t, "root", k, func(c *Certificate) {
2497 c.ExtKeyUsage = tc.root.EKUs
2498 c.UnknownExtKeyUsage = tc.root.Unknown
2499 }, rootCertificate, nil, k)
2500 rootPool.AddCert(root)
2501
2502 parent := root
2503 interPool := NewCertPool()
2504 for i, interEKUs := range tc.inters {
2505 inter := genCertEdge(t, fmt.Sprintf("inter %d", i), k, func(c *Certificate) {
2506 c.ExtKeyUsage = interEKUs.EKUs
2507 c.UnknownExtKeyUsage = interEKUs.Unknown
2508 }, intermediateCertificate, parent, k)
2509 interPool.AddCert(inter)
2510 parent = inter
2511 }
2512
2513 leaf := genCertEdge(t, "leaf", k, func(c *Certificate) {
2514 c.ExtKeyUsage = tc.leaf.EKUs
2515 c.UnknownExtKeyUsage = tc.leaf.Unknown
2516 }, intermediateCertificate, parent, k)
2517
2518 _, err := leaf.Verify(VerifyOptions{Roots: rootPool, Intermediates: interPool, KeyUsages: tc.verifyEKUs})
2519 if err == nil && tc.err != "" {
2520 t.Errorf("expected error")
2521 } else if err != nil && err.Error() != tc.err {
2522 t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.err)
2523 }
2524 })
2525 }
2526 }
2527
2528 func TestVerifyEKURootAsLeaf(t *testing.T) {
2529 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2530 if err != nil {
2531 t.Fatalf("failed to generate key: %s", err)
2532 }
2533
2534 for _, tc := range []struct {
2535 rootEKUs []ExtKeyUsage
2536 verifyEKUs []ExtKeyUsage
2537 succeed bool
2538 }{
2539 {
2540 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2541 succeed: true,
2542 },
2543 {
2544 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2545 succeed: true,
2546 },
2547 {
2548 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2549 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2550 succeed: true,
2551 },
2552 {
2553 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2554 verifyEKUs: []ExtKeyUsage{ExtKeyUsageAny},
2555 succeed: true,
2556 },
2557 {
2558 rootEKUs: []ExtKeyUsage{ExtKeyUsageAny},
2559 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2560 succeed: true,
2561 },
2562 {
2563 rootEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
2564 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2565 succeed: false,
2566 },
2567 } {
2568 t.Run(fmt.Sprintf("root EKUs %#v, verify EKUs %#v", tc.rootEKUs, tc.verifyEKUs), func(t *testing.T) {
2569 tmpl := &Certificate{
2570 SerialNumber: big.NewInt(1),
2571 Subject: pkix.Name{CommonName: "root"},
2572 NotBefore: time.Now().Add(-time.Hour),
2573 NotAfter: time.Now().Add(time.Hour),
2574 DNSNames: []string{"localhost"},
2575 ExtKeyUsage: tc.rootEKUs,
2576 }
2577 rootDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
2578 if err != nil {
2579 t.Fatalf("failed to create certificate: %s", err)
2580 }
2581 root, err := ParseCertificate(rootDER)
2582 if err != nil {
2583 t.Fatalf("failed to parse certificate: %s", err)
2584 }
2585 roots := NewCertPool()
2586 roots.AddCert(root)
2587
2588 _, err = root.Verify(VerifyOptions{Roots: roots, KeyUsages: tc.verifyEKUs})
2589 if err == nil && !tc.succeed {
2590 t.Error("verification succeed")
2591 } else if err != nil && tc.succeed {
2592 t.Errorf("verification failed: %q", err)
2593 }
2594 })
2595 }
2596
2597 }
2598
2599 func TestVerifyNilPubKey(t *testing.T) {
2600 c := &Certificate{
2601 RawIssuer: []byte{1, 2, 3},
2602 AuthorityKeyId: []byte{1, 2, 3},
2603 }
2604 opts := &VerifyOptions{}
2605 opts.Roots = NewCertPool()
2606 r := &Certificate{
2607 RawSubject: []byte{1, 2, 3},
2608 SubjectKeyId: []byte{1, 2, 3},
2609 }
2610 opts.Roots.AddCert(r)
2611
2612 _, err := c.buildChains([]*Certificate{r}, nil, opts)
2613 if _, ok := err.(UnknownAuthorityError); !ok {
2614 t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
2615 }
2616 }
2617
2618 func TestVerifyBareWildcard(t *testing.T) {
2619 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2620 if err != nil {
2621 t.Fatalf("failed to generate key: %s", err)
2622 }
2623 tmpl := &Certificate{
2624 SerialNumber: big.NewInt(1),
2625 Subject: pkix.Name{CommonName: "test"},
2626 NotBefore: time.Now().Add(-time.Hour),
2627 NotAfter: time.Now().Add(time.Hour),
2628 DNSNames: []string{"*"},
2629 }
2630 cDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
2631 if err != nil {
2632 t.Fatalf("failed to create certificate: %s", err)
2633 }
2634 c, err := ParseCertificate(cDER)
2635 if err != nil {
2636 t.Fatalf("failed to parse certificate: %s", err)
2637 }
2638
2639 if err := c.VerifyHostname("label"); err == nil {
2640 t.Fatalf("VerifyHostname unexpected success with bare wildcard SAN")
2641 }
2642 }
2643
2644 func TestPoliciesValid(t *testing.T) {
2645
2646
2647
2648
2649
2650
2651
2652 testOID1 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 1})
2653 testOID2 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 2})
2654 testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3})
2655 testOID4 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 4})
2656 testOID5 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 5})
2657
2658 loadTestCert := func(t *testing.T, path string) *Certificate {
2659 b, err := os.ReadFile(path)
2660 if err != nil {
2661 t.Fatal(err)
2662 }
2663 p, _ := pem.Decode(b)
2664 c, err := ParseCertificate(p.Bytes)
2665 if err != nil {
2666 t.Fatal(err)
2667 }
2668 return c
2669 }
2670
2671 root := loadTestCert(t, "testdata/policy_root.pem")
2672 root_cross_inhibit_mapping := loadTestCert(t, "testdata/policy_root_cross_inhibit_mapping.pem")
2673 root2 := loadTestCert(t, "testdata/policy_root2.pem")
2674 intermediate := loadTestCert(t, "testdata/policy_intermediate.pem")
2675 intermediate_any := loadTestCert(t, "testdata/policy_intermediate_any.pem")
2676 intermediate_mapped := loadTestCert(t, "testdata/policy_intermediate_mapped.pem")
2677 intermediate_mapped_any := loadTestCert(t, "testdata/policy_intermediate_mapped_any.pem")
2678 intermediate_mapped_oid3 := loadTestCert(t, "testdata/policy_intermediate_mapped_oid3.pem")
2679 intermediate_require := loadTestCert(t, "testdata/policy_intermediate_require.pem")
2680 intermediate_require1 := loadTestCert(t, "testdata/policy_intermediate_require1.pem")
2681 intermediate_require2 := loadTestCert(t, "testdata/policy_intermediate_require2.pem")
2682 intermediate_require_no_policies := loadTestCert(t, "testdata/policy_intermediate_require_no_policies.pem")
2683 leaf := loadTestCert(t, "testdata/policy_leaf.pem")
2684 leaf_any := loadTestCert(t, "testdata/policy_leaf_any.pem")
2685 leaf_none := loadTestCert(t, "testdata/policy_leaf_none.pem")
2686 leaf_oid1 := loadTestCert(t, "testdata/policy_leaf_oid1.pem")
2687 leaf_oid2 := loadTestCert(t, "testdata/policy_leaf_oid2.pem")
2688 leaf_oid3 := loadTestCert(t, "testdata/policy_leaf_oid3.pem")
2689 leaf_oid4 := loadTestCert(t, "testdata/policy_leaf_oid4.pem")
2690 leaf_oid5 := loadTestCert(t, "testdata/policy_leaf_oid5.pem")
2691 leaf_require := loadTestCert(t, "testdata/policy_leaf_require.pem")
2692 leaf_require1 := loadTestCert(t, "testdata/policy_leaf_require1.pem")
2693
2694 type testCase struct {
2695 chain []*Certificate
2696 policies []OID
2697 requireExplicitPolicy bool
2698 inhibitPolicyMapping bool
2699 inhibitAnyPolicy bool
2700 valid bool
2701 }
2702
2703 tests := []testCase{
2704
2705 {
2706 chain: []*Certificate{leaf, intermediate, root},
2707 requireExplicitPolicy: true,
2708 valid: true,
2709 },
2710 {
2711 chain: []*Certificate{leaf, intermediate, root},
2712 policies: []OID{testOID1},
2713 requireExplicitPolicy: true,
2714 valid: true,
2715 },
2716 {
2717 chain: []*Certificate{leaf, intermediate, root},
2718 policies: []OID{testOID2},
2719 requireExplicitPolicy: true,
2720 valid: true,
2721 },
2722 {
2723 chain: []*Certificate{leaf, intermediate, root},
2724 policies: []OID{testOID3},
2725 requireExplicitPolicy: true,
2726 valid: false,
2727 },
2728 {
2729 chain: []*Certificate{leaf, intermediate, root},
2730 policies: []OID{testOID1, testOID2},
2731 requireExplicitPolicy: true,
2732 valid: true,
2733 },
2734 {
2735 chain: []*Certificate{leaf, intermediate, root},
2736 policies: []OID{testOID1, testOID3},
2737 requireExplicitPolicy: true,
2738 valid: true,
2739 },
2740
2741
2742
2743 {
2744 chain: []*Certificate{leaf, intermediate, root},
2745 policies: []OID{testOID1},
2746 valid: true,
2747 },
2748 {
2749 chain: []*Certificate{leaf, intermediate, root},
2750 policies: []OID{testOID3},
2751 valid: true,
2752 },
2753
2754 {
2755 chain: []*Certificate{leaf, intermediate_require, root},
2756 policies: []OID{testOID1},
2757 valid: true,
2758 },
2759 {
2760 chain: []*Certificate{leaf, intermediate_require, root},
2761 policies: []OID{testOID3},
2762 valid: false,
2763 },
2764
2765
2766
2767 {
2768 chain: []*Certificate{leaf_none, intermediate_require, root},
2769 requireExplicitPolicy: true,
2770 valid: false,
2771 },
2772
2773 {
2774 chain: []*Certificate{leaf_require, intermediate, root},
2775 valid: true,
2776 },
2777 {
2778 chain: []*Certificate{leaf_require, intermediate, root},
2779 policies: []OID{testOID1},
2780 valid: true,
2781 },
2782 {
2783 chain: []*Certificate{leaf_require, intermediate, root},
2784 policies: []OID{testOID3},
2785 valid: false,
2786 },
2787
2788
2789 {
2790 chain: []*Certificate{leaf, intermediate_require1, root},
2791 policies: []OID{testOID3},
2792 valid: false,
2793 },
2794 {
2795 chain: []*Certificate{leaf, intermediate_require2, root},
2796 policies: []OID{testOID3},
2797 valid: true,
2798 },
2799 {
2800 chain: []*Certificate{leaf_require1, intermediate, root},
2801 policies: []OID{testOID3},
2802 valid: true,
2803 },
2804
2805
2806 {
2807 chain: []*Certificate{leaf_require1, intermediate_require1, root},
2808 policies: []OID{testOID3},
2809 valid: false,
2810 },
2811 {
2812 chain: []*Certificate{leaf_require, intermediate_require2, root},
2813 policies: []OID{testOID3},
2814 valid: false,
2815 },
2816
2817
2818 {
2819 chain: []*Certificate{leaf, intermediate_require_no_policies, root},
2820 policies: []OID{testOID1},
2821 valid: false,
2822 },
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832 {
2833 chain: []*Certificate{leaf_any, intermediate, root},
2834 policies: []OID{testOID1},
2835 requireExplicitPolicy: true,
2836 valid: true,
2837 },
2838 {
2839 chain: []*Certificate{leaf_any, intermediate, root},
2840 policies: []OID{testOID3},
2841 requireExplicitPolicy: true,
2842 valid: false,
2843 },
2844
2845
2846 {
2847 chain: []*Certificate{leaf, intermediate_any, root},
2848 policies: []OID{testOID1},
2849 requireExplicitPolicy: true,
2850 valid: true,
2851 },
2852 {
2853 chain: []*Certificate{leaf, intermediate_any, root},
2854 policies: []OID{testOID3},
2855 requireExplicitPolicy: true,
2856 valid: false,
2857 },
2858
2859 {
2860 chain: []*Certificate{leaf_any, intermediate_any, root},
2861 policies: []OID{testOID1},
2862 requireExplicitPolicy: true,
2863 valid: true,
2864 },
2865 {
2866 chain: []*Certificate{leaf_any, intermediate_any, root},
2867 policies: []OID{testOID3},
2868 requireExplicitPolicy: true,
2869 valid: true,
2870 },
2871
2872 {
2873 chain: []*Certificate{root},
2874 policies: []OID{testOID1},
2875 requireExplicitPolicy: true,
2876 valid: true,
2877 },
2878
2879
2880 {
2881 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root},
2882 policies: []OID{testOID3},
2883 requireExplicitPolicy: true,
2884 valid: true,
2885 },
2886 {
2887 chain: []*Certificate{leaf_oid4, intermediate_mapped_oid3, root},
2888 policies: []OID{testOID4},
2889 requireExplicitPolicy: true,
2890 valid: false,
2891 },
2892
2893
2894
2895 {
2896 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root},
2897 policies: []OID{testOID3},
2898 requireExplicitPolicy: true,
2899 inhibitPolicyMapping: true,
2900 valid: false,
2901 },
2902 {
2903 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root_cross_inhibit_mapping, root2},
2904 policies: []OID{testOID3},
2905 requireExplicitPolicy: true,
2906 valid: false,
2907 },
2908 }
2909
2910 for _, useAny := range []bool{false, true} {
2911 var intermediate *Certificate
2912 if useAny {
2913 intermediate = intermediate_mapped_any
2914 } else {
2915 intermediate = intermediate_mapped
2916 }
2917 extraTests := []testCase{
2918
2919
2920 {
2921 chain: []*Certificate{leaf, intermediate, root},
2922 policies: []OID{testOID3},
2923 requireExplicitPolicy: true,
2924 valid: true,
2925 },
2926 {
2927 chain: []*Certificate{leaf_oid1, intermediate, root},
2928 policies: []OID{testOID3},
2929 requireExplicitPolicy: true,
2930 valid: true,
2931 },
2932 {
2933 chain: []*Certificate{leaf_oid2, intermediate, root},
2934 policies: []OID{testOID3},
2935 requireExplicitPolicy: true,
2936 valid: true,
2937 },
2938
2939
2940
2941
2942
2943
2944
2945
2946 {
2947 chain: []*Certificate{leaf_oid3, intermediate, root},
2948 policies: []OID{testOID3},
2949 requireExplicitPolicy: true,
2950 valid: useAny,
2951 },
2952
2953
2954
2955
2956
2957
2958
2959 {
2960 chain: []*Certificate{leaf_oid1, intermediate, root},
2961 policies: []OID{testOID1},
2962 requireExplicitPolicy: true,
2963 valid: !useAny,
2964 },
2965
2966
2967 {
2968 chain: []*Certificate{leaf_oid4, intermediate, root},
2969 policies: []OID{testOID4},
2970 requireExplicitPolicy: true,
2971 valid: true,
2972 },
2973 {
2974 chain: []*Certificate{leaf_oid4, intermediate, root},
2975 policies: []OID{testOID5},
2976 requireExplicitPolicy: true,
2977 valid: true,
2978 },
2979 {
2980 chain: []*Certificate{leaf_oid5, intermediate, root},
2981 policies: []OID{testOID4},
2982 requireExplicitPolicy: true,
2983 valid: true,
2984 },
2985 {
2986 chain: []*Certificate{leaf_oid5, intermediate, root},
2987 policies: []OID{testOID5},
2988 requireExplicitPolicy: true,
2989 valid: true,
2990 },
2991 {
2992 chain: []*Certificate{leaf_oid4, intermediate, root},
2993 policies: []OID{testOID4, testOID5},
2994 requireExplicitPolicy: true,
2995 valid: true,
2996 },
2997 }
2998 tests = append(tests, extraTests...)
2999 }
3000
3001 for i, tc := range tests {
3002 t.Run(fmt.Sprint(i), func(t *testing.T) {
3003 valid := policiesValid(tc.chain, VerifyOptions{
3004 CertificatePolicies: tc.policies,
3005 requireExplicitPolicy: tc.requireExplicitPolicy,
3006 inhibitPolicyMapping: tc.inhibitPolicyMapping,
3007 inhibitAnyPolicy: tc.inhibitAnyPolicy,
3008 })
3009 if valid != tc.valid {
3010 t.Errorf("policiesValid: got %t, want %t", valid, tc.valid)
3011 }
3012 })
3013 }
3014 }
3015
View as plain text