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