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 var nameConstraintTests = []struct {
1382 constraint, domain string
1383 expectError bool
1384 shouldMatch bool
1385 }{
1386 {"", "anything.com", false, true},
1387 {"example.com", "example.com", false, true},
1388 {"example.com.", "example.com", true, false},
1389 {"example.com", "example.com.", true, false},
1390 {"example.com", "ExAmPle.coM", false, true},
1391 {"example.com", "exampl1.com", false, false},
1392 {"example.com", "www.ExAmPle.coM", false, true},
1393 {"example.com", "sub.www.ExAmPle.coM", false, true},
1394 {"example.com", "notexample.com", false, false},
1395 {".example.com", "example.com", false, false},
1396 {".example.com", "www.example.com", false, true},
1397 {".example.com", "www..example.com", true, false},
1398 }
1399
1400 func TestNameConstraints(t *testing.T) {
1401 for i, test := range nameConstraintTests {
1402 result, err := matchDomainConstraint(test.domain, test.constraint, false, map[string][]string{}, map[string][]string{})
1403
1404 if err != nil && !test.expectError {
1405 t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err)
1406 continue
1407 }
1408
1409 if err == nil && test.expectError {
1410 t.Errorf("unexpected success for test #%d: domain=%s, constraint=%s", i, test.domain, test.constraint)
1411 continue
1412 }
1413
1414 if result != test.shouldMatch {
1415 t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
1416 }
1417 }
1418 }
1419
1420 const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
1421 MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1422 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
1423 CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
1424 ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
1425 gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
1426 8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
1427 +G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
1428 czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
1429 tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
1430 AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
1431 MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
1432 XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
1433 dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
1434 v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
1435 jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
1436 fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
1437 IuYkJwt6w+LH/9HZgf8=
1438 -----END CERTIFICATE-----`
1439 const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
1440 MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1441 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
1442 CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
1443 7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
1444 8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
1445 gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
1446 xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
1447 g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
1448 46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
1449 CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
1450 A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
1451 bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
1452 wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
1453 rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
1454 DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
1455 29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
1456 -----END CERTIFICATE-----`
1457 const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
1458 MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
1459 MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
1460 IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
1461 fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
1462 35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
1463 2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
1464 S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
1465 kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
1466 AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
1467 AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
1468 BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
1469 4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
1470 9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
1471 w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
1472 4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
1473 8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
1474 -----END CERTIFICATE-----`
1475
1476 const criticalExtRoot = `-----BEGIN CERTIFICATE-----
1477 MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1478 A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1479 MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
1480 CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
1481 gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
1482 BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
1483 /zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
1484 uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
1485 FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
1486 -----END CERTIFICATE-----`
1487
1488 const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
1489 MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
1490 A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
1491 MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
1492 KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
1493 rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
1494 AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
1495 Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
1496 EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
1497 cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
1498 xXbdbm27KQ==
1499 -----END CERTIFICATE-----`
1500
1501 const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
1502 MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
1503 A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
1504 MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
1505 bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
1506 6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
1507 gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
1508 AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
1509 IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
1510 SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
1511 I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
1512 -----END CERTIFICATE-----`
1513
1514 const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
1515 MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
1516 T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
1517 MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
1518 cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
1519 mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
1520 oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
1521 BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
1522 UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
1523 BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
1524 c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
1525 -----END CERTIFICATE-----`
1526
1527 const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
1528 MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
1529 A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
1530 aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
1531 T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
1532 A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
1533 GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
1534 FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
1535 UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
1536 CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
1537 2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
1538 -----END CERTIFICATE-----`
1539
1540 func TestValidHostname(t *testing.T) {
1541 tests := []struct {
1542 host string
1543 validInput, validPattern bool
1544 }{
1545 {host: "example.com", validInput: true, validPattern: true},
1546 {host: "eXample123-.com", validInput: true, validPattern: true},
1547 {host: "-eXample123-.com"},
1548 {host: ""},
1549 {host: "."},
1550 {host: "example..com"},
1551 {host: ".example.com"},
1552 {host: "example.com.", validInput: true},
1553 {host: "*.example.com."},
1554 {host: "*.example.com", validPattern: true},
1555 {host: "*foo.example.com"},
1556 {host: "foo.*.example.com"},
1557 {host: "exa_mple.com", validInput: true, validPattern: true},
1558 {host: "foo,bar"},
1559 {host: "project-dev:us-central1:main"},
1560 }
1561 for _, tt := range tests {
1562 if got := validHostnamePattern(tt.host); got != tt.validPattern {
1563 t.Errorf("validHostnamePattern(%q) = %v, want %v", tt.host, got, tt.validPattern)
1564 }
1565 if got := validHostnameInput(tt.host); got != tt.validInput {
1566 t.Errorf("validHostnameInput(%q) = %v, want %v", tt.host, got, tt.validInput)
1567 }
1568 }
1569 }
1570
1571 func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
1572 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1573 if err != nil {
1574 return nil, nil, err
1575 }
1576
1577 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
1578 serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
1579
1580 template := &Certificate{
1581 SerialNumber: serialNumber,
1582 Subject: pkix.Name{CommonName: cn},
1583 NotBefore: time.Now().Add(-1 * time.Hour),
1584 NotAfter: time.Now().Add(24 * time.Hour),
1585
1586 KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
1587 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
1588 BasicConstraintsValid: true,
1589 IsCA: isCA,
1590 }
1591 if issuer == nil {
1592 issuer = template
1593 issuerKey = priv
1594 }
1595
1596 derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
1597 if err != nil {
1598 return nil, nil, err
1599 }
1600 cert, err := ParseCertificate(derBytes)
1601 if err != nil {
1602 return nil, nil, err
1603 }
1604
1605 return cert, priv, nil
1606 }
1607
1608 func TestPathologicalChain(t *testing.T) {
1609 if testing.Short() {
1610 t.Skip("skipping generation of a long chain of certificates in short mode")
1611 }
1612
1613
1614
1615 roots, intermediates := NewCertPool(), NewCertPool()
1616
1617 parent, parentKey, err := generateCert("Root CA", true, nil, nil)
1618 if err != nil {
1619 t.Fatal(err)
1620 }
1621 roots.AddCert(parent)
1622
1623 for i := 1; i < 100; i++ {
1624 parent, parentKey, err = generateCert("Intermediate CA", 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 _, err = leaf.Verify(VerifyOptions{
1638 Roots: roots,
1639 Intermediates: intermediates,
1640 })
1641 t.Logf("verification took %v", time.Since(start))
1642
1643 if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
1644 t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
1645 }
1646 }
1647
1648 func TestLongChain(t *testing.T) {
1649 if testing.Short() {
1650 t.Skip("skipping generation of a long chain of certificates in short mode")
1651 }
1652
1653 roots, intermediates := NewCertPool(), NewCertPool()
1654
1655 parent, parentKey, err := generateCert("Root CA", true, nil, nil)
1656 if err != nil {
1657 t.Fatal(err)
1658 }
1659 roots.AddCert(parent)
1660
1661 for i := 1; i < 15; i++ {
1662 name := fmt.Sprintf("Intermediate CA #%d", i)
1663 parent, parentKey, err = generateCert(name, true, parent, parentKey)
1664 if err != nil {
1665 t.Fatal(err)
1666 }
1667 intermediates.AddCert(parent)
1668 }
1669
1670 leaf, _, err := generateCert("Leaf", false, parent, parentKey)
1671 if err != nil {
1672 t.Fatal(err)
1673 }
1674
1675 start := time.Now()
1676 if _, err := leaf.Verify(VerifyOptions{
1677 Roots: roots,
1678 Intermediates: intermediates,
1679 }); err != nil {
1680 t.Error(err)
1681 }
1682 t.Logf("verification took %v", time.Since(start))
1683 }
1684
1685 func TestSystemRootsError(t *testing.T) {
1686 if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
1687 t.Skip("Windows and darwin do not use (or support) systemRoots")
1688 }
1689
1690 defer func(oldSystemRoots *CertPool) { systemRoots = oldSystemRoots }(systemRootsPool())
1691
1692 opts := VerifyOptions{
1693 Intermediates: NewCertPool(),
1694 DNSName: "www.google.com",
1695 CurrentTime: time.Unix(1677615892, 0),
1696 }
1697
1698 if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
1699 t.Fatalf("failed to parse intermediate")
1700 }
1701
1702 leaf, err := certificateFromPEM(googleLeaf)
1703 if err != nil {
1704 t.Fatalf("failed to parse leaf: %v", err)
1705 }
1706
1707 systemRoots = nil
1708
1709 _, err = leaf.Verify(opts)
1710 if _, ok := err.(SystemRootsError); !ok {
1711 t.Errorf("error was not SystemRootsError: %v", err)
1712 }
1713 }
1714
1715 func TestSystemRootsErrorUnwrap(t *testing.T) {
1716 var err1 = errors.New("err1")
1717 err := SystemRootsError{Err: err1}
1718 if !errors.Is(err, err1) {
1719 t.Error("errors.Is failed, wanted success")
1720 }
1721 }
1722
1723 func macosMajorVersion(t *testing.T) (int, error) {
1724 cmd := testenv.Command(t, "sw_vers", "-productVersion")
1725 out, err := cmd.Output()
1726 if err != nil {
1727 if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
1728 return 0, fmt.Errorf("%v: %v\n%s", cmd, err, ee.Stderr)
1729 }
1730 return 0, fmt.Errorf("%v: %v", cmd, err)
1731 }
1732 before, _, ok := strings.Cut(string(out), ".")
1733 major, err := strconv.Atoi(before)
1734 if !ok || err != nil {
1735 return 0, fmt.Errorf("%v: unexpected output: %q", cmd, out)
1736 }
1737
1738 return major, nil
1739 }
1740
1741 func TestIssue51759(t *testing.T) {
1742 if runtime.GOOS != "darwin" {
1743 t.Skip("only affects darwin")
1744 }
1745
1746 testenv.MustHaveExecPath(t, "sw_vers")
1747 if vers, err := macosMajorVersion(t); err != nil {
1748 if builder := testenv.Builder(); builder != "" {
1749 t.Fatalf("unable to determine macOS version: %s", err)
1750 } else {
1751 t.Skip("unable to determine macOS version")
1752 }
1753 } else if vers < 11 {
1754 t.Skip("behavior only enforced in macOS 11 and after")
1755 }
1756
1757
1758
1759 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"
1760 badCert, err := ParseCertificate([]byte(badCertData))
1761 if err != nil {
1762 t.Fatal(err)
1763 }
1764
1765 t.Run("leaf", func(t *testing.T) {
1766 opts := VerifyOptions{}
1767 expectedErr := "invalid leaf certificate"
1768 _, err = badCert.Verify(opts)
1769 if err == nil || err.Error() != expectedErr {
1770 t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
1771 }
1772 })
1773
1774 goodCert, err := certificateFromPEM(googleLeaf)
1775 if err != nil {
1776 t.Fatal(err)
1777 }
1778
1779 t.Run("intermediate", func(t *testing.T) {
1780 opts := VerifyOptions{
1781 Intermediates: NewCertPool(),
1782 }
1783 opts.Intermediates.AddCert(badCert)
1784 expectedErr := "SecCertificateCreateWithData: invalid certificate"
1785 _, err = goodCert.Verify(opts)
1786 if err == nil || err.Error() != expectedErr {
1787 t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
1788 }
1789 })
1790 }
1791
1792 type trustGraphEdge struct {
1793 Issuer string
1794 Subject string
1795 Type int
1796 MutateTemplate func(*Certificate)
1797 Constraint func([]*Certificate) error
1798 }
1799
1800 type rootDescription struct {
1801 Subject string
1802 MutateTemplate func(*Certificate)
1803 Constraint func([]*Certificate) error
1804 }
1805
1806 type trustGraphDescription struct {
1807 Roots []rootDescription
1808 Leaf string
1809 Graph []trustGraphEdge
1810 }
1811
1812 func genCertEdge(t *testing.T, subject string, key crypto.Signer, mutateTmpl func(*Certificate), certType int, issuer *Certificate, signer crypto.Signer) *Certificate {
1813 t.Helper()
1814
1815 serial, err := rand.Int(rand.Reader, big.NewInt(100))
1816 if err != nil {
1817 t.Fatalf("failed to generate test serial: %s", err)
1818 }
1819 tmpl := &Certificate{
1820 SerialNumber: serial,
1821 Subject: pkix.Name{CommonName: subject},
1822 NotBefore: time.Now().Add(-time.Hour),
1823 NotAfter: time.Now().Add(time.Hour),
1824 }
1825 if certType == rootCertificate || certType == intermediateCertificate {
1826 tmpl.IsCA, tmpl.BasicConstraintsValid = true, true
1827 tmpl.KeyUsage = KeyUsageCertSign
1828 } else if certType == leafCertificate {
1829 tmpl.DNSNames = []string{"localhost"}
1830 }
1831 if mutateTmpl != nil {
1832 mutateTmpl(tmpl)
1833 }
1834
1835 if certType == rootCertificate {
1836 issuer = tmpl
1837 signer = key
1838 }
1839
1840 d, err := CreateCertificate(rand.Reader, tmpl, issuer, key.Public(), signer)
1841 if err != nil {
1842 t.Fatalf("failed to generate test cert: %s", err)
1843 }
1844 c, err := ParseCertificate(d)
1845 if err != nil {
1846 t.Fatalf("failed to parse test cert: %s", err)
1847 }
1848 return c
1849 }
1850
1851 func buildTrustGraph(t *testing.T, d trustGraphDescription) (*CertPool, *CertPool, *Certificate) {
1852 t.Helper()
1853
1854 certs := map[string]*Certificate{}
1855 keys := map[string]crypto.Signer{}
1856 rootPool := NewCertPool()
1857 for _, r := range d.Roots {
1858 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1859 if err != nil {
1860 t.Fatalf("failed to generate test key: %s", err)
1861 }
1862 root := genCertEdge(t, r.Subject, k, r.MutateTemplate, rootCertificate, nil, nil)
1863 if r.Constraint != nil {
1864 rootPool.AddCertWithConstraint(root, r.Constraint)
1865 } else {
1866 rootPool.AddCert(root)
1867 }
1868 certs[r.Subject] = root
1869 keys[r.Subject] = k
1870 }
1871
1872 intermediatePool := NewCertPool()
1873 var leaf *Certificate
1874 for _, e := range d.Graph {
1875 issuerCert, ok := certs[e.Issuer]
1876 if !ok {
1877 t.Fatalf("unknown issuer %s", e.Issuer)
1878 }
1879 issuerKey, ok := keys[e.Issuer]
1880 if !ok {
1881 t.Fatalf("unknown issuer %s", e.Issuer)
1882 }
1883
1884 k, ok := keys[e.Subject]
1885 if !ok {
1886 var err error
1887 k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1888 if err != nil {
1889 t.Fatalf("failed to generate test key: %s", err)
1890 }
1891 keys[e.Subject] = k
1892 }
1893 cert := genCertEdge(t, e.Subject, k, e.MutateTemplate, e.Type, issuerCert, issuerKey)
1894 certs[e.Subject] = cert
1895 if e.Subject == d.Leaf {
1896 leaf = cert
1897 } else {
1898 if e.Constraint != nil {
1899 intermediatePool.AddCertWithConstraint(cert, e.Constraint)
1900 } else {
1901 intermediatePool.AddCert(cert)
1902 }
1903 }
1904 }
1905
1906 return rootPool, intermediatePool, leaf
1907 }
1908
1909 func chainsToStrings(chains [][]*Certificate) []string {
1910 chainStrings := []string{}
1911 for _, chain := range chains {
1912 names := []string{}
1913 for _, c := range chain {
1914 names = append(names, c.Subject.String())
1915 }
1916 chainStrings = append(chainStrings, strings.Join(names, " -> "))
1917 }
1918 slices.Sort(chainStrings)
1919 return chainStrings
1920 }
1921
1922 func TestPathBuilding(t *testing.T) {
1923 tests := []struct {
1924 name string
1925 graph trustGraphDescription
1926 expectedChains []string
1927 expectedErr string
1928 }{
1929 {
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955 name: "bad EKU",
1956 graph: trustGraphDescription{
1957 Roots: []rootDescription{{Subject: "root"}},
1958 Leaf: "leaf",
1959 Graph: []trustGraphEdge{
1960 {
1961 Issuer: "root",
1962 Subject: "inter a",
1963 Type: intermediateCertificate,
1964 },
1965 {
1966 Issuer: "root",
1967 Subject: "inter c",
1968 Type: intermediateCertificate,
1969 },
1970 {
1971 Issuer: "inter c",
1972 Subject: "inter a",
1973 Type: intermediateCertificate,
1974 },
1975 {
1976 Issuer: "inter a",
1977 Subject: "inter c",
1978 Type: intermediateCertificate,
1979 },
1980 {
1981 Issuer: "inter c",
1982 Subject: "inter b",
1983 Type: intermediateCertificate,
1984 MutateTemplate: func(t *Certificate) {
1985 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
1986 },
1987 },
1988 {
1989 Issuer: "inter a",
1990 Subject: "inter b",
1991 Type: intermediateCertificate,
1992 },
1993 {
1994 Issuer: "inter b",
1995 Subject: "leaf",
1996 Type: leafCertificate,
1997 },
1998 },
1999 },
2000 expectedChains: []string{
2001 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
2002 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2003 },
2004 },
2005 {
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031 name: "bad EKU",
2032 graph: trustGraphDescription{
2033 Roots: []rootDescription{{Subject: "root"}},
2034 Leaf: "leaf",
2035 Graph: []trustGraphEdge{
2036 {
2037 Issuer: "root",
2038 Subject: "inter a",
2039 Type: intermediateCertificate,
2040 },
2041 {
2042 Issuer: "root",
2043 Subject: "inter c",
2044 Type: intermediateCertificate,
2045 },
2046 {
2047 Issuer: "inter c",
2048 Subject: "inter a",
2049 Type: intermediateCertificate,
2050 },
2051 {
2052 Issuer: "inter a",
2053 Subject: "inter c",
2054 Type: intermediateCertificate,
2055 },
2056 {
2057 Issuer: "inter c",
2058 Subject: "inter b",
2059 Type: intermediateCertificate,
2060 MutateTemplate: func(t *Certificate) {
2061 t.PermittedDNSDomains = []string{"good"}
2062 t.DNSNames = []string{"bad"}
2063 },
2064 },
2065 {
2066 Issuer: "inter a",
2067 Subject: "inter b",
2068 Type: intermediateCertificate,
2069 },
2070 {
2071 Issuer: "inter b",
2072 Subject: "leaf",
2073 Type: leafCertificate,
2074 },
2075 },
2076 },
2077 expectedChains: []string{
2078 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
2079 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2080 },
2081 },
2082 {
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113 name: "all paths",
2114 graph: trustGraphDescription{
2115 Roots: []rootDescription{{Subject: "root"}},
2116 Leaf: "leaf",
2117 Graph: []trustGraphEdge{
2118 {
2119 Issuer: "root",
2120 Subject: "inter a",
2121 Type: intermediateCertificate,
2122 },
2123 {
2124 Issuer: "inter a",
2125 Subject: "inter b",
2126 Type: intermediateCertificate,
2127 },
2128 {
2129 Issuer: "inter a",
2130 Subject: "inter c",
2131 Type: intermediateCertificate,
2132 },
2133 {
2134 Issuer: "inter b",
2135 Subject: "inter c",
2136 Type: intermediateCertificate,
2137 },
2138 {
2139 Issuer: "inter c",
2140 Subject: "leaf",
2141 Type: leafCertificate,
2142 },
2143 },
2144 },
2145 expectedChains: []string{
2146 "CN=leaf -> CN=inter c -> CN=inter a -> CN=root",
2147 "CN=leaf -> CN=inter c -> CN=inter b -> CN=inter a -> CN=root",
2148 },
2149 },
2150 {
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177 name: "ignore cross-sig loops",
2178 graph: trustGraphDescription{
2179 Roots: []rootDescription{{Subject: "root"}},
2180 Leaf: "leaf",
2181 Graph: []trustGraphEdge{
2182 {
2183 Issuer: "root",
2184 Subject: "inter a",
2185 Type: intermediateCertificate,
2186 },
2187 {
2188 Issuer: "root",
2189 Subject: "inter c",
2190 Type: intermediateCertificate,
2191 },
2192 {
2193 Issuer: "inter c",
2194 Subject: "inter a",
2195 Type: intermediateCertificate,
2196 },
2197 {
2198 Issuer: "inter a",
2199 Subject: "inter c",
2200 Type: intermediateCertificate,
2201 },
2202 {
2203 Issuer: "inter c",
2204 Subject: "inter b",
2205 Type: intermediateCertificate,
2206 },
2207 {
2208 Issuer: "inter a",
2209 Subject: "inter b",
2210 Type: intermediateCertificate,
2211 },
2212 {
2213 Issuer: "inter b",
2214 Subject: "leaf",
2215 Type: leafCertificate,
2216 },
2217 },
2218 },
2219 expectedChains: []string{
2220 "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
2221 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2222 "CN=leaf -> CN=inter b -> CN=inter c -> CN=inter a -> CN=root",
2223 "CN=leaf -> CN=inter b -> CN=inter c -> CN=root",
2224 },
2225 },
2226 {
2227
2228
2229
2230 name: "leaf with same subject, key, as parent but with SAN",
2231 graph: trustGraphDescription{
2232 Roots: []rootDescription{{Subject: "root"}},
2233 Leaf: "root",
2234 Graph: []trustGraphEdge{
2235 {
2236 Issuer: "root",
2237 Subject: "root",
2238 Type: leafCertificate,
2239 MutateTemplate: func(c *Certificate) {
2240 c.DNSNames = []string{"localhost"}
2241 },
2242 },
2243 },
2244 },
2245 expectedChains: []string{
2246 "CN=root -> CN=root",
2247 },
2248 },
2249 {
2250
2251
2252 name: "ignore invalid EKU path",
2253 graph: trustGraphDescription{
2254 Roots: []rootDescription{{Subject: "root"}},
2255 Leaf: "leaf",
2256 Graph: []trustGraphEdge{
2257 {
2258 Issuer: "root",
2259 Subject: "inter a",
2260 Type: intermediateCertificate,
2261 },
2262 {
2263 Issuer: "root",
2264 Subject: "inter c",
2265 Type: intermediateCertificate,
2266 },
2267 {
2268 Issuer: "inter c",
2269 Subject: "inter b",
2270 Type: intermediateCertificate,
2271 MutateTemplate: func(t *Certificate) {
2272 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
2273 },
2274 },
2275 {
2276 Issuer: "inter a",
2277 Subject: "inter b",
2278 Type: intermediateCertificate,
2279 MutateTemplate: func(t *Certificate) {
2280 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
2281 },
2282 },
2283 {
2284 Issuer: "inter b",
2285 Subject: "leaf",
2286 Type: leafCertificate,
2287 MutateTemplate: func(t *Certificate) {
2288 t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
2289 },
2290 },
2291 },
2292 },
2293 expectedChains: []string{
2294 "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
2295 },
2296 },
2297 {
2298
2299
2300 name: "constrained root, invalid intermediate",
2301 graph: trustGraphDescription{
2302 Roots: []rootDescription{
2303 {
2304 Subject: "root",
2305 MutateTemplate: func(t *Certificate) {
2306 t.PermittedDNSDomains = []string{"example.com"}
2307 },
2308 },
2309 },
2310 Leaf: "leaf",
2311 Graph: []trustGraphEdge{
2312 {
2313 Issuer: "root",
2314 Subject: "inter",
2315 Type: intermediateCertificate,
2316 MutateTemplate: func(t *Certificate) {
2317 t.DNSNames = []string{"beep.com"}
2318 },
2319 },
2320 {
2321 Issuer: "inter",
2322 Subject: "leaf",
2323 Type: leafCertificate,
2324 MutateTemplate: func(t *Certificate) {
2325 t.DNSNames = []string{"www.example.com"}
2326 },
2327 },
2328 },
2329 },
2330 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",
2331 },
2332 {
2333
2334
2335 name: "constrained intermediate, non-matching SAN",
2336 graph: trustGraphDescription{
2337 Roots: []rootDescription{{Subject: "root"}},
2338 Leaf: "leaf",
2339 Graph: []trustGraphEdge{
2340 {
2341 Issuer: "root",
2342 Subject: "inter",
2343 Type: intermediateCertificate,
2344 MutateTemplate: func(t *Certificate) {
2345 t.DNSNames = []string{"beep.com"}
2346 t.PermittedDNSDomains = []string{"example.com"}
2347 },
2348 },
2349 {
2350 Issuer: "inter",
2351 Subject: "leaf",
2352 Type: leafCertificate,
2353 MutateTemplate: func(t *Certificate) {
2354 t.DNSNames = []string{"www.example.com"}
2355 },
2356 },
2357 },
2358 },
2359 expectedChains: []string{"CN=leaf -> CN=inter -> CN=root"},
2360 },
2361 {
2362
2363
2364 name: "code constrained root, two paths, one valid",
2365 graph: trustGraphDescription{
2366 Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
2367 for _, c := range chain {
2368 if c.Subject.CommonName == "inter a" {
2369 return errors.New("bad")
2370 }
2371 }
2372 return nil
2373 }}},
2374 Leaf: "leaf",
2375 Graph: []trustGraphEdge{
2376 {
2377 Issuer: "root",
2378 Subject: "inter a",
2379 Type: intermediateCertificate,
2380 },
2381 {
2382 Issuer: "root",
2383 Subject: "inter b",
2384 Type: intermediateCertificate,
2385 },
2386 {
2387 Issuer: "inter a",
2388 Subject: "inter c",
2389 Type: intermediateCertificate,
2390 },
2391 {
2392 Issuer: "inter b",
2393 Subject: "inter c",
2394 Type: intermediateCertificate,
2395 },
2396 {
2397 Issuer: "inter c",
2398 Subject: "leaf",
2399 Type: leafCertificate,
2400 },
2401 },
2402 },
2403 expectedChains: []string{"CN=leaf -> CN=inter c -> CN=inter b -> CN=root"},
2404 },
2405 {
2406
2407 name: "code constrained root, one invalid path",
2408 graph: trustGraphDescription{
2409 Roots: []rootDescription{{Subject: "root", Constraint: func(chain []*Certificate) error {
2410 for _, c := range chain {
2411 if c.Subject.CommonName == "leaf" {
2412 return errors.New("bad")
2413 }
2414 }
2415 return nil
2416 }}},
2417 Leaf: "leaf",
2418 Graph: []trustGraphEdge{
2419 {
2420 Issuer: "root",
2421 Subject: "inter",
2422 Type: intermediateCertificate,
2423 },
2424 {
2425 Issuer: "inter",
2426 Subject: "leaf",
2427 Type: leafCertificate,
2428 },
2429 },
2430 },
2431 expectedErr: "x509: certificate signed by unknown authority (possibly because of \"bad\" while trying to verify candidate authority certificate \"root\")",
2432 },
2433 }
2434
2435 for _, tc := range tests {
2436 t.Run(tc.name, func(t *testing.T) {
2437 roots, intermediates, leaf := buildTrustGraph(t, tc.graph)
2438 chains, err := leaf.Verify(VerifyOptions{
2439 Roots: roots,
2440 Intermediates: intermediates,
2441 })
2442 if err != nil && err.Error() != tc.expectedErr {
2443 t.Fatalf("unexpected error: got %q, want %q", err, tc.expectedErr)
2444 }
2445 if len(tc.expectedChains) == 0 {
2446 return
2447 }
2448 gotChains := chainsToStrings(chains)
2449 if !slices.Equal(gotChains, tc.expectedChains) {
2450 t.Errorf("unexpected chains returned:\ngot:\n\t%s\nwant:\n\t%s", strings.Join(gotChains, "\n\t"), strings.Join(tc.expectedChains, "\n\t"))
2451 }
2452 })
2453 }
2454 }
2455
2456 func TestEKUEnforcement(t *testing.T) {
2457 type ekuDescs struct {
2458 EKUs []ExtKeyUsage
2459 Unknown []asn1.ObjectIdentifier
2460 }
2461 tests := []struct {
2462 name string
2463 root ekuDescs
2464 inters []ekuDescs
2465 leaf ekuDescs
2466 verifyEKUs []ExtKeyUsage
2467 err string
2468 }{
2469 {
2470 name: "valid, full chain",
2471 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2472 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}}},
2473 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2474 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2475 },
2476 {
2477 name: "valid, only leaf has EKU",
2478 root: ekuDescs{},
2479 inters: []ekuDescs{ekuDescs{}},
2480 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2481 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2482 },
2483 {
2484 name: "invalid, serverAuth not nested",
2485 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2486 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
2487 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2488 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2489 err: "x509: certificate specifies an incompatible key usage",
2490 },
2491 {
2492 name: "valid, two EKUs, one path",
2493 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2494 inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
2495 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2496 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2497 },
2498 {
2499 name: "invalid, ladder",
2500 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2501 inters: []ekuDescs{
2502 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2503 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2504 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
2505 ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2506 },
2507 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2508 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2509 err: "x509: certificate specifies an incompatible key usage",
2510 },
2511 {
2512 name: "valid, intermediate has no EKU",
2513 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2514 inters: []ekuDescs{ekuDescs{}},
2515 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2516 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2517 },
2518 {
2519 name: "invalid, intermediate has no EKU and no nested path",
2520 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
2521 inters: []ekuDescs{ekuDescs{}},
2522 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2523 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
2524 err: "x509: certificate specifies an incompatible key usage",
2525 },
2526 {
2527 name: "invalid, intermediate has unknown EKU",
2528 root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2529 inters: []ekuDescs{ekuDescs{Unknown: []asn1.ObjectIdentifier{{1, 2, 3}}}},
2530 leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
2531 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2532 err: "x509: certificate specifies an incompatible key usage",
2533 },
2534 }
2535
2536 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2537 if err != nil {
2538 t.Fatalf("failed to generate test key: %s", err)
2539 }
2540
2541 for _, tc := range tests {
2542 t.Run(tc.name, func(t *testing.T) {
2543 rootPool := NewCertPool()
2544 root := genCertEdge(t, "root", k, func(c *Certificate) {
2545 c.ExtKeyUsage = tc.root.EKUs
2546 c.UnknownExtKeyUsage = tc.root.Unknown
2547 }, rootCertificate, nil, k)
2548 rootPool.AddCert(root)
2549
2550 parent := root
2551 interPool := NewCertPool()
2552 for i, interEKUs := range tc.inters {
2553 inter := genCertEdge(t, fmt.Sprintf("inter %d", i), k, func(c *Certificate) {
2554 c.ExtKeyUsage = interEKUs.EKUs
2555 c.UnknownExtKeyUsage = interEKUs.Unknown
2556 }, intermediateCertificate, parent, k)
2557 interPool.AddCert(inter)
2558 parent = inter
2559 }
2560
2561 leaf := genCertEdge(t, "leaf", k, func(c *Certificate) {
2562 c.ExtKeyUsage = tc.leaf.EKUs
2563 c.UnknownExtKeyUsage = tc.leaf.Unknown
2564 }, intermediateCertificate, parent, k)
2565
2566 _, err := leaf.Verify(VerifyOptions{Roots: rootPool, Intermediates: interPool, KeyUsages: tc.verifyEKUs})
2567 if err == nil && tc.err != "" {
2568 t.Errorf("expected error")
2569 } else if err != nil && err.Error() != tc.err {
2570 t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.err)
2571 }
2572 })
2573 }
2574 }
2575
2576 func TestVerifyEKURootAsLeaf(t *testing.T) {
2577 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2578 if err != nil {
2579 t.Fatalf("failed to generate key: %s", err)
2580 }
2581
2582 for _, tc := range []struct {
2583 rootEKUs []ExtKeyUsage
2584 verifyEKUs []ExtKeyUsage
2585 succeed bool
2586 }{
2587 {
2588 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2589 succeed: true,
2590 },
2591 {
2592 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2593 succeed: true,
2594 },
2595 {
2596 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2597 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2598 succeed: true,
2599 },
2600 {
2601 rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2602 verifyEKUs: []ExtKeyUsage{ExtKeyUsageAny},
2603 succeed: true,
2604 },
2605 {
2606 rootEKUs: []ExtKeyUsage{ExtKeyUsageAny},
2607 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2608 succeed: true,
2609 },
2610 {
2611 rootEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
2612 verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
2613 succeed: false,
2614 },
2615 } {
2616 t.Run(fmt.Sprintf("root EKUs %#v, verify EKUs %#v", tc.rootEKUs, tc.verifyEKUs), func(t *testing.T) {
2617 tmpl := &Certificate{
2618 SerialNumber: big.NewInt(1),
2619 Subject: pkix.Name{CommonName: "root"},
2620 NotBefore: time.Now().Add(-time.Hour),
2621 NotAfter: time.Now().Add(time.Hour),
2622 DNSNames: []string{"localhost"},
2623 ExtKeyUsage: tc.rootEKUs,
2624 }
2625 rootDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
2626 if err != nil {
2627 t.Fatalf("failed to create certificate: %s", err)
2628 }
2629 root, err := ParseCertificate(rootDER)
2630 if err != nil {
2631 t.Fatalf("failed to parse certificate: %s", err)
2632 }
2633 roots := NewCertPool()
2634 roots.AddCert(root)
2635
2636 _, err = root.Verify(VerifyOptions{Roots: roots, KeyUsages: tc.verifyEKUs})
2637 if err == nil && !tc.succeed {
2638 t.Error("verification succeed")
2639 } else if err != nil && tc.succeed {
2640 t.Errorf("verification failed: %q", err)
2641 }
2642 })
2643 }
2644
2645 }
2646
2647 func TestVerifyNilPubKey(t *testing.T) {
2648 c := &Certificate{
2649 RawIssuer: []byte{1, 2, 3},
2650 AuthorityKeyId: []byte{1, 2, 3},
2651 }
2652 opts := &VerifyOptions{}
2653 opts.Roots = NewCertPool()
2654 r := &Certificate{
2655 RawSubject: []byte{1, 2, 3},
2656 SubjectKeyId: []byte{1, 2, 3},
2657 }
2658 opts.Roots.AddCert(r)
2659
2660 _, err := c.buildChains([]*Certificate{r}, nil, opts)
2661 if _, ok := err.(UnknownAuthorityError); !ok {
2662 t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
2663 }
2664 }
2665
2666 func TestVerifyBareWildcard(t *testing.T) {
2667 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2668 if err != nil {
2669 t.Fatalf("failed to generate key: %s", err)
2670 }
2671 tmpl := &Certificate{
2672 SerialNumber: big.NewInt(1),
2673 Subject: pkix.Name{CommonName: "test"},
2674 NotBefore: time.Now().Add(-time.Hour),
2675 NotAfter: time.Now().Add(time.Hour),
2676 DNSNames: []string{"*"},
2677 }
2678 cDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
2679 if err != nil {
2680 t.Fatalf("failed to create certificate: %s", err)
2681 }
2682 c, err := ParseCertificate(cDER)
2683 if err != nil {
2684 t.Fatalf("failed to parse certificate: %s", err)
2685 }
2686
2687 if err := c.VerifyHostname("label"); err == nil {
2688 t.Fatalf("VerifyHostname unexpected success with bare wildcard SAN")
2689 }
2690 }
2691
2692 func TestPoliciesValid(t *testing.T) {
2693
2694
2695
2696
2697
2698
2699
2700 testOID1 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 1})
2701 testOID2 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 2})
2702 testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3})
2703 testOID4 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 4})
2704 testOID5 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 5})
2705
2706 loadTestCert := func(t *testing.T, path string) *Certificate {
2707 b, err := os.ReadFile(path)
2708 if err != nil {
2709 t.Fatal(err)
2710 }
2711 p, _ := pem.Decode(b)
2712 c, err := ParseCertificate(p.Bytes)
2713 if err != nil {
2714 t.Fatal(err)
2715 }
2716 return c
2717 }
2718
2719 root := loadTestCert(t, "testdata/policy_root.pem")
2720 root_cross_inhibit_mapping := loadTestCert(t, "testdata/policy_root_cross_inhibit_mapping.pem")
2721 root2 := loadTestCert(t, "testdata/policy_root2.pem")
2722 intermediate := loadTestCert(t, "testdata/policy_intermediate.pem")
2723 intermediate_any := loadTestCert(t, "testdata/policy_intermediate_any.pem")
2724 intermediate_mapped := loadTestCert(t, "testdata/policy_intermediate_mapped.pem")
2725 intermediate_mapped_any := loadTestCert(t, "testdata/policy_intermediate_mapped_any.pem")
2726 intermediate_mapped_oid3 := loadTestCert(t, "testdata/policy_intermediate_mapped_oid3.pem")
2727 intermediate_require := loadTestCert(t, "testdata/policy_intermediate_require.pem")
2728 intermediate_require1 := loadTestCert(t, "testdata/policy_intermediate_require1.pem")
2729 intermediate_require2 := loadTestCert(t, "testdata/policy_intermediate_require2.pem")
2730 intermediate_require_no_policies := loadTestCert(t, "testdata/policy_intermediate_require_no_policies.pem")
2731 leaf := loadTestCert(t, "testdata/policy_leaf.pem")
2732 leaf_any := loadTestCert(t, "testdata/policy_leaf_any.pem")
2733 leaf_none := loadTestCert(t, "testdata/policy_leaf_none.pem")
2734 leaf_oid1 := loadTestCert(t, "testdata/policy_leaf_oid1.pem")
2735 leaf_oid2 := loadTestCert(t, "testdata/policy_leaf_oid2.pem")
2736 leaf_oid3 := loadTestCert(t, "testdata/policy_leaf_oid3.pem")
2737 leaf_oid4 := loadTestCert(t, "testdata/policy_leaf_oid4.pem")
2738 leaf_oid5 := loadTestCert(t, "testdata/policy_leaf_oid5.pem")
2739 leaf_require := loadTestCert(t, "testdata/policy_leaf_require.pem")
2740 leaf_require1 := loadTestCert(t, "testdata/policy_leaf_require1.pem")
2741
2742 type testCase struct {
2743 chain []*Certificate
2744 policies []OID
2745 requireExplicitPolicy bool
2746 inhibitPolicyMapping bool
2747 inhibitAnyPolicy bool
2748 valid bool
2749 }
2750
2751 tests := []testCase{
2752
2753 {
2754 chain: []*Certificate{leaf, intermediate, root},
2755 requireExplicitPolicy: true,
2756 valid: true,
2757 },
2758 {
2759 chain: []*Certificate{leaf, intermediate, root},
2760 policies: []OID{testOID1},
2761 requireExplicitPolicy: true,
2762 valid: true,
2763 },
2764 {
2765 chain: []*Certificate{leaf, intermediate, root},
2766 policies: []OID{testOID2},
2767 requireExplicitPolicy: true,
2768 valid: true,
2769 },
2770 {
2771 chain: []*Certificate{leaf, intermediate, root},
2772 policies: []OID{testOID3},
2773 requireExplicitPolicy: true,
2774 valid: false,
2775 },
2776 {
2777 chain: []*Certificate{leaf, intermediate, root},
2778 policies: []OID{testOID1, testOID2},
2779 requireExplicitPolicy: true,
2780 valid: true,
2781 },
2782 {
2783 chain: []*Certificate{leaf, intermediate, root},
2784 policies: []OID{testOID1, testOID3},
2785 requireExplicitPolicy: true,
2786 valid: true,
2787 },
2788
2789
2790
2791 {
2792 chain: []*Certificate{leaf, intermediate, root},
2793 policies: []OID{testOID1},
2794 valid: true,
2795 },
2796 {
2797 chain: []*Certificate{leaf, intermediate, root},
2798 policies: []OID{testOID3},
2799 valid: true,
2800 },
2801
2802 {
2803 chain: []*Certificate{leaf, intermediate_require, root},
2804 policies: []OID{testOID1},
2805 valid: true,
2806 },
2807 {
2808 chain: []*Certificate{leaf, intermediate_require, root},
2809 policies: []OID{testOID3},
2810 valid: false,
2811 },
2812
2813
2814
2815 {
2816 chain: []*Certificate{leaf_none, intermediate_require, root},
2817 requireExplicitPolicy: true,
2818 valid: false,
2819 },
2820
2821 {
2822 chain: []*Certificate{leaf_require, intermediate, root},
2823 valid: true,
2824 },
2825 {
2826 chain: []*Certificate{leaf_require, intermediate, root},
2827 policies: []OID{testOID1},
2828 valid: true,
2829 },
2830 {
2831 chain: []*Certificate{leaf_require, intermediate, root},
2832 policies: []OID{testOID3},
2833 valid: false,
2834 },
2835
2836
2837 {
2838 chain: []*Certificate{leaf, intermediate_require1, root},
2839 policies: []OID{testOID3},
2840 valid: false,
2841 },
2842 {
2843 chain: []*Certificate{leaf, intermediate_require2, root},
2844 policies: []OID{testOID3},
2845 valid: true,
2846 },
2847 {
2848 chain: []*Certificate{leaf_require1, intermediate, root},
2849 policies: []OID{testOID3},
2850 valid: true,
2851 },
2852
2853
2854 {
2855 chain: []*Certificate{leaf_require1, intermediate_require1, root},
2856 policies: []OID{testOID3},
2857 valid: false,
2858 },
2859 {
2860 chain: []*Certificate{leaf_require, intermediate_require2, root},
2861 policies: []OID{testOID3},
2862 valid: false,
2863 },
2864
2865
2866 {
2867 chain: []*Certificate{leaf, intermediate_require_no_policies, root},
2868 policies: []OID{testOID1},
2869 valid: false,
2870 },
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880 {
2881 chain: []*Certificate{leaf_any, intermediate, root},
2882 policies: []OID{testOID1},
2883 requireExplicitPolicy: true,
2884 valid: true,
2885 },
2886 {
2887 chain: []*Certificate{leaf_any, intermediate, root},
2888 policies: []OID{testOID3},
2889 requireExplicitPolicy: true,
2890 valid: false,
2891 },
2892
2893
2894 {
2895 chain: []*Certificate{leaf, intermediate_any, root},
2896 policies: []OID{testOID1},
2897 requireExplicitPolicy: true,
2898 valid: true,
2899 },
2900 {
2901 chain: []*Certificate{leaf, intermediate_any, root},
2902 policies: []OID{testOID3},
2903 requireExplicitPolicy: true,
2904 valid: false,
2905 },
2906
2907 {
2908 chain: []*Certificate{leaf_any, intermediate_any, root},
2909 policies: []OID{testOID1},
2910 requireExplicitPolicy: true,
2911 valid: true,
2912 },
2913 {
2914 chain: []*Certificate{leaf_any, intermediate_any, root},
2915 policies: []OID{testOID3},
2916 requireExplicitPolicy: true,
2917 valid: true,
2918 },
2919
2920 {
2921 chain: []*Certificate{root},
2922 policies: []OID{testOID1},
2923 requireExplicitPolicy: true,
2924 valid: true,
2925 },
2926
2927
2928 {
2929 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root},
2930 policies: []OID{testOID3},
2931 requireExplicitPolicy: true,
2932 valid: true,
2933 },
2934 {
2935 chain: []*Certificate{leaf_oid4, intermediate_mapped_oid3, root},
2936 policies: []OID{testOID4},
2937 requireExplicitPolicy: true,
2938 valid: false,
2939 },
2940
2941
2942
2943 {
2944 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root},
2945 policies: []OID{testOID3},
2946 requireExplicitPolicy: true,
2947 inhibitPolicyMapping: true,
2948 valid: false,
2949 },
2950 {
2951 chain: []*Certificate{leaf_oid1, intermediate_mapped_oid3, root_cross_inhibit_mapping, root2},
2952 policies: []OID{testOID3},
2953 requireExplicitPolicy: true,
2954 valid: false,
2955 },
2956 }
2957
2958 for _, useAny := range []bool{false, true} {
2959 var intermediate *Certificate
2960 if useAny {
2961 intermediate = intermediate_mapped_any
2962 } else {
2963 intermediate = intermediate_mapped
2964 }
2965 extraTests := []testCase{
2966
2967
2968 {
2969 chain: []*Certificate{leaf, intermediate, root},
2970 policies: []OID{testOID3},
2971 requireExplicitPolicy: true,
2972 valid: true,
2973 },
2974 {
2975 chain: []*Certificate{leaf_oid1, intermediate, root},
2976 policies: []OID{testOID3},
2977 requireExplicitPolicy: true,
2978 valid: true,
2979 },
2980 {
2981 chain: []*Certificate{leaf_oid2, intermediate, root},
2982 policies: []OID{testOID3},
2983 requireExplicitPolicy: true,
2984 valid: true,
2985 },
2986
2987
2988
2989
2990
2991
2992
2993
2994 {
2995 chain: []*Certificate{leaf_oid3, intermediate, root},
2996 policies: []OID{testOID3},
2997 requireExplicitPolicy: true,
2998 valid: useAny,
2999 },
3000
3001
3002
3003
3004
3005
3006
3007 {
3008 chain: []*Certificate{leaf_oid1, intermediate, root},
3009 policies: []OID{testOID1},
3010 requireExplicitPolicy: true,
3011 valid: !useAny,
3012 },
3013
3014
3015 {
3016 chain: []*Certificate{leaf_oid4, intermediate, root},
3017 policies: []OID{testOID4},
3018 requireExplicitPolicy: true,
3019 valid: true,
3020 },
3021 {
3022 chain: []*Certificate{leaf_oid4, intermediate, root},
3023 policies: []OID{testOID5},
3024 requireExplicitPolicy: true,
3025 valid: true,
3026 },
3027 {
3028 chain: []*Certificate{leaf_oid5, intermediate, root},
3029 policies: []OID{testOID4},
3030 requireExplicitPolicy: true,
3031 valid: true,
3032 },
3033 {
3034 chain: []*Certificate{leaf_oid5, intermediate, root},
3035 policies: []OID{testOID5},
3036 requireExplicitPolicy: true,
3037 valid: true,
3038 },
3039 {
3040 chain: []*Certificate{leaf_oid4, intermediate, root},
3041 policies: []OID{testOID4, testOID5},
3042 requireExplicitPolicy: true,
3043 valid: true,
3044 },
3045 }
3046 tests = append(tests, extraTests...)
3047 }
3048
3049 for i, tc := range tests {
3050 t.Run(fmt.Sprint(i), func(t *testing.T) {
3051 valid := policiesValid(tc.chain, VerifyOptions{
3052 CertificatePolicies: tc.policies,
3053 requireExplicitPolicy: tc.requireExplicitPolicy,
3054 inhibitPolicyMapping: tc.inhibitPolicyMapping,
3055 inhibitAnyPolicy: tc.inhibitAnyPolicy,
3056 })
3057 if valid != tc.valid {
3058 t.Errorf("policiesValid: got %t, want %t", valid, tc.valid)
3059 }
3060 })
3061 }
3062 }
3063
3064 func TestInvalidPolicyWithAnyKeyUsage(t *testing.T) {
3065 loadTestCert := func(t *testing.T, path string) *Certificate {
3066 b, err := os.ReadFile(path)
3067 if err != nil {
3068 t.Fatal(err)
3069 }
3070 p, _ := pem.Decode(b)
3071 c, err := ParseCertificate(p.Bytes)
3072 if err != nil {
3073 t.Fatal(err)
3074 }
3075 return c
3076 }
3077
3078 testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3})
3079 root, intermediate, leaf := loadTestCert(t, "testdata/policy_root.pem"), loadTestCert(t, "testdata/policy_intermediate_require.pem"), loadTestCert(t, "testdata/policy_leaf.pem")
3080
3081 expectedErr := "x509: no valid chains built: all candidate chains have invalid policies"
3082
3083 roots, intermediates := NewCertPool(), NewCertPool()
3084 roots.AddCert(root)
3085 intermediates.AddCert(intermediate)
3086
3087 _, err := leaf.Verify(VerifyOptions{
3088 Roots: roots,
3089 Intermediates: intermediates,
3090 KeyUsages: []ExtKeyUsage{ExtKeyUsageAny},
3091 CertificatePolicies: []OID{testOID3},
3092 })
3093 if err == nil {
3094 t.Fatal("unexpected success, invalid policy shouldn't be bypassed by passing VerifyOptions.KeyUsages with ExtKeyUsageAny")
3095 } else if err.Error() != expectedErr {
3096 t.Fatalf("unexpected error, got %q, want %q", err, expectedErr)
3097 }
3098 }
3099
3100 func TestCertificateChainSignedByECDSA(t *testing.T) {
3101 caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
3102 if err != nil {
3103 t.Fatal(err)
3104 }
3105 root := &Certificate{
3106 SerialNumber: big.NewInt(1),
3107 Subject: pkix.Name{CommonName: "X"},
3108 NotBefore: time.Now().Add(-time.Hour),
3109 NotAfter: time.Now().Add(365 * 24 * time.Hour),
3110 IsCA: true,
3111 KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
3112 BasicConstraintsValid: true,
3113 }
3114 caDER, err := CreateCertificate(rand.Reader, root, root, &caKey.PublicKey, caKey)
3115 if err != nil {
3116 t.Fatal(err)
3117 }
3118 root, err = ParseCertificate(caDER)
3119 if err != nil {
3120 t.Fatal(err)
3121 }
3122
3123 leafKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
3124 leaf := &Certificate{
3125 SerialNumber: big.NewInt(42),
3126 Subject: pkix.Name{CommonName: "leaf"},
3127 NotBefore: time.Now().Add(-10 * time.Minute),
3128 NotAfter: time.Now().Add(24 * time.Hour),
3129 KeyUsage: KeyUsageDigitalSignature,
3130 ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
3131 BasicConstraintsValid: true,
3132 }
3133 leafDER, err := CreateCertificate(rand.Reader, leaf, root, &leafKey.PublicKey, caKey)
3134 if err != nil {
3135 t.Fatal(err)
3136 }
3137 leaf, err = ParseCertificate(leafDER)
3138 if err != nil {
3139 t.Fatal(err)
3140 }
3141
3142 inter, err := ParseCertificate(dsaSelfSignedCNX(t))
3143 if err != nil {
3144 t.Fatal(err)
3145 }
3146
3147 inters := NewCertPool()
3148 inters.AddCert(root)
3149 inters.AddCert(inter)
3150
3151 wantErr := "certificate signed by unknown authority"
3152 _, err = leaf.Verify(VerifyOptions{Intermediates: inters, Roots: NewCertPool()})
3153 if !strings.Contains(err.Error(), wantErr) {
3154 t.Errorf("got %v, want %q", err, wantErr)
3155 }
3156 }
3157
3158
3159
3160
3161
3162
3163
3164
3165 func dsaSelfSignedCNX(t *testing.T) []byte {
3166 t.Helper()
3167 var params dsa.Parameters
3168 if err := dsa.GenerateParameters(¶ms, rand.Reader, dsa.L1024N160); err != nil {
3169 t.Fatal(err)
3170 }
3171
3172 var dsaPriv dsa.PrivateKey
3173 dsaPriv.Parameters = params
3174 if err := dsa.GenerateKey(&dsaPriv, rand.Reader); err != nil {
3175 t.Fatal(err)
3176 }
3177 dsaPub := &dsaPriv.PublicKey
3178
3179 type dsaParams struct{ P, Q, G *big.Int }
3180 paramDER, err := asn1.Marshal(dsaParams{dsaPub.P, dsaPub.Q, dsaPub.G})
3181 if err != nil {
3182 t.Fatal(err)
3183 }
3184 yDER, err := asn1.Marshal(dsaPub.Y)
3185 if err != nil {
3186 t.Fatal(err)
3187 }
3188
3189 spki := publicKeyInfo{
3190 Algorithm: pkix.AlgorithmIdentifier{
3191 Algorithm: oidPublicKeyDSA,
3192 Parameters: asn1.RawValue{FullBytes: paramDER},
3193 },
3194 PublicKey: asn1.BitString{Bytes: yDER, BitLength: 8 * len(yDER)},
3195 }
3196
3197 rdn := pkix.Name{CommonName: "X"}.ToRDNSequence()
3198 b, err := asn1.Marshal(rdn)
3199 if err != nil {
3200 t.Fatal(err)
3201 }
3202 rawName := asn1.RawValue{FullBytes: b}
3203
3204 algoIdent := pkix.AlgorithmIdentifier{Algorithm: oidSignatureDSAWithSHA256}
3205 tbs := tbsCertificate{
3206 Version: 0,
3207 SerialNumber: big.NewInt(1002),
3208 SignatureAlgorithm: algoIdent,
3209 Issuer: rawName,
3210 Validity: validity{NotBefore: time.Now().Add(-time.Hour), NotAfter: time.Now().Add(24 * time.Hour)},
3211 Subject: rawName,
3212 PublicKey: spki,
3213 }
3214 c := certificate{
3215 TBSCertificate: tbs,
3216 SignatureAlgorithm: algoIdent,
3217 SignatureValue: asn1.BitString{Bytes: []byte{0}, BitLength: 8},
3218 }
3219 dsaDER, err := asn1.Marshal(c)
3220 if err != nil {
3221 t.Fatal(err)
3222 }
3223 return dsaDER
3224 }
3225
View as plain text