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