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