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 5package x509 6 7import ( 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 "slices" 23 "strconv" 24 "strings" 25 "testing" 26 "time" 27) 28 29type 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 44var 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 388func 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 399func 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 405func 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 411func 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 421func 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 430func 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 436func 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 442func 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 448func 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 456func 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 555func 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 567func 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 582func 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 593func nameToKey(name *pkix.Name) string { 594 return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName 595} 596 597const gtsIntermediate = `-----BEGIN CERTIFICATE----- 598MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw 599CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 600MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw 601MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp 602Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD 603ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp 604kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX 605lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm 606BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA 607gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL 608tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud 609DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T 610AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD 611VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG 612CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw 613AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt 614MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG 615A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br 616aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN 617AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ 618cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL 619RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U 620+o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr 621PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER 622lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs 623Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO 624z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG 625AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw 626juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl 6271IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd 628-----END CERTIFICATE-----` 629 630const gtsRoot = `-----BEGIN CERTIFICATE----- 631MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw 632CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 633MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw 634MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp 635Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA 636A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo 63727xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w 638Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw 639TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl 640qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH 641szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 642Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk 643MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 644wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p 645aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN 646VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID 647AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E 648FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb 649C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe 650QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy 651h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 6527HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J 653ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef 654MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ 655Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT 6566u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ 6570E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm 6582tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb 659bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c 660-----END CERTIFICATE-----` 661 662const googleLeaf = `-----BEGIN CERTIFICATE----- 663MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG 664MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM 665QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw 666ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B 667AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a 668wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o 66955kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr 670N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs 671KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q 672WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw 673DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC 674MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0 675f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb 676aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v 677cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n 678b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD 679VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow 680TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4 6814FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S 6823T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx 6831+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB 684hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC 685IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF 686AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p 687MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd 688VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga 689zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI 690c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP 691i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg== 692-----END CERTIFICATE-----` 693 694// googleLeafWithInvalidHash is the same as googleLeaf, but the signature 695// algorithm in the certificate contains a nonsense OID. 696const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE----- 697MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG 698MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM 699QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw 700ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B 701AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a 702wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o 70355kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr 704N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs 705KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q 706WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw 707DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC 708MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0 709f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb 710aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v 711cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n 712b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD 713VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow 714TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4 7154FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S 7163T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx 7171+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB 718hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC 719IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F 720AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p 721MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd 722VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga 723zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI 724c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP 725i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg== 726-----END CERTIFICATE-----` 727 728const dnssecExpLeaf = `-----BEGIN CERTIFICATE----- 729MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ 730TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 731YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg 732MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwNzA0MTQ1MjQ1 733WhcNMTEwNzA1MTA1NzA0WjCBwTEgMB4GA1UEDRMXMjIxMTM3LWxpOWE5dHhJRzZM 734NnNyVFMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0 735ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRsw 736GQYDVQQDExJ3d3cuZG5zc2VjLWV4cC5vcmcxKDAmBgkqhkiG9w0BCQEWGWhvc3Rt 737YXN0ZXJAZG5zc2VjLWV4cC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 738AoIBAQDEdF/22vaxrPbqpgVYMWi+alfpzBctpbfLBdPGuqOazJdCT0NbWcK8/+B4 739X6OlSOURNIlwLzhkmwVsWdVv6dVSaN7d4yI/fJkvgfDB9+au+iBJb6Pcz8ULBfe6 740D8HVvqKdORp6INzHz71z0sghxrQ0EAEkoWAZLh+kcn2ZHdcmZaBNUfjmGbyU6PRt 741RjdqoP+owIaC1aktBN7zl4uO7cRjlYFdusINrh2kPP02KAx2W84xjxX1uyj6oS6e 7427eBfvcwe8czW/N1rbE0CoR7h9+HnIrjnVG9RhBiZEiw3mUmF++Up26+4KTdRKbu3 743+BL4yMpfd66z0+zzqu+HkvyLpFn5AgMBAAGjggL/MIIC+zAJBgNVHRMEAjAAMAsG 744A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUy04I5guM 745drzfh2JQaXhgV86+4jUwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUw 746LQYDVR0RBCYwJIISd3d3LmRuc3NlYy1leHAub3Jngg5kbnNzZWMtZXhwLm9yZzCC 747AUIGA1UdIASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgIwggEgMC4GCCsGAQUFBwIB 748FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIB 749FihodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3Bggr 750BgEFBQcCAjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJp 751bGl0eSwgc2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3Rh 752cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBh 753dCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGEGA1UdHwRaMFgw 754KqAooCaGJGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDAqoCig 755JoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEF 756BQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20v 757c3ViL2NsYXNzMS9zZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuc3Rh 758cnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIE 759HDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEB 760ACXj6SB59KRJPenn6gUdGEqcta97U769SATyiQ87i9er64qLwvIGLMa3o2Rcgl2Y 761kghUeyLdN/EXyFBYA8L8uvZREPoc7EZukpT/ZDLXy9i2S0jkOxvF2fD/XLbcjGjM 762iEYG1/6ASw0ri9C0k4oDDoJLCoeH9++yqF7SFCCMcDkJqiAGXNb4euDpa8vCCtEQ 763CSS+ObZbfkreRt3cNCf5LfCXe9OsTnCfc8Cuq81c0oLaG+SmaLUQNBuToq8e9/Zm 764+b+/a3RVjxmkV5OCcGVBxsXNDn54Q6wsdw0TBMcjwoEndzpLS7yWgFbbkq5ZiGpw 765Qibb2+CfKuQ+WFV1GkVQmVA= 766-----END CERTIFICATE-----` 767 768const startComIntermediate = `-----BEGIN CERTIFICATE----- 769MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW 770MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg 771Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh 772dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB 773jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT 774IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0 775YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB 776IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE 777gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA 778pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv 779kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/ 780ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5 781xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID 782AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD 783VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul 784F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov 785L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0 786YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3 787dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0 788c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu 789BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0 790BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl 791LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp 792tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen 793xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw 794xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X 795t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI 796RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi 797YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L 798WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN 799SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD 800wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L 801p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un 8020q6Dp6jOW6c= 803-----END CERTIFICATE-----` 804 805const startComRoot = `-----BEGIN CERTIFICATE----- 806MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW 807MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg 808Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh 809dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 810MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi 811U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh 812cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA 813A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk 814pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf 815OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C 816Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT 817Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi 818HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM 819Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w 820+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ 821Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 822Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B 82326Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID 824AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE 825FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j 826ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js 827LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM 828BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 829Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy 830dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh 831cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh 832YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg 833dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp 834bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ 835YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT 836TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ 8379GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 838jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW 839FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz 840ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 841ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L 842EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu 843L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq 844yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC 845O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V 846um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh 847NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= 848-----END CERTIFICATE-----` 849 850const smimeLeaf = `-----BEGIN CERTIFICATE----- 851MIIIPDCCBiSgAwIBAgIQaMDxFS0pOMxZZeOBxoTJtjANBgkqhkiG9w0BAQsFADCB 852nTELMAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTowOAYDVQQLDDFB 853WlogWml1cnRhZ2lyaSBwdWJsaWtvYSAtIENlcnRpZmljYWRvIHB1YmxpY28gU0NB 854MTwwOgYDVQQDDDNFQUVrbyBIZXJyaSBBZG1pbmlzdHJhemlvZW4gQ0EgLSBDQSBB 855QVBQIFZhc2NhcyAoMikwHhcNMTcwNzEyMDg1MzIxWhcNMjEwNzEyMDg1MzIxWjCC 856AQwxDzANBgNVBAoMBklaRU5QRTE4MDYGA1UECwwvWml1cnRhZ2lyaSBrb3Jwb3Jh 857dGlib2EtQ2VydGlmaWNhZG8gY29ycG9yYXRpdm8xQzBBBgNVBAsMOkNvbmRpY2lv 858bmVzIGRlIHVzbyBlbiB3d3cuaXplbnBlLmNvbSBub2xhIGVyYWJpbGkgamFraXRl 859a28xFzAVBgNVBC4TDi1kbmkgOTk5OTk5ODlaMSQwIgYDVQQDDBtDT1JQT1JBVElW 860TyBGSUNUSUNJTyBBQ1RJVk8xFDASBgNVBCoMC0NPUlBPUkFUSVZPMREwDwYDVQQE 861DAhGSUNUSUNJTzESMBAGA1UEBRMJOTk5OTk5ODlaMIIBIjANBgkqhkiG9w0BAQEF 862AAOCAQ8AMIIBCgKCAQEAwVOMwUDfBtsH0XuxYnb+v/L774jMH8valX7RPH8cl2Lb 863SiqSo0RchW2RGA2d1yuYHlpChC9jGmt0X/g66/E/+q2hUJlfJtqVDJFwtFYV4u2S 864yzA3J36V4PRkPQrKxAsbzZriFXAF10XgiHQz9aVeMMJ9GBhmh9+DK8Tm4cMF6i8l 865+AuC35KdngPF1x0ealTYrYZplpEJFO7CiW42aLi6vQkDR2R7nmZA4AT69teqBWsK 8660DZ93/f0G/3+vnWwNTBF0lB6dIXoaz8OMSyHLqGnmmAtMrzbjAr/O/WWgbB/BqhR 867qjJQ7Ui16cuDldXaWQ/rkMzsxmsAox0UF+zdQNvXUQIDAQABo4IDBDCCAwAwgccG 868A1UdEgSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j 869b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S 870TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh 871IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H 872YXN0ZWl6MB4GA1UdEQQXMBWBE2ZpY3RpY2lvQGl6ZW5wZS5ldXMwDgYDVR0PAQH/ 873BAQDAgXgMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC 874AjAdBgNVHQ4EFgQUyeoOD4cgcljKY0JvrNuX2waFQLAwHwYDVR0jBBgwFoAUwKlK 87590clh/+8taaJzoLSRqiJ66MwggEnBgNVHSAEggEeMIIBGjCCARYGCisGAQQB8zkB 876AQEwggEGMDMGCCsGAQUFBwIBFidodHRwOi8vd3d3Lml6ZW5wZS5jb20vcnBhc2Nh 877Y29ycG9yYXRpdm8wgc4GCCsGAQUFBwICMIHBGoG+Wml1cnRhZ2lyaWEgRXVza2Fs 878IEF1dG9ub21pYSBFcmtpZGVnb2tvIHNla3RvcmUgcHVibGlrb2tvIGVyYWt1bmRl 879ZW4gYmFybmUtc2FyZWV0YW4gYmFrYXJyaWsgZXJhYmlsIGRhaXRla2UuIFVzbyBy 880ZXN0cmluZ2lkbyBhbCBhbWJpdG8gZGUgcmVkZXMgaW50ZXJuYXMgZGUgRW50aWRh 881ZGVzIGRlbCBTZWN0b3IgUHVibGljbyBWYXNjbzAyBggrBgEFBQcBAQQmMCQwIgYI 882KwYBBQUHMAGGFmh0dHA6Ly9vY3NwLml6ZW5wZS5jb20wOgYDVR0fBDMwMTAvoC2g 883K4YpaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vY3JsaW50ZXJuYTIwDQYJ 884KoZIhvcNAQELBQADggIBAIy5PQ+UZlCRq6ig43vpHwlwuD9daAYeejV0Q+ZbgWAE 885GtO0kT/ytw95ZEJMNiMw3fYfPRlh27ThqiT0VDXZJDlzmn7JZd6QFcdXkCsiuv4+ 886ZoXAg/QwnA3SGUUO9aVaXyuOIIuvOfb9MzoGp9xk23SMV3eiLAaLMLqwB5DTfBdt 887BGI7L1MnGJBv8RfP/TL67aJ5bgq2ri4S8vGHtXSjcZ0+rCEOLJtmDNMnTZxancg3 888/H5edeNd+n6Z48LO+JHRxQufbC4mVNxVLMIP9EkGUejlq4E4w6zb5NwCQczJbSWL 889i31rk2orsNsDlyaLGsWZp3JSNX6RmodU4KAUPor4jUJuUhrrm3Spb73gKlV/gcIw 890bCE7mML1Kss3x1ySaXsis6SZtLpGWKkW2iguPWPs0ydV6RPhmsCxieMwPPIJ87vS 8915IejfgyBae7RSuAIHyNFy4uI5xwvwUFf6OZ7az8qtW7ImFOgng3Ds+W9k1S2CNTx 892d0cnKTfA6IpjGo8EeHcxnIXT8NPImWaRj0qqonvYady7ci6U4m3lkNSdXNn1afgw 893mYust+gxVtOZs1gk2MUCgJ1V1X+g7r/Cg7viIn6TLkLrpS1kS1hvMqkl9M+7XqPo 894Qd95nJKOkusQpy99X4dF/lfbYAQnnjnqh3DLD2gvYObXFaAYFaiBKTiMTV2X72F+ 895-----END CERTIFICATE-----` 896 897const smimeIntermediate = `-----BEGIN CERTIFICATE----- 898MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL 899MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu 900cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV 901BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0 902YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE 903AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj 904YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h 905rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2 906To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU 907ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD 908PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr 909PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn 910soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM 9118IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL 912MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg 913jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk 9143LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb 915KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w 916gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO 917MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0 918b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk 919aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP 920BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl 921h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw 922OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl 923bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v 924b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny 925bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM 9263DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS 927M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E 9283TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL 929xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4 930VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR 9310oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK 932b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi 9331tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS 934FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM 9355tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw 936k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7 937-----END CERTIFICATE-----` 938 939const smimeRoot = `-----BEGIN CERTIFICATE----- 940MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 941MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 942ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD 943VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j 944b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq 945scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO 946xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H 947LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX 948uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD 949yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ 950JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q 951rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN 952BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L 953hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB 954QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ 955HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu 956Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg 957QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB 958BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx 959MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC 960AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA 961A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb 962laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 963awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo 964JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw 965LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT 966VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk 967LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb 968UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ 969QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ 970naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls 971QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== 972-----END CERTIFICATE-----` 973 974var nameConstraintsLeaf = `-----BEGIN CERTIFICATE----- 975MIIHMTCCBRmgAwIBAgIIIZaV/3ezOJkwDQYJKoZIhvcNAQEFBQAwgcsxCzAJBgNV 976BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEj 977MCEGA1UECxMaR2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1Zp 978cmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0 979eTExMC8GA1UEAxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZl 980ciBDQTAeFw0xMzA5MTkxNDM2NTVaFw0xNTA5MTkxNDM2NTVaMIHNMQswCQYDVQQG 981EwJVUzERMA8GA1UECAwIVmlyZ2luaWExEzARBgNVBAcMCkJsYWNrc2J1cmcxPDA6 982BgNVBAoMM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUg 983VW5pdmVyc2l0eTE7MDkGA1UECwwyVGVjaG5vbG9neS1lbmhhbmNlZCBMZWFybmlu 984ZyBhbmQgT25saW5lIFN0cmF0ZWdpZXMxGzAZBgNVBAMMEnNlY3VyZS5pZGRsLnZ0 985LmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkOyPpsOK/6IuPG 986WnIBlVwlHzeYf+cUlggqkLq0b0+vZbiTXgio9/VCuNQ8opSoss7J7o3ygV9to+9Y 987YwJKVC5WDT/y5JWpQey0CWILymViJnpNSwnxBc8A+Q8w5NUGDd/UhtPx/U8/hqbd 988WPDYj2hbOqyq8UlRhfS5pwtnv6BbCTaY11I6FhCLK7zttISyTuWCf9p9o/ggiipP 989ii/5oh4dkl+r5SfuSp5GPNHlYO8lWqys5NAPoDD4fc/kuflcK7Exx7XJ+Oqu0W0/ 990psjEY/tES1ZgDWU/ParcxxFpFmKHbD5DXsfPOObzkVWXIY6tGMutSlE1Froy/Nn0 991OZsAOrcCAwEAAaOCAhMwggIPMIG4BggrBgEFBQcBAQSBqzCBqDBYBggrBgEFBQcw 992AoZMaHR0cDovL3d3dy5wa2kudnQuZWR1L2dsb2JhbHF1YWxpZmllZHNlcnZlci9j 993YWNlcnQvZ2xvYmFscXVhbGlmaWVkc2VydmVyLmNydDBMBggrBgEFBQcwAYZAaHR0 994cDovL3Z0Y2EtcC5lcHJvdi5zZXRpLnZ0LmVkdTo4MDgwL2VqYmNhL3B1YmxpY3dl 995Yi9zdGF0dXMvb2NzcDAdBgNVHQ4EFgQUp7xbO6iHkvtZbPE4jmndmnAbSEcwDAYD 996VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS8YmAn1eM1SBfpS6tFatDIqHdxjDBqBgNV 997HSAEYzBhMA4GDCsGAQQBtGgFAgICATAOBgwrBgEEAbRoBQICAQEwPwYMKwYBBAG0 998aAUCAgMBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9i 999YWwvY3BzLzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vd3d3LnBraS52dC5lZHUv 1000Z2xvYmFscXVhbGlmaWVkc2VydmVyL2NybC9jYWNybC5jcmwwDgYDVR0PAQH/BAQD 1001AgTwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHREEFjAUghJz 1002ZWN1cmUuaWRkbC52dC5lZHUwDQYJKoZIhvcNAQEFBQADggIBAEgoYo4aUtatY3gI 1003OyyKp7QlIOaLbTJZywESHqy+L5EGDdJW2DJV+mcE0LDGvqa2/1Lo+AR1ntsZwfOi 1004Y718JwgVVaX/RCd5+QKP25c5/x72xI8hb/L1bgS0ED9b0YAhd7Qm1K1ot82+6mqX 1005DW6WiGeDr8Z07MQ3143qQe2rBlq+QI69DYzm2GOqAIAnUIWv7tCyLUm31b4DwmrJ 1006TeudVreTKUbBNB1TWRFHEPkWhjjXKZnNGRO11wHXcyBu6YekIvVZ+vmx8ePee4jJ 10073GFOi7lMuWOeq57jTVL7KOKaKLVXBb6gqo5aq+Wwt8RUD5MakrCAEeQZj7DKaFmZ 1008oQCO0Pxrsl3InCGvxnGzT+bFVO9nJ/BAMj7hknFdm9Jr6Bg5q33Z+gnf909AD9QF 1009ESqUSykaHu2LVdJx2MaCH1CyKnRgMw5tEwE15EXpUjCm24m8FMOYC+rNtf18pgrz 10105D8Jhh+oxK9PjcBYqXNtnioIxiMCYcV0q5d4w4BYFEh71tk7/bYB0R55CsBUVPmp 1011timWNOdRd57Tfpk3USaVsumWZAf9MP3wPiC7gb4d5tYEEAG5BuDT8ruFw838wU8G 10121VvAVutSiYBg7k3NYO7AUqZ+Ax4klQX3aM9lgonmJ78Qt94UPtbptrfZ4/lSqEf8 1013GBUwDrQNTb+gsXsDkjd5lcYxNx6l 1014-----END CERTIFICATE-----` 1015 1016var nameConstraintsIntermediate1 = `-----BEGIN CERTIFICATE----- 1017MIINLjCCDBagAwIBAgIRIqpyf/YoGgvHc8HiDAxAI8owDQYJKoZIhvcNAQEFBQAw 1018XDELMAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQ 1019R2xvYmFsU2lnbiBudi1zYTEbMBkGA1UEAxMSVHJ1c3RlZCBSb290IENBIEcyMB4X 1020DTEyMTIxMzAwMDAwMFoXDTE3MTIxMzAwMDAwMFowgcsxCzAJBgNVBAYTAlVTMREw 1021DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEjMCEGA1UECxMa 1022R2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1ZpcmdpbmlhIFBv 1023bHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTExMC8GA1UE 1024AxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTCCAiIw 1025DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALgIZhEaptBWADBqdJ45ueFGzMXa 1026GHnzNxoxR1fQIaaRQNdCg4cw3A4dWKMeEgYLtsp65ai3Xfw62Qaus0+KJ3RhgV+r 1027ihqK81NUzkls78fJlADVDI4fCTlothsrE1CTOMiy97jKHai5mVTiWxmcxpmjv7fm 10285Nhc+uHgh2hIz6npryq495mD51ZrUTIaqAQN6Pw/VHfAmR524vgriTOjtp1t4lA9 1029pXGWjF/vkhAKFFheOQSQ00rngo2wHgCqMla64UTN0oz70AsCYNZ3jDLx0kOP0YmM 1030R3Ih91VA63kLqPXA0R6yxmmhhxLZ5bcyAy1SLjr1N302MIxLM/pSy6aquEnbELhz 1031qyp9yGgRyGJay96QH7c4RJY6gtcoPDbldDcHI9nXngdAL4DrZkJ9OkDkJLyqG66W 1032ZTF5q4EIs6yMdrywz0x7QP+OXPJrjYpbeFs6tGZCFnWPFfmHCRJF8/unofYrheq+ 10339J7Jx3U55S/k57NXbAM1RAJOuMTlfn9Etf9Dpoac9poI4Liav6rBoUQk3N3JWqnV 1034HNx/NdCyJ1/6UbKMJUZsStAVglsi6lVPo289HHOE4f7iwl3SyekizVOp01wUin3y 1035cnbZB/rXmZbwapSxTTSBf0EIOr9i4EGfnnhCAVA9U5uLrI5OEB69IY8PNX0071s3 1036Z2a2fio5c8m3JkdrAgMBAAGjggh5MIIIdTAOBgNVHQ8BAf8EBAMCAQYwTAYDVR0g 1037BEUwQzBBBgkrBgEEAaAyATwwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv 1038YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wEgYDVR0TAQH/BAgwBgEB/wIBADCCBtAG 1039A1UdHgSCBscwggbDoIIGvzASghAzZGJsYWNrc2J1cmcub3JnMBiCFmFjY2VsZXJh 1040dGV2aXJnaW5pYS5jb20wGIIWYWNjZWxlcmF0ZXZpcmdpbmlhLm9yZzALgglhY3Zj 1041cC5vcmcwCYIHYmV2Lm5ldDAJggdiZXYub3JnMAuCCWNsaWdzLm9yZzAMggpjbWl3 1042ZWIub3JnMBeCFWVhc3Rlcm5icm9va3Ryb3V0Lm5ldDAXghVlYXN0ZXJuYnJvb2t0 1043cm91dC5vcmcwEYIPZWNvcnJpZG9ycy5pbmZvMBOCEWVkZ2FycmVzZWFyY2gub3Jn 1044MBKCEGdldC1lZHVjYXRlZC5jb20wE4IRZ2V0LWVkdWNhdGVkLmluZm8wEYIPZ2V0 1045ZWR1Y2F0ZWQubmV0MBKCEGdldC1lZHVjYXRlZC5uZXQwEYIPZ2V0ZWR1Y2F0ZWQu 1046b3JnMBKCEGdldC1lZHVjYXRlZC5vcmcwD4INaG9raWVjbHViLmNvbTAQgg5ob2tp 1047ZXBob3RvLmNvbTAPgg1ob2tpZXNob3AuY29tMBGCD2hva2llc3BvcnRzLmNvbTAS 1048ghBob2tpZXRpY2tldHMuY29tMBKCEGhvdGVscm9hbm9rZS5jb20wE4IRaHVtYW53 1049aWxkbGlmZS5vcmcwF4IVaW5uYXR2aXJnaW5pYXRlY2guY29tMA+CDWlzY2hwMjAx 1050MS5vcmcwD4INbGFuZHJlaGFiLm9yZzAggh5uYXRpb25hbHRpcmVyZXNlYXJjaGNl 1051bnRlci5jb20wFYITbmV0d29ya3ZpcmdpbmlhLm5ldDAMggpwZHJjdnQuY29tMBiC 1052FnBldGVkeWVyaXZlcmNvdXJzZS5jb20wDYILcmFkaW9pcS5vcmcwFYITcml2ZXJj 1053b3Vyc2Vnb2xmLmNvbTALgglzZGltaS5vcmcwEIIOc292YW1vdGlvbi5jb20wHoIc 1054c3VzdGFpbmFibGUtYmlvbWF0ZXJpYWxzLmNvbTAeghxzdXN0YWluYWJsZS1iaW9t 1055YXRlcmlhbHMub3JnMBWCE3RoaXNpc3RoZWZ1dHVyZS5jb20wGIIWdGhpcy1pcy10 1056aGUtZnV0dXJlLmNvbTAVghN0aGlzaXN0aGVmdXR1cmUubmV0MBiCFnRoaXMtaXMt 1057dGhlLWZ1dHVyZS5uZXQwCoIIdmFkcy5vcmcwDIIKdmFsZWFmLm9yZzANggt2YXRl 1058Y2guaW5mbzANggt2YXRlY2gubW9iaTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5n 1059LmNvbTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5nLm5ldDAcghp2YXRlY2hsaWZl 1060bG9uZ2xlYXJuaW5nLm9yZzAKggh2Y29tLmVkdTASghB2aXJnaW5pYXZpZXcubmV0 1061MDSCMnZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVuaXZlcnNp 1062dHkuY29tMDWCM3ZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVu 1063aXZlcnNpdHkuaW5mbzA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0dXRlYW5k 1064c3RhdGV1bml2ZXJzaXR5Lm5ldDA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0 1065dXRlYW5kc3RhdGV1bml2ZXJzaXR5Lm9yZzAZghd2aXJnaW5pYXB1YmxpY3JhZGlv 1066Lm9yZzASghB2aXJnaW5pYXRlY2guZWR1MBOCEXZpcmdpbmlhdGVjaC5tb2JpMByC 1067GnZpcmdpbmlhdGVjaGZvdW5kYXRpb24ub3JnMAiCBnZ0LmVkdTALggl2dGFyYy5v 1068cmcwDIIKdnQtYXJjLm9yZzALggl2dGNyYy5jb20wCoIIdnRpcC5vcmcwDIIKdnRs 1069ZWFuLm9yZzAWghR2dGtub3dsZWRnZXdvcmtzLmNvbTAYghZ2dGxpZmVsb25nbGVh 1070cm5pbmcuY29tMBiCFnZ0bGlmZWxvbmdsZWFybmluZy5uZXQwGIIWdnRsaWZlbG9u 1071Z2xlYXJuaW5nLm9yZzATghF2dHNwb3J0c21lZGlhLmNvbTALggl2dHdlaS5jb20w 1072D4INd2l3YXR3ZXJjLmNvbTAKggh3dnRmLm9yZzAIgQZ2dC5lZHUwd6R1MHMxCzAJ 1073BgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVy 1074ZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBT 1075dGF0ZSBVbml2ZXJzaXR5MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYI 1076KwYBBQUHAwkwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5nbG9iYWxzaWdu 1077LmNvbS9ncy90cnVzdHJvb3RnMi5jcmwwgYQGCCsGAQUFBwEBBHgwdjAzBggrBgEF 1078BQcwAYYnaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3RydXN0cm9vdGcyMD8G 1079CCsGAQUFBzAChjNodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90 1080cnVzdHJvb3RnMi5jcnQwHQYDVR0OBBYEFLxiYCfV4zVIF+lLq0Vq0Miod3GMMB8G 1081A1UdIwQYMBaAFBT25YsxtkWASkxt/MKHico2w5BiMA0GCSqGSIb3DQEBBQUAA4IB 1082AQAyJm/lOB2Er4tHXhc/+fSufSzgjohJgYfMkvG4LknkvnZ1BjliefR8tTXX49d2 1083SCDFWfGjqyJZwavavkl/4p3oXPG/nAMDMvxh4YAT+CfEK9HH+6ICV087kD4BLegi 1084+aFJMj8MMdReWCzn5sLnSR1rdse2mo2arX3Uod14SW+PGrbUmTuWNyvRbz3fVmxp 1085UdbGmj3laknO9YPsBGgHfv73pVVsTJkW4ZfY/7KdD/yaVv6ophpOB3coXfjl2+kd 1086Z4ypn2zK+cx9IL/LSewqd/7W9cD55PCUy4X9OTbEmAccwiz3LB66mQoUGfdHdkoB 1087jUY+v9vLQXmaVwI0AYL7g9LN 1088-----END CERTIFICATE-----` 1089 1090var nameConstraintsIntermediate2 = `-----BEGIN CERTIFICATE----- 1091MIIEXTCCA0WgAwIBAgILBAAAAAABNuk6OrMwDQYJKoZIhvcNAQEFBQAwVzELMAkG 1092A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 1093b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMjA0MjUxMTAw 1094MDBaFw0yNzA0MjUxMTAwMDBaMFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVz 1095dGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRy 1096dXN0ZWQgUm9vdCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 1097AKyuvqrtcMr7g7EuNbu4sKwxM127UsCmx1RxbxxgcArGS7rjiefpBH/w4LYrymjf 1098vcw1ueyMNoqLo9nJMz/ORXupb35NNfE667prQYHa+tTjl1IiKpB7QUwt3wXPuTMF 1099Ja1tXtjKzkqJyuJlNuPKT76HcjgNqgV1s9qG44MD5I2JvI12du8zI1bgdQ+l/KsX 1100kTfbGjUvhOLOlVNWVQDpL+YMIrGqgBYxy5TUNgrAcRtwpNdS2KkF5otSmMweVb5k 1101hoUVv3u8UxQH/WWbNhHq1RrIlg/0rBUfi/ziShYFSB7U+aLx5DxPphTFBiDquQGp 1102tB+FC4JvnukDStFihZCZ1R8CAwEAAaOCASMwggEfMA4GA1UdDwEB/wQEAwIBBjAP 1103BgNVHRMBAf8EBTADAQH/MEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB 1104FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAdBgNVHQ4E 1105FgQUFPblizG2RYBKTG38woeJyjbDkGIwMwYDVR0fBCwwKjAooCagJIYiaHR0cDov 1106L2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNybDA+BggrBgEFBQcBAQQyMDAwLgYI 1107KwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjEwHwYD 1108VR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEFBQADggEB 1109AL7IG0l+k4LkcpI+a/kvZsSRwSM4uA6zGX34e78A2oytr8RG8bJwVb8+AHMUD+Xe 11102kYdh/Uj/waQXfqR0OgxQXL9Ct4ZM+JlR1avsNKXWL5AwYXAXCOB3J5PW2XOck7H 1111Zw0vRbGQhjWjQx+B4KOUFg1b3ov/z6Xkr3yaCfRQhXh7KC0Bc0RXPPG5Nv5lCW+z 1112tbbg0zMm3kyfQITRusMSg6IBsDJqOnjaiaKQRcXiD0Sk43ZXb2bUKMxC7+Td3QL4 1113RyHcWJbQ7YylLTS/x+jxWIcOQ0oO5/54t5PTQ14neYhOz9x4gUk2AYAW6d1vePwb 1114hcC8roQwkHT7HvfYBoc74FM= 1115-----END CERTIFICATE-----` 1116 1117var globalSignRoot = `-----BEGIN CERTIFICATE----- 1118MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG 1119A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 1120b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw 1121MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i 1122YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT 1123aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ 1124jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp 1125xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 11261Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG 1127snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ 1128U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 11299iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E 1130BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B 1131AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz 1132yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 113338NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP 1134AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad 1135DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME 1136HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 1137-----END CERTIFICATE-----` 1138 1139const digicertRoot = `-----BEGIN CERTIFICATE----- 1140MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh 1141MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 1142d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 1143QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT 1144MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 1145b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 11469w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB 1147CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 1148nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 114943C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P 1150T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 1151gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO 1152BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR 1153TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw 1154DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr 1155hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 115606O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF 1157PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls 1158YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk 1159CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= 1160-----END CERTIFICATE-----` 1161 1162const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE----- 1163MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh 1164MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 1165d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 1166QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO 1167MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD 1168ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA 1169IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR 1170xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v 1171Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD 1172VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G 1173A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA 1174MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl 1175cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt 1176Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG 1177SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v 1178Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd 1179j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV 1180OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk 1181GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa 1182SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq 1183PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6 1184rRzZxAYN36q1SX8= 1185-----END CERTIFICATE-----` 1186 1187const trustAsiaLeaf = `-----BEGIN CERTIFICATE----- 1188MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw 1189CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j 1190LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx 1191NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI 1192DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo 11935Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm 1194nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC 1195AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL 1196TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/ 1197+LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud 1198EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU 1199BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny 1200bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD 1201VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu 1202ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG 1203AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG 1204OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM 1205U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv 1206AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA 1207RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8 1208leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K 1209tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx 1210x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw 1211CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z 12120GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364 1213EEeHB9vhZAEjQSePAfjR9aAGhXRa 1214-----END CERTIFICATE-----` 1215 1216const selfSigned = `-----BEGIN CERTIFICATE----- 1217MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw 1218EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz 1219NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 1220ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP 1221pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF 1222w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D 1223WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY 1224YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO 1225NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF 1226oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C 1227C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim 12284EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN 1229UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0 1230pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG 1231vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE 1232cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj 1233-----END CERTIFICATE-----` 1234 1235const issuerSubjectMatchRoot = `-----BEGIN CERTIFICATE----- 1236MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE 1237ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1 1238MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh 1239MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1 1240siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw 1241+QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD 1242JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw 1243FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE 1244EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG 1245VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn 1246RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3 1247eyfm5ITdK/WT9TzYhsU4AVZcn20= 1248-----END CERTIFICATE-----` 1249 1250const issuerSubjectMatchLeaf = `-----BEGIN CERTIFICATE----- 1251MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV 1252BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y 1253NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB 1254nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e 1255UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx 12560ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU 1257Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG 1258CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf 1259Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI 1260hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I 1261ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k 1262vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ= 1263-----END CERTIFICATE-----` 1264 1265const x509v1TestRoot = `-----BEGIN CERTIFICATE----- 1266MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE 1267ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1 1268MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB 1269MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1 1270siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw 1271+QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD 1272JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw 1273FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE 1274EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm 1275YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md 1276h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB 1277/1JmacUUofl+HusHuLkDxmadogI= 1278-----END CERTIFICATE-----` 1279 1280const x509v1TestIntermediate = `-----BEGIN CERTIFICATE----- 1281MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH 1282b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx 1283MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50 1284ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL 1285jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM 1286k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8 1287UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab 1288DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR 1289zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur 1290x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+ 1291-----END CERTIFICATE-----` 1292 1293const x509v1TestLeaf = `-----BEGIN CERTIFICATE----- 1294MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV 1295BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw 1296MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW 1297BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC 1298gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR 1299+RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG 1300Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD 1301VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV 1302HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB 1303CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9 13045R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL 1305/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/ 1306-----END CERTIFICATE-----` 1307 1308const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE----- 1309MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE 1310ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx 1311MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa 1312BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB 1313DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW 1314P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY 1315VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf 13162FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3 1317KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w 1318OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE 1319AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw 1320AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC 1321AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j 1322fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I 1323VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy 1324nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU 1325aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu 1326BJ6bvwEAasFiLGP6Zbdmxb2hIA== 1327-----END CERTIFICATE-----` 1328 1329const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE----- 1330MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV 1331BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw 1332MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw 1333FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 1334ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS 1335ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3 1336rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ 1337hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW 1338S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV 1339nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD 1340AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA 1341MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4 1342HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ 1343ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI 1344Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv 1345AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR 1346sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY 1347j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn 1348xZbqP3Krgjj4XNaXjg== 1349-----END CERTIFICATE-----` 1350 1351const excludedNamesLeaf = `-----BEGIN CERTIFICATE----- 1352MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE 1353BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU 1354MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 1355ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv 1356ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV 1357BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx 1358FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0 1359eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G 1360CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA 1361zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8 1362Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu 1363/9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP 1364/Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB 1365UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj 1366LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB 1367MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq 1368sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP 1369hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt 1370qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+ 1371VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4 1372oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A 1373-----END CERTIFICATE-----` 1374 1375const excludedNamesIntermediate = `-----BEGIN CERTIFICATE----- 1376MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE 1377BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU 1378MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 1379ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5 1380MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV 1381UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD 1382VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3 1383MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz 1384OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx 13853FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I 1386CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE 13871AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL 13887oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS 1389nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y 1390E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB 1391ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA 1392V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI 1393JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7 1394A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z 1395LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS 1396zMBX1/lk4wkFckeUIlkD55Y= 1397-----END CERTIFICATE-----` 1398 1399const excludedNamesRoot = `-----BEGIN CERTIFICATE----- 1400MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE 1401BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU 1402MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 1403ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU 1404ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL 1405MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH 1406YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl 1407Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm 1408b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc 14097+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+ 14108TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4 1411gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb 14125Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb 1413smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV 1414m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww 1415CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu 1416ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs 1417n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+ 1418Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ 1419yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT 14206mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o 1421+NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy 1422-----END CERTIFICATE-----` 1423 1424const invalidCNRoot = `-----BEGIN CERTIFICATE----- 1425MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg 1426cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM 1427CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj 1428QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg 1429oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI 1430XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6 1431-----END CERTIFICATE-----` 1432 1433const validCNWithoutSAN = `-----BEGIN CERTIFICATE----- 1434MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG 1435A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow 1436GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D 1437AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr 1438p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR 1439cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0 1440h7olHCpY9yMRiz0= 1441-----END CERTIFICATE-----` 1442 1443const rootWithoutSKID = `-----BEGIN CERTIFICATE----- 1444MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw 1445DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow 1446EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm 1447jGlTr4dLOWT+BCTm2PzWRjk1DpLcSAh+Al8eB1Nc2eBWxYIH9qPirfatvqBOA4c5 1448ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr 1449BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI 1450KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA 1451AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec= 1452-----END CERTIFICATE-----` 1453 1454const leafWithAKID = `-----BEGIN CERTIFICATE----- 1455MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ 1456MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa 1457MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE 1458Wk5N+/8X97YT6ClFNIE5/4yc2YwKn921l0wrIJEcT2u+Uydm7EqtCJNtZjYMAnBd 1459Acp/wynpTwC6tBTsxcM0s6NqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG 1460CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R 1461ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk 14624LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU 1463ZZMqeJS7JldLx91sPUArY5A= 1464-----END CERTIFICATE-----` 1465 1466const rootMatchingSKIDMismatchingSubject = `-----BEGIN CERTIFICATE----- 1467MIIBQjCB6aADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQTAe 1468Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg 1469QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPK4p1uXq2aAeDtKDHIokg2rTcPM 14702gq3N9Y96wiW6/7puBK1+INEW//cO9x6FpzkcsHw/TriAqy4sck/iDAvf9WjMjAw 1471MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAMBgNVHQ4EBQQDAQID 1472MAoGCCqGSM49BAMCA0gAMEUCIQDgtAp7iVHxMnKxZPaLQPC+Tv2r7+DJc88k2SKH 1473MPs/wQIgFjjNvBoQEl7vSHTcRGCCcFMdlN4l0Dqc9YwGa9fyrQs= 1474-----END CERTIFICATE-----` 1475 1476const rootMismatchingSKIDMatchingSubject = `-----BEGIN CERTIFICATE----- 1477MIIBNDCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe 1478Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg 1479QjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI1YRFcIlkWzm9BdEVrIsEQJ2dT6 1480qiW8/WV9GoIhmDtX9SEDHospc0Cgm+TeD2QYW2iMrS5mvNe4GSw0Jezg/bOjJDAi 1481MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNI 1482ADBFAiEAukWOiuellx8bugRiwCS5XQ6IOJ1SZcjuZxj76WojwxkCIHqa71qNw8FM 1483DtA5yoL9M2pDFF6ovFWnaCe+KlzSwAW/ 1484-----END CERTIFICATE-----` 1485 1486const leafMatchingAKIDMatchingIssuer = `-----BEGIN CERTIFICATE----- 1487MIIBNTCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe 1488Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMA8xDTALBgNVBAMTBExlYWYw 1489WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNWERXCJZFs5vQXRFayLBECdnU+qol 1490vP1lfRqCIZg7V/UhAx6LKXNAoJvk3g9kGFtojK0uZrzXuBksNCXs4P2zoyYwJDAO 1491BgNVHSMEBzAFgAMBAgMwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNJ 1492ADBGAiEAnV9XV7a4h0nfJB8pWv+pBUXRlRFA2uZz3mXEpee8NYACIQCWa+wL70GL 1493ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA== 1494-----END CERTIFICATE-----` 1495 1496var 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 1506func 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 1530var 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 1549func 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 1569const selfSignedWithCommonName = `-----BEGIN CERTIFICATE----- 1570MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL 1571MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw 1572CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP 1573ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY 1574gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x 15758RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH 1576+G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq 1577czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3 1578tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD 1579AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA 1580MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM 1581XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw 1582dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT 1583v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx 1584jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe 1585fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf 1586IuYkJwt6w+LH/9HZgf8= 1587-----END CERTIFICATE-----` 1588const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE----- 1589MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL 1590MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw 1591CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa 15927EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd 15938t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS 1594gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/ 1595xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu 1596g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU 159746IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG 1598CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG 1599A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB 1600bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3 1601wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK 1602rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR 1603DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU 160429ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w= 1605-----END CERTIFICATE-----` 1606const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE----- 1607MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL 1608MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB 1609IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM 1610fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz 161135YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI 16122gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm 1613S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0 1614kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID 1615AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG 1616AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN 1617BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq 16184ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM 16199z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb 1620w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi 16214R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs 16228FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA== 1623-----END CERTIFICATE-----` 1624 1625const criticalExtRoot = `-----BEGIN CERTIFICATE----- 1626MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT 1627A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw 1628MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG 1629CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib 1630gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC 1631BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB 1632/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av 1633uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY 1634FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo= 1635-----END CERTIFICATE-----` 1636 1637const criticalExtIntermediate = `-----BEGIN CERTIFICATE----- 1638MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT 1639A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw 1640MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH 1641KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n 1642rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P 1643AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB 1644Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA 1645EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE 1646cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y 1647xXbdbm27KQ== 1648-----END CERTIFICATE-----` 1649 1650const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE----- 1651MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT 1652A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1 1653MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv 1654bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No 16556PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw 1656gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD 1657AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud 1658IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID 1659SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E 1660I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg== 1661-----END CERTIFICATE-----` 1662 1663const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE----- 1664MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD 1665T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw 1666MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD 1667cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH 1668mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP 1669oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr 1670BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv 1671UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED 1672BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG 1673c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx 1674-----END CERTIFICATE-----` 1675 1676const criticalExtLeaf = `-----BEGIN CERTIFICATE----- 1677MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT 1678A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z 1679aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD 1680T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH 1681A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h 1682GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE 1683FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ 1684UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG 1685CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA 16862AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc= 1687-----END CERTIFICATE-----` 1688 1689func 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 1720func 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 1757func 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 1797func 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 1834func 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 1864func 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 1872func 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 1890func 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 1941type trustGraphEdge struct { 1942 Issuer string 1943 Subject string 1944 Type int 1945 MutateTemplate func(*Certificate) 1946 Constraint func([]*Certificate) error 1947} 1948 1949type rootDescription struct { 1950 Subject string 1951 MutateTemplate func(*Certificate) 1952 Constraint func([]*Certificate) error 1953} 1954 1955type trustGraphDescription struct { 1956 Roots []rootDescription 1957 Leaf string 1958 Graph []trustGraphEdge 1959} 1960 1961func 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 2000func 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 2058func 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 slices.Sort(chainStrings) 2068 return chainStrings 2069} 2070 2071func 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 2605func 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 2725func 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 2796func 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} 2814 2815func TestVerifyBareWildcard(t *testing.T) { 2816 k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 2817 if err != nil { 2818 t.Fatalf("failed to generate key: %s", err) 2819 } 2820 tmpl := &Certificate{ 2821 SerialNumber: big.NewInt(1), 2822 Subject: pkix.Name{CommonName: "test"}, 2823 NotBefore: time.Now().Add(-time.Hour), 2824 NotAfter: time.Now().Add(time.Hour), 2825 DNSNames: []string{"*"}, 2826 } 2827 cDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k) 2828 if err != nil { 2829 t.Fatalf("failed to create certificate: %s", err) 2830 } 2831 c, err := ParseCertificate(cDER) 2832 if err != nil { 2833 t.Fatalf("failed to parse certificate: %s", err) 2834 } 2835 2836 if err := c.VerifyHostname("label"); err == nil { 2837 t.Fatalf("VerifyHostname unexpected success with bare wildcard SAN") 2838 } 2839} 2840