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