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