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