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