)
type verifyTest struct {
- leaf string
- intermediates []string
- roots []string
- currentTime int64
- dnsName string
- systemSkip bool
- keyUsages []ExtKeyUsage
- testSystemRootsError bool
- sha2 bool
- ignoreCN bool
-
- errorCallback func(*testing.T, int, error) bool
+ name string
+ leaf string
+ intermediates []string
+ roots []string
+ currentTime int64
+ dnsName string
+ systemSkip bool
+ systemLax bool
+ keyUsages []ExtKeyUsage
+ ignoreCN bool
+
+ errorCallback func(*testing.T, error)
expectedChains [][]string
}
var verifyTests = []verifyTest{
{
- leaf: googleLeaf,
- intermediates: []string{giag2Intermediate},
- currentTime: 1395785200,
- dnsName: "www.google.com",
- testSystemRootsError: true,
-
- // Without any roots specified we should get a system roots
- // error.
- errorCallback: expectSystemRootsError,
- },
- {
+ name: "Valid",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
},
},
{
+ name: "MixedCase",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
},
},
{
+ name: "HostnameMismatch",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
errorCallback: expectHostnameError("certificate is valid for"),
},
{
+ name: "IPMissing",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
errorCallback: expectHostnameError("doesn't contain any IP SANs"),
},
{
+ name: "Expired",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
errorCallback: expectExpired,
},
{
+ name: "MissingIntermediate",
leaf: googleLeaf,
roots: []string{geoTrustRoot},
currentTime: 1395785200,
errorCallback: expectAuthorityUnknown,
},
{
+ name: "RootInIntermediates",
leaf: googleLeaf,
intermediates: []string{geoTrustRoot, giag2Intermediate},
roots: []string{geoTrustRoot},
{"Google", "Google Internet Authority", "GeoTrust"},
},
// CAPI doesn't build the chain with the duplicated GeoTrust
- // entry so the results don't match. Thus we skip this test
- // until that's fixed.
+ // entry so the results don't match.
+ systemLax: true,
+ },
+ {
+ name: "dnssec-exp",
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+
+ // The StartCom root is not trusted by Windows when the default
+ // ServerAuth EKU is requested.
systemSkip: true,
+
+ expectedChains: [][]string{
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ },
},
{
+ name: "dnssec-exp/AnyEKU",
leaf: dnssecExpLeaf,
intermediates: []string{startComIntermediate},
roots: []string{startComRoot},
currentTime: 1302726541,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageAny},
expectedChains: [][]string{
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
},
},
{
+ name: "dnssec-exp/RootInIntermediates",
leaf: dnssecExpLeaf,
intermediates: []string{startComIntermediate, startComRoot},
roots: []string{startComRoot},
currentTime: 1302726541,
+ systemSkip: true, // see dnssec-exp test
expectedChains: [][]string{
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
},
},
{
+ name: "InvalidHash",
leaf: googleLeafWithInvalidHash,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
// The specific error message may not occur when using system
// verification.
- systemSkip: true,
+ systemLax: true,
errorCallback: expectHashError,
},
+ // EKULeaf tests use an unconstrained chain leading to a leaf certificate
+ // with an E-mail Protection EKU but not a Server Auth one, checking that
+ // the EKUs on the leaf are enforced.
{
- // The default configuration should reject an S/MIME chain.
- leaf: smimeLeaf,
- roots: []string{smimeIntermediate},
- currentTime: 1339436154,
+ name: "EKULeaf",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
- // Key usage not implemented for Windows yet.
- systemSkip: true,
errorCallback: expectUsageError,
},
{
- leaf: smimeLeaf,
- roots: []string{smimeIntermediate},
- currentTime: 1339436154,
- keyUsages: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ name: "EKULeafExplicit",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageServerAuth},
- // Key usage not implemented for Windows yet.
- systemSkip: true,
errorCallback: expectUsageError,
},
{
- leaf: smimeLeaf,
- roots: []string{smimeIntermediate},
- currentTime: 1339436154,
- keyUsages: []ExtKeyUsage{ExtKeyUsageEmailProtection},
+ name: "EKULeafValid",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageEmailProtection},
- // Key usage not implemented for Windows yet.
- systemSkip: true,
expectedChains: [][]string{
- {"Ryan Hurst", "GlobalSign PersonalSign 2 CA - G2"},
+ {"CORPORATIVO FICTICIO ACTIVO", "EAEko Herri Administrazioen CA - CA AAPP Vascas (2)", "IZENPE S.A."},
},
},
{
+ name: "SGCIntermediate",
leaf: megaLeaf,
intermediates: []string{comodoIntermediate1},
roots: []string{comodoRoot},
currentTime: 1360431182,
- // CryptoAPI can find alternative validation paths so we don't
- // perform this test with system validation.
- systemSkip: true,
+ // CryptoAPI can find alternative validation paths.
+ systemLax: true,
expectedChains: [][]string{
{"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
},
{
// Check that a name constrained intermediate works even when
// it lists multiple constraints.
+ name: "MultipleConstraints",
leaf: nameConstraintsLeaf,
intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
roots: []string{globalSignRoot},
{
// Check that SHA-384 intermediates (which are popping up)
// work.
+ name: "SHA-384",
leaf: moipLeafCert,
intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
roots: []string{addTrustRoot},
currentTime: 1397502195,
dnsName: "api.moip.com.br",
- // CryptoAPI can find alternative validation paths so we don't
- // perform this test with system validation.
- systemSkip: true,
+ // CryptoAPI can find alternative validation paths.
+ systemLax: true,
- sha2: true,
expectedChains: [][]string{
{
"api.moip.com.br",
{
// Putting a certificate as a root directly should work as a
// way of saying “exactly this”.
+ name: "LeafInRoots",
leaf: selfSigned,
roots: []string{selfSigned},
currentTime: 1471624472,
dnsName: "foo.example",
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
expectedChains: [][]string{
{"Acme Co"},
{
// Putting a certificate as a root directly should not skip
// other checks however.
+ name: "LeafInRootsInvalid",
leaf: selfSigned,
roots: []string{selfSigned},
currentTime: 1471624472,
dnsName: "notfoo.example",
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectHostnameError("certificate is valid for"),
},
// The issuer name in the leaf doesn't exactly match the
// subject name in the root. Go does not perform
// canonicalization and so should reject this. See issue 14955.
+ name: "IssuerSubjectMismatch",
leaf: issuerSubjectMatchLeaf,
roots: []string{issuerSubjectMatchRoot},
currentTime: 1475787715,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectSubjectIssuerMismatcthError,
},
{
// An X.509 v1 certificate should not be accepted as an
// intermediate.
+ name: "X509v1Intermediate",
leaf: x509v1TestLeaf,
intermediates: []string{x509v1TestIntermediate},
roots: []string{x509v1TestRoot},
currentTime: 1481753183,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectNotAuthorizedError,
},
{
// If any SAN extension is present (even one without any DNS
// names), the CN should be ignored.
+ name: "IgnoreCNWithSANs",
leaf: ignoreCNWithSANLeaf,
dnsName: "foo.example.com",
roots: []string{ignoreCNWithSANRoot},
currentTime: 1486684488,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectHostnameError("certificate is not valid for any names"),
},
{
// Test that excluded names are respected.
+ name: "ExcludedNames",
leaf: excludedNamesLeaf,
dnsName: "bender.local",
intermediates: []string{excludedNamesIntermediate},
roots: []string{excludedNamesRoot},
currentTime: 1486684488,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectNameConstraintsError,
},
{
// Test that unknown critical extensions in a leaf cause a
// verify error.
+ name: "CriticalExtLeaf",
leaf: criticalExtLeafWithExt,
dnsName: "example.com",
intermediates: []string{criticalExtIntermediate},
roots: []string{criticalExtRoot},
currentTime: 1486684488,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectUnhandledCriticalExtension,
},
{
// Test that unknown critical extensions in an intermediate
// cause a verify error.
+ name: "CriticalExtIntermediate",
leaf: criticalExtLeaf,
dnsName: "example.com",
intermediates: []string{criticalExtIntermediateWithExt},
roots: []string{criticalExtRoot},
currentTime: 1486684488,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectUnhandledCriticalExtension,
},
{
// Test that invalid CN are ignored.
+ name: "InvalidCN",
leaf: invalidCNWithoutSAN,
dnsName: "foo,invalid",
roots: []string{invalidCNRoot},
currentTime: 1540000000,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
errorCallback: expectHostnameError("Common Name is not a valid hostname"),
},
{
// Test that valid CN are respected.
+ name: "ValidCN",
leaf: validCNWithoutSAN,
dnsName: "foo.example.com",
roots: []string{invalidCNRoot},
currentTime: 1540000000,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
expectedChains: [][]string{
{"foo.example.com", "Test root"},
},
// Replicate CN tests with ignoreCN = true
{
+ name: "IgnoreCNWithSANs/ignoreCN",
leaf: ignoreCNWithSANLeaf,
dnsName: "foo.example.com",
roots: []string{ignoreCNWithSANRoot},
currentTime: 1486684488,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
ignoreCN: true,
errorCallback: expectHostnameError("certificate is not valid for any names"),
},
{
+ name: "InvalidCN/ignoreCN",
leaf: invalidCNWithoutSAN,
dnsName: "foo,invalid",
roots: []string{invalidCNRoot},
currentTime: 1540000000,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
ignoreCN: true,
errorCallback: expectHostnameError("Common Name is not a valid hostname"),
},
{
+ name: "ValidCN/ignoreCN",
leaf: validCNWithoutSAN,
dnsName: "foo.example.com",
roots: []string{invalidCNRoot},
currentTime: 1540000000,
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
ignoreCN: true,
errorCallback: expectHostnameError("not valid for any names"),
{
// A certificate with an AKID should still chain to a parent without SKID.
// See Issue 30079.
+ name: "AKIDNoSKID",
leaf: leafWithAKID,
roots: []string{rootWithoutSKID},
currentTime: 1550000000,
dnsName: "example",
- systemSkip: true,
+ systemSkip: true, // does not chain to a system root
expectedChains: [][]string{
{"Acme LLC", "Acme Co"},
},
}
-func expectHostnameError(msg string) func(*testing.T, int, error) bool {
- return func(t *testing.T, i int, err error) (ok bool) {
+func expectHostnameError(msg string) func(*testing.T, error) {
+ return func(t *testing.T, err error) {
if _, ok := err.(HostnameError); !ok {
- t.Errorf("#%d: error was not a HostnameError: %v", i, err)
- return false
+ t.Fatalf("error was not a HostnameError: %v", err)
}
if !strings.Contains(err.Error(), msg) {
- t.Errorf("#%d: HostnameError did not contain %q: %v", i, msg, err)
+ t.Fatalf("HostnameError did not contain %q: %v", msg, err)
}
- return true
}
}
-func expectExpired(t *testing.T, i int, err error) (ok bool) {
+func expectExpired(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
- t.Errorf("#%d: error was not Expired: %v", i, err)
- return false
+ t.Fatalf("error was not Expired: %v", err)
}
- return true
}
-func expectUsageError(t *testing.T, i int, err error) (ok bool) {
+func expectUsageError(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage {
- t.Errorf("#%d: error was not IncompatibleUsage: %v", i, err)
- return false
+ t.Fatalf("error was not IncompatibleUsage: %v", err)
}
- return true
}
-func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {
+func expectAuthorityUnknown(t *testing.T, err error) {
e, ok := err.(UnknownAuthorityError)
if !ok {
- t.Errorf("#%d: error was not UnknownAuthorityError: %v", i, err)
- return false
+ t.Fatalf("error was not UnknownAuthorityError: %v", err)
}
if e.Cert == nil {
- t.Errorf("#%d: error was UnknownAuthorityError, but missing Cert: %v", i, err)
- return false
+ t.Fatalf("error was UnknownAuthorityError, but missing Cert: %v", err)
}
- return true
}
-func expectSystemRootsError(t *testing.T, i int, err error) bool {
- if _, ok := err.(SystemRootsError); !ok {
- t.Errorf("#%d: error was not SystemRootsError: %v", i, err)
- return false
- }
- return true
-}
-
-func expectHashError(t *testing.T, i int, err error) bool {
+func expectHashError(t *testing.T, err error) {
if err == nil {
- t.Errorf("#%d: no error resulted from invalid hash", i)
- return false
+ t.Fatalf("no error resulted from invalid hash")
}
if expected := "algorithm unimplemented"; !strings.Contains(err.Error(), expected) {
- t.Errorf("#%d: error resulting from invalid hash didn't contain '%s', rather it was: %v", i, expected, err)
- return false
+ t.Fatalf("error resulting from invalid hash didn't contain '%s', rather it was: %v", expected, err)
}
- return true
}
-func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) {
+func expectSubjectIssuerMismatcthError(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NameMismatch {
- t.Errorf("#%d: error was not a NameMismatch: %v", i, err)
- return false
+ t.Fatalf("error was not a NameMismatch: %v", err)
}
- return true
}
-func expectNameConstraintsError(t *testing.T, i int, err error) (ok bool) {
+func expectNameConstraintsError(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
- t.Errorf("#%d: error was not a CANotAuthorizedForThisName: %v", i, err)
- return false
+ t.Fatalf("error was not a CANotAuthorizedForThisName: %v", err)
}
- return true
}
-func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) {
+func expectNotAuthorizedError(t *testing.T, err error) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign {
- t.Errorf("#%d: error was not a NotAuthorizedToSign: %v", i, err)
- return false
+ t.Fatalf("error was not a NotAuthorizedToSign: %v", err)
}
- return true
}
-func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) {
+func expectUnhandledCriticalExtension(t *testing.T, err error) {
if _, ok := err.(UnhandledCriticalExtension); !ok {
- t.Errorf("#%d: error was not an UnhandledCriticalExtension: %v", i, err)
- return false
+ t.Fatalf("error was not an UnhandledCriticalExtension: %v", err)
}
- return true
}
func certificateFromPEM(pemBytes string) (*Certificate, error) {
return ParseCertificate(block.Bytes)
}
-func testVerify(t *testing.T, useSystemRoots bool) {
- defer func(savedIgnoreCN bool) {
- ignoreCN = savedIgnoreCN
- }(ignoreCN)
- for i, test := range verifyTests {
- if useSystemRoots && test.systemSkip {
- continue
- }
- if runtime.GOOS == "windows" && test.testSystemRootsError {
- continue
- }
-
- ignoreCN = test.ignoreCN
- opts := VerifyOptions{
- Intermediates: NewCertPool(),
- DNSName: test.dnsName,
- CurrentTime: time.Unix(test.currentTime, 0),
- KeyUsages: test.keyUsages,
- }
+func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
+ defer func(savedIgnoreCN bool) { ignoreCN = savedIgnoreCN }(ignoreCN)
- if !useSystemRoots {
- opts.Roots = NewCertPool()
- for j, root := range test.roots {
- ok := opts.Roots.AppendCertsFromPEM([]byte(root))
- if !ok {
- t.Errorf("#%d: failed to parse root #%d", i, j)
- return
- }
- }
- }
+ ignoreCN = test.ignoreCN
+ opts := VerifyOptions{
+ Intermediates: NewCertPool(),
+ DNSName: test.dnsName,
+ CurrentTime: time.Unix(test.currentTime, 0),
+ KeyUsages: test.keyUsages,
+ }
- for j, intermediate := range test.intermediates {
- ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
+ if !useSystemRoots {
+ opts.Roots = NewCertPool()
+ for j, root := range test.roots {
+ ok := opts.Roots.AppendCertsFromPEM([]byte(root))
if !ok {
- t.Errorf("#%d: failed to parse intermediate #%d", i, j)
- return
+ t.Fatalf("failed to parse root #%d", j)
}
}
+ }
- leaf, err := certificateFromPEM(test.leaf)
- if err != nil {
- t.Errorf("#%d: failed to parse leaf: %v", i, err)
- return
- }
-
- var oldSystemRoots *CertPool
- if test.testSystemRootsError {
- oldSystemRoots = systemRootsPool()
- systemRoots = nil
- opts.Roots = nil
+ for j, intermediate := range test.intermediates {
+ ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
+ if !ok {
+ t.Fatalf("failed to parse intermediate #%d", j)
}
+ }
- chains, err := leaf.Verify(opts)
+ leaf, err := certificateFromPEM(test.leaf)
+ if err != nil {
+ t.Fatalf("failed to parse leaf: %v", err)
+ }
- if test.testSystemRootsError {
- systemRoots = oldSystemRoots
- }
+ chains, err := leaf.Verify(opts)
- if test.errorCallback == nil && err != nil {
- t.Errorf("#%d: unexpected error: %v", i, err)
- }
- if test.errorCallback != nil {
- if !test.errorCallback(t, i, err) {
- return
+ if test.errorCallback == nil && err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if test.errorCallback != nil {
+ if useSystemRoots && test.systemLax {
+ if err == nil {
+ t.Fatalf("expected error")
}
+ } else {
+ test.errorCallback(t, err)
}
+ }
- if len(chains) != len(test.expectedChains) {
- t.Errorf("#%d: wanted %d chains, got %d", i, len(test.expectedChains), len(chains))
- }
+ if len(chains) != len(test.expectedChains) {
+ t.Errorf("wanted %d chains, got %d", len(test.expectedChains), len(chains))
+ }
- // We check that each returned chain matches a chain from
- // expectedChains but an entry in expectedChains can't match
- // two chains.
- seenChains := make([]bool, len(chains))
- NextOutputChain:
- for _, chain := range chains {
- TryNextExpected:
- for j, expectedChain := range test.expectedChains {
- if seenChains[j] {
- continue
- }
- if len(chain) != len(expectedChain) {
- continue
- }
- for k, cert := range chain {
- if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
- continue TryNextExpected
- }
+ // We check that each returned chain matches a chain from
+ // expectedChains but an entry in expectedChains can't match
+ // two chains.
+ seenChains := make([]bool, len(chains))
+NextOutputChain:
+ for _, chain := range chains {
+ TryNextExpected:
+ for j, expectedChain := range test.expectedChains {
+ if seenChains[j] {
+ continue
+ }
+ if len(chain) != len(expectedChain) {
+ continue
+ }
+ for k, cert := range chain {
+ if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
+ continue TryNextExpected
}
- // we matched
- seenChains[j] = true
- continue NextOutputChain
}
- t.Errorf("#%d: No expected chain matched %s", i, chainToDebugString(chain))
+ // we matched
+ seenChains[j] = true
+ continue NextOutputChain
}
+ t.Errorf("no expected chain matched %s", chainToDebugString(chain))
}
}
func TestGoVerify(t *testing.T) {
- testVerify(t, false)
+ for _, test := range verifyTests {
+ t.Run(test.name, func(t *testing.T) {
+ testVerify(t, test, false)
+ })
+ }
}
func TestSystemVerify(t *testing.T) {
t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
}
- testVerify(t, true)
+ for _, test := range verifyTests {
+ t.Run(test.name, func(t *testing.T) {
+ if test.systemSkip {
+ t.SkipNow()
+ }
+ testVerify(t, test, true)
+ })
+ }
}
func chainToDebugString(chain []*Certificate) string {
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const giag2Intermediate = `-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const googleLeaf = `-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
// algorithm in the certificate contains a nonsense OID.
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
-----END CERTIFICATE-----`
const smimeLeaf = `-----BEGIN CERTIFICATE-----
-MIIFBjCCA+6gAwIBAgISESFvrjT8XcJTEe6rBlPptILlMA0GCSqGSIb3DQEBBQUA
-MFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSowKAYD
-VQQDEyFHbG9iYWxTaWduIFBlcnNvbmFsU2lnbiAyIENBIC0gRzIwHhcNMTIwMTIz
-MTYzNjU5WhcNMTUwMTIzMTYzNjU5WjCBlDELMAkGA1UEBhMCVVMxFjAUBgNVBAgT
-DU5ldyBIYW1zcGhpcmUxEzARBgNVBAcTClBvcnRzbW91dGgxGTAXBgNVBAoTEEds
-b2JhbFNpZ24sIEluYy4xEzARBgNVBAMTClJ5YW4gSHVyc3QxKDAmBgkqhkiG9w0B
-CQEWGXJ5YW4uaHVyc3RAZ2xvYmFsc2lnbi5jb20wggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQC4ASSTvavmsFQAob60ukSSwOAL9nT/s99ltNUCAf5fPH5j
-NceMKxaQse2miOmRRIXaykcq1p/TbI70Ztce38r2mbOwqDHHPVi13GxJEyUXWgaR
-BteDMu5OGyWNG1kchVsGWpbstT0Z4v0md5m1BYFnxB20ebJyOR2lXDxsFK28nnKV
-+5eMj76U8BpPQ4SCH7yTMG6y0XXsB3cCrBKr2o3TOYgEKv+oNnbaoMt3UxMt9nSf
-9jyIshjqfnT5Aew3CUNMatO55g5FXXdIukAweg1YSb1ls05qW3sW00T3d7dQs9/7
-NuxCg/A2elmVJSoy8+MLR8JSFEf/aMgjO/TyLg/jAgMBAAGjggGPMIIBizAOBgNV
-HQ8BAf8EBAMCBaAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQwMgYIKwYBBQUH
-AgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMCQGA1Ud
-EQQdMBuBGXJ5YW4uaHVyc3RAZ2xvYmFsc2lnbi5jb20wCQYDVR0TBAIwADAdBgNV
-HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwQwYDVR0fBDwwOjA4oDagNIYyaHR0
-cDovL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc3BlcnNvbmFsc2lnbjJnMi5jcmww
-VQYIKwYBBQUHAQEESTBHMEUGCCsGAQUFBzAChjlodHRwOi8vc2VjdXJlLmdsb2Jh
-bHNpZ24uY29tL2NhY2VydC9nc3BlcnNvbmFsc2lnbjJnMi5jcnQwHQYDVR0OBBYE
-FFWiECe0/L72eVYqcWYnLV6SSjzhMB8GA1UdIwQYMBaAFD8V0m18L+cxnkMKBqiU
-bCw7xe5lMA0GCSqGSIb3DQEBBQUAA4IBAQAhQi6hLPeudmf3IBF4IDzCvRI0FaYd
-BKfprSk/H0PDea4vpsLbWpA0t0SaijiJYtxKjlM4bPd+2chb7ejatDdyrZIzmDVy
-q4c30/xMninGKokpYA11/Ve+i2dvjulu65qasrtQRGybAuuZ67lrp/K3OMFgjV5N
-C3AHYLzvNU4Dwc4QQ1BaMOg6KzYSrKbABRZajfrpC9uiePsv7mDIXLx/toBPxWNl
-a5vJm5DrZdn7uHdvBCE6kMykbOLN5pmEK0UIlwKh6Qi5XD0pzlVkEZliFkBMJgub
-d/eF7xeg7TKPWC5xyOFp9SdMolJM7LTC3wnSO3frBAev+q/nGs9Xxyvs
+MIIIPDCCBiSgAwIBAgIQaMDxFS0pOMxZZeOBxoTJtjANBgkqhkiG9w0BAQsFADCB
+nTELMAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTowOAYDVQQLDDFB
+WlogWml1cnRhZ2lyaSBwdWJsaWtvYSAtIENlcnRpZmljYWRvIHB1YmxpY28gU0NB
+MTwwOgYDVQQDDDNFQUVrbyBIZXJyaSBBZG1pbmlzdHJhemlvZW4gQ0EgLSBDQSBB
+QVBQIFZhc2NhcyAoMikwHhcNMTcwNzEyMDg1MzIxWhcNMjEwNzEyMDg1MzIxWjCC
+AQwxDzANBgNVBAoMBklaRU5QRTE4MDYGA1UECwwvWml1cnRhZ2lyaSBrb3Jwb3Jh
+dGlib2EtQ2VydGlmaWNhZG8gY29ycG9yYXRpdm8xQzBBBgNVBAsMOkNvbmRpY2lv
+bmVzIGRlIHVzbyBlbiB3d3cuaXplbnBlLmNvbSBub2xhIGVyYWJpbGkgamFraXRl
+a28xFzAVBgNVBC4TDi1kbmkgOTk5OTk5ODlaMSQwIgYDVQQDDBtDT1JQT1JBVElW
+TyBGSUNUSUNJTyBBQ1RJVk8xFDASBgNVBCoMC0NPUlBPUkFUSVZPMREwDwYDVQQE
+DAhGSUNUSUNJTzESMBAGA1UEBRMJOTk5OTk5ODlaMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAwVOMwUDfBtsH0XuxYnb+v/L774jMH8valX7RPH8cl2Lb
+SiqSo0RchW2RGA2d1yuYHlpChC9jGmt0X/g66/E/+q2hUJlfJtqVDJFwtFYV4u2S
+yzA3J36V4PRkPQrKxAsbzZriFXAF10XgiHQz9aVeMMJ9GBhmh9+DK8Tm4cMF6i8l
++AuC35KdngPF1x0ealTYrYZplpEJFO7CiW42aLi6vQkDR2R7nmZA4AT69teqBWsK
+0DZ93/f0G/3+vnWwNTBF0lB6dIXoaz8OMSyHLqGnmmAtMrzbjAr/O/WWgbB/BqhR
+qjJQ7Ui16cuDldXaWQ/rkMzsxmsAox0UF+zdQNvXUQIDAQABo4IDBDCCAwAwgccG
+A1UdEgSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j
+b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S
+TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh
+IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H
+YXN0ZWl6MB4GA1UdEQQXMBWBE2ZpY3RpY2lvQGl6ZW5wZS5ldXMwDgYDVR0PAQH/
+BAQDAgXgMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC
+AjAdBgNVHQ4EFgQUyeoOD4cgcljKY0JvrNuX2waFQLAwHwYDVR0jBBgwFoAUwKlK
+90clh/+8taaJzoLSRqiJ66MwggEnBgNVHSAEggEeMIIBGjCCARYGCisGAQQB8zkB
+AQEwggEGMDMGCCsGAQUFBwIBFidodHRwOi8vd3d3Lml6ZW5wZS5jb20vcnBhc2Nh
+Y29ycG9yYXRpdm8wgc4GCCsGAQUFBwICMIHBGoG+Wml1cnRhZ2lyaWEgRXVza2Fs
+IEF1dG9ub21pYSBFcmtpZGVnb2tvIHNla3RvcmUgcHVibGlrb2tvIGVyYWt1bmRl
+ZW4gYmFybmUtc2FyZWV0YW4gYmFrYXJyaWsgZXJhYmlsIGRhaXRla2UuIFVzbyBy
+ZXN0cmluZ2lkbyBhbCBhbWJpdG8gZGUgcmVkZXMgaW50ZXJuYXMgZGUgRW50aWRh
+ZGVzIGRlbCBTZWN0b3IgUHVibGljbyBWYXNjbzAyBggrBgEFBQcBAQQmMCQwIgYI
+KwYBBQUHMAGGFmh0dHA6Ly9vY3NwLml6ZW5wZS5jb20wOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vY3JsaW50ZXJuYTIwDQYJ
+KoZIhvcNAQELBQADggIBAIy5PQ+UZlCRq6ig43vpHwlwuD9daAYeejV0Q+ZbgWAE
+GtO0kT/ytw95ZEJMNiMw3fYfPRlh27ThqiT0VDXZJDlzmn7JZd6QFcdXkCsiuv4+
+ZoXAg/QwnA3SGUUO9aVaXyuOIIuvOfb9MzoGp9xk23SMV3eiLAaLMLqwB5DTfBdt
+BGI7L1MnGJBv8RfP/TL67aJ5bgq2ri4S8vGHtXSjcZ0+rCEOLJtmDNMnTZxancg3
+/H5edeNd+n6Z48LO+JHRxQufbC4mVNxVLMIP9EkGUejlq4E4w6zb5NwCQczJbSWL
+i31rk2orsNsDlyaLGsWZp3JSNX6RmodU4KAUPor4jUJuUhrrm3Spb73gKlV/gcIw
+bCE7mML1Kss3x1ySaXsis6SZtLpGWKkW2iguPWPs0ydV6RPhmsCxieMwPPIJ87vS
+5IejfgyBae7RSuAIHyNFy4uI5xwvwUFf6OZ7az8qtW7ImFOgng3Ds+W9k1S2CNTx
+d0cnKTfA6IpjGo8EeHcxnIXT8NPImWaRj0qqonvYady7ci6U4m3lkNSdXNn1afgw
+mYust+gxVtOZs1gk2MUCgJ1V1X+g7r/Cg7viIn6TLkLrpS1kS1hvMqkl9M+7XqPo
+Qd95nJKOkusQpy99X4dF/lfbYAQnnjnqh3DLD2gvYObXFaAYFaiBKTiMTV2X72F+
-----END CERTIFICATE-----`
const smimeIntermediate = `-----BEGIN CERTIFICATE-----
-MIIEFjCCAv6gAwIBAgILBAAAAAABL07hL1IwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw
-MDBaFw0xOTA0MTMxMDAwMDBaMFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMSowKAYDVQQDEyFHbG9iYWxTaWduIFBlcnNvbmFsU2lnbiAy
-IENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBa0H5Nez4
-En3dIlFpX7e5E0YndxQ74xOBbz7kdBd+DLX0LOQMjVPU3DAgKL9ujhH+ZhHkURbH
-3X/94TQSUL/z2JjsaQvS0NqyZXHhM5eeuquzOJRzEQ8+odETzHg2G0Erv7yjSeww
-gkwDWDJnYUDlOjYTDUEG6+i+8Mn425reo4I0E277wD542kmVWeW7+oHv5dZo9e1Q
-yWwiKTEP6BEQVVSBgThXMG4traSSDRUt3T1eQTZx5EObpiBEBO4OTqiBTJfg4vEI
-YgkXzKLpnfszTB6YMDpR9/QS6p3ANB3kfAb+t6udSO3WCst0DGrwHDLBFGDR4UeY
-T5KGGnI7cWL7AgMBAAGjgeUwgeIwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
-MAYBAf8CAQAwHQYDVR0OBBYEFD8V0m18L+cxnkMKBqiUbCw7xe5lMEcGA1UdIARA
-MD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWdu
-LmNvbS9yZXBvc2l0b3J5LzAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmds
-b2JhbHNpZ24ubmV0L3Jvb3QuY3JsMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTN
-NKj//P1LMA0GCSqGSIb3DQEBBQUAA4IBAQBDc3nMpMxJMQMcYUCB3+C73UpvwDE8
-eCOr7t2F/uaQKKcyqqstqLZc6vPwI/rcE9oDHugY5QEjQzIBIEaTnN6P0vege2IX
-eCOr7t2F/uaQKKcyqqstqLZc6vPwI/rcE9oDHugY5QEjQzIBIEaTnN6P0vege2IX
-YEvTWbWwGdPytDFPYIl3/6OqNSXSnZ7DxPcdLJq2uyiga8PB/TTIIHYkdM2+1DE0
-7y3rH/7TjwDVD7SLu5/SdOfKskuMPTjOEvz3K161mymW06klVhubCIWOro/Gx1Q2
-2FQOZ7/2k4uYoOdBTSlb8kTAuzZNgIE0rB2BIYCTz/P6zZIKW0ogbRSH
+MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL
+MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu
+cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV
+BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0
+YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE
+AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj
+YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h
+rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2
+To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU
+ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD
+PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr
+PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn
+soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM
+8IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL
+MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg
+jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk
+3LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb
+KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w
+gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO
+MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0
+b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk
+aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl
+h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw
+OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl
+bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v
+b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny
+bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM
+3DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS
+M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E
+3TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL
+xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4
+VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR
+0oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK
+b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi
+1tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS
+FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM
+5tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw
+k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7
+-----END CERTIFICATE-----`
+
+const smimeRoot = `-----BEGIN CERTIFICATE-----
+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
-----END CERTIFICATE-----`
var megaLeaf = `-----BEGIN CERTIFICATE-----
cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
-----END CERTIFICATE-----`
-const issuerSubjectMatchRoot = `
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 161640039802297062 (0x23e42c281e55ae6)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: O=Golang, CN=Root ca
- Validity
- Not Before: Jan 1 00:00:00 2015 GMT
- Not After : Jan 1 00:00:00 2025 GMT
- Subject: O=Golang, CN=Root ca
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:e9:0e:7f:11:0c:e6:5a:e6:86:83:70:f6:51:07:
- 2e:02:78:11:f5:b2:24:92:38:ee:26:62:02:c7:94:
- f1:3e:a1:77:6a:c0:8f:d5:22:68:b6:5d:e2:4c:da:
- e0:85:11:35:c2:92:72:49:8d:81:b4:88:97:6b:b7:
- fc:b2:44:5b:d9:4d:06:70:f9:0c:c6:8f:e9:b3:df:
- a3:6a:84:6c:43:59:be:9d:b2:d0:76:9b:c3:d7:fa:
- 99:59:c3:b8:e5:f3:53:03:bd:49:d6:b3:cc:a2:43:
- fe:ad:c2:0b:b9:01:b8:56:29:94:03:24:a7:0d:28:
- 21:29:a9:ae:94:5b:4a:f9:9f
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Key Usage: critical
- Certificate Sign
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Key Identifier:
- 40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
- Signature Algorithm: sha256WithRSAEncryption
- 6f:84:df:49:e0:99:d4:71:66:1d:32:86:56:cb:ea:5a:6b:0e:
- 00:6a:d1:5a:6e:1f:06:23:07:ff:cb:d1:1a:74:e4:24:43:0b:
- aa:2a:a0:73:75:25:82:bc:bf:3f:a9:f8:48:88:ac:ed:3a:94:
- 3b:0d:d3:88:c8:67:44:61:33:df:71:6c:c5:af:ed:16:8c:bf:
- 82:f9:49:bb:e3:2a:07:53:36:37:25:77:de:91:a4:77:09:7f:
- 6f:b2:91:58:c4:05:89:ea:8e:fa:e1:3b:19:ef:f8:f6:94:b7:
- 7b:27:e6:e4:84:dd:2b:f5:93:f5:3c:d8:86:c5:38:01:56:5c:
- 9f:6d
------BEGIN CERTIFICATE-----
+const issuerSubjectMatchRoot = `-----BEGIN CERTIFICATE-----
MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
eyfm5ITdK/WT9TzYhsU4AVZcn20=
-----END CERTIFICATE-----`
-const issuerSubjectMatchLeaf = `
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 16785088708916013734 (0xe8f09d3fe25beaa6)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: O=Golang, CN=Root CA
- Validity
- Not Before: Jan 1 00:00:00 2015 GMT
- Not After : Jan 1 00:00:00 2025 GMT
- Subject: O=Golang, CN=Leaf
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:db:46:7d:93:2e:12:27:06:48:bc:06:28:21:ab:
- 7e:c4:b6:a2:5d:fe:1e:52:45:88:7a:36:47:a5:08:
- 0d:92:42:5b:c2:81:c0:be:97:79:98:40:fb:4f:6d:
- 14:fd:2b:13:8b:c2:a5:2e:67:d8:d4:09:9e:d6:22:
- 38:b7:4a:0b:74:73:2b:c2:34:f1:d1:93:e5:96:d9:
- 74:7b:f3:58:9f:6c:61:3c:c0:b0:41:d4:d9:2b:2b:
- 24:23:77:5b:1c:3b:bd:75:5d:ce:20:54:cf:a1:63:
- 87:1d:1e:24:c4:f3:1d:1a:50:8b:aa:b6:14:43:ed:
- 97:a7:75:62:f4:14:c8:52:d7
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication, TLS Web Client Authentication
- X509v3 Basic Constraints: critical
- CA:FALSE
- X509v3 Subject Key Identifier:
- 9F:91:16:1F:43:43:3E:49:A6:DE:6D:B6:80:D7:9F:60
- X509v3 Authority Key Identifier:
- keyid:40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
-
- Signature Algorithm: sha256WithRSAEncryption
- 8d:86:05:da:89:f5:1d:c5:16:14:41:b9:34:87:2b:5c:38:99:
- e3:d9:5a:5b:7a:5b:de:0b:5c:08:45:09:6f:1c:9d:31:5f:08:
- ca:7a:a3:99:da:83:0b:22:be:4f:02:35:91:4e:5d:5c:37:bf:
- 89:22:58:7d:30:76:d2:2f:d0:a0:ee:77:9e:77:c0:d6:19:eb:
- ec:a0:63:35:6a:80:9b:80:1a:80:de:64:bc:40:38:3c:22:69:
- ad:46:26:a2:3d:ea:f4:c2:92:49:16:03:96:ae:64:21:b9:7c:
- ee:64:91:47:81:aa:b4:0c:09:2b:12:1a:b2:f3:af:50:b3:b1:
- ce:24
------BEGIN CERTIFICATE-----
+const issuerSubjectMatchLeaf = `-----BEGIN CERTIFICATE-----
MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
-const x509v1TestRoot = `
------BEGIN CERTIFICATE-----
+const x509v1TestRoot = `-----BEGIN CERTIFICATE-----
MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
/1JmacUUofl+HusHuLkDxmadogI=
-----END CERTIFICATE-----`
-const x509v1TestIntermediate = `
------BEGIN CERTIFICATE-----
+const x509v1TestIntermediate = `-----BEGIN CERTIFICATE-----
MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
-----END CERTIFICATE-----`
-const x509v1TestLeaf = `
------BEGIN CERTIFICATE-----
+const x509v1TestLeaf = `-----BEGIN CERTIFICATE-----
MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
-----END CERTIFICATE-----`
-const ignoreCNWithSANRoot = `
------BEGIN CERTIFICATE-----
+const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE-----
MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
BJ6bvwEAasFiLGP6Zbdmxb2hIA==
-----END CERTIFICATE-----`
-const ignoreCNWithSANLeaf = `
------BEGIN CERTIFICATE-----
+const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE-----
MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
xZbqP3Krgjj4XNaXjg==
-----END CERTIFICATE-----`
-const excludedNamesLeaf = `
------BEGIN CERTIFICATE-----
+const excludedNamesLeaf = `-----BEGIN CERTIFICATE-----
MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+
VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4
oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
-const excludedNamesIntermediate = `
------BEGIN CERTIFICATE-----
+const excludedNamesIntermediate = `-----BEGIN CERTIFICATE-----
MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
zMBX1/lk4wkFckeUIlkD55Y=
-----END CERTIFICATE-----`
-const excludedNamesRoot = `
------BEGIN CERTIFICATE-----
+const excludedNamesRoot = `-----BEGIN CERTIFICATE-----
MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy
-----END CERTIFICATE-----`
-const invalidCNRoot = `
------BEGIN CERTIFICATE-----
+const invalidCNRoot = `-----BEGIN CERTIFICATE-----
MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg
cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM
CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj
QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg
oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI
XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6
------END CERTIFICATE-----
-`
-
-const invalidCNWithoutSAN = `
-Certificate:
- Data:
- Version: 1 (0x0)
- Serial Number:
- 07:ba:bc:b7:d9:ab:0c:02:fe:50:1d:4e:15:a3:0d:e4:11:16:14:a2
- Signature Algorithm: ecdsa-with-SHA256
- Issuer: OU = Test root
- Validity
- Not Before: Jul 11 18:35:21 2018 GMT
- Not After : Jul 8 18:35:21 2028 GMT
- Subject: CN = "foo,invalid"
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- pub:
- 04:a7:a6:7c:22:33:a7:47:7f:08:93:2d:5f:61:35:
- 2e:da:45:67:76:f2:97:73:18:b0:01:12:4a:1a:d5:
- b7:6f:41:3c:bb:05:69:f4:06:5d:ff:eb:2b:a7:85:
- 0b:4c:f7:45:4e:81:40:7a:a9:c6:1d:bb:ba:d9:b9:
- 26:b3:ca:50:90
- ASN1 OID: prime256v1
- NIST CURVE: P-256
- Signature Algorithm: ecdsa-with-SHA256
- 30:45:02:21:00:85:96:75:b6:72:3c:67:12:a0:7f:86:04:81:
- d2:dd:c8:67:50:d7:5f:85:c0:54:54:fc:e6:6b:45:08:93:d3:
- 2a:02:20:60:86:3e:d6:28:a6:4e:da:dd:6e:95:89:cc:00:76:
- 78:1c:03:80:85:a6:5a:0b:eb:c5:f3:9c:2e:df:ef:6e:fa
------BEGIN CERTIFICATE-----
+-----END CERTIFICATE-----`
+
+const invalidCNWithoutSAN = `-----BEGIN CERTIFICATE-----
MIIBJDCBywIUB7q8t9mrDAL+UB1OFaMN5BEWFKIwCgYIKoZIzj0EAwIwFDESMBAG
A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4MzUyMVoXDTI4MDcwODE4MzUyMVow
FjEUMBIGA1UEAwwLZm9vLGludmFsaWQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
90VOgUB6qcYdu7rZuSazylCQMAoGCCqGSM49BAMCA0gAMEUCIQCFlnW2cjxnEqB/
hgSB0t3IZ1DXX4XAVFT85mtFCJPTKgIgYIY+1iimTtrdbpWJzAB2eBwDgIWmWgvr
xfOcLt/vbvo=
------END CERTIFICATE-----
-`
-
-const validCNWithoutSAN = `
-Certificate:
- Data:
- Version: 1 (0x0)
- Serial Number:
- 07:ba:bc:b7:d9:ab:0c:02:fe:50:1d:4e:15:a3:0d:e4:11:16:14:a4
- Signature Algorithm: ecdsa-with-SHA256
- Issuer: OU = Test root
- Validity
- Not Before: Jul 11 18:47:24 2018 GMT
- Not After : Jul 8 18:47:24 2028 GMT
- Subject: CN = foo.example.com
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- pub:
- 04:a7:a6:7c:22:33:a7:47:7f:08:93:2d:5f:61:35:
- 2e:da:45:67:76:f2:97:73:18:b0:01:12:4a:1a:d5:
- b7:6f:41:3c:bb:05:69:f4:06:5d:ff:eb:2b:a7:85:
- 0b:4c:f7:45:4e:81:40:7a:a9:c6:1d:bb:ba:d9:b9:
- 26:b3:ca:50:90
- ASN1 OID: prime256v1
- NIST CURVE: P-256
- Signature Algorithm: ecdsa-with-SHA256
- 30:44:02:20:53:6c:d7:b7:59:61:51:72:a5:18:a3:4b:0d:52:
- ea:15:fa:d0:93:30:32:54:4b:ed:0f:58:85:b8:a8:1a:82:3b:
- 02:20:14:77:4b:0e:7e:4f:0a:4f:64:26:97:dc:d0:ed:aa:67:
- 1d:37:85:da:b4:87:ba:25:1c:2a:58:f7:23:11:8b:3d
------BEGIN CERTIFICATE-----
+-----END CERTIFICATE-----`
+
+const validCNWithoutSAN = `-----BEGIN CERTIFICATE-----
MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG
A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow
GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR
cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0
h7olHCpY9yMRiz0=
------END CERTIFICATE-----
-`
-
-const (
- rootWithoutSKID = `
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- 78:29:2a:dc:2f:12:39:7f:c9:33:93:ea:61:39:7d:70
- Signature Algorithm: ecdsa-with-SHA256
- Issuer: O = Acme Co
- Validity
- Not Before: Feb 4 22:56:34 2019 GMT
- Not After : Feb 1 22:56:34 2029 GMT
- Subject: O = Acme Co
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- pub:
- 04:84:a6:8c:69:53:af:87:4b:39:64:fe:04:24:e6:
- d8:fc:d6:46:39:35:0e:92:dc:48:08:7e:02:5f:1e:
- 07:53:5c:d9:e0:56:c5:82:07:f6:a3:e2:ad:f6:ad:
- be:a0:4e:03:87:39:67:0c:9c:46:91:68:6b:0e:8e:
- f8:49:97:9d:5b
- ASN1 OID: prime256v1
- NIST CURVE: P-256
- X509v3 extensions:
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment, Certificate Sign
- X509v3 Extended Key Usage:
- TLS Web Server Authentication
- X509v3 Basic Constraints: critical
- CA:TRUE
- X509v3 Subject Alternative Name:
- DNS:example
- Signature Algorithm: ecdsa-with-SHA256
- 30:46:02:21:00:c6:81:61:61:42:8d:37:e7:d0:c3:72:43:44:
- 17:bd:84:ff:88:81:68:9a:99:08:ab:3c:3a:c0:1e:ea:8c:ba:
- c0:02:21:00:de:c9:fa:e5:5e:c6:e2:db:23:64:43:a9:37:42:
- 72:92:7f:6e:89:38:ea:9e:2a:a7:fd:2f:ea:9a:ff:20:21:e7
------BEGIN CERTIFICATE-----
+-----END CERTIFICATE-----`
+
+const rootWithoutSKID = `-----BEGIN CERTIFICATE-----
MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI
KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA
AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec=
------END CERTIFICATE-----
-`
- leafWithAKID = `
- Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number:
- f0:8a:62:f0:03:84:a2:cf:69:63:ad:71:3b:b6:5d:8c
- Signature Algorithm: ecdsa-with-SHA256
- Issuer: O = Acme Co
- Validity
- Not Before: Feb 4 23:06:52 2019 GMT
- Not After : Feb 1 23:06:52 2029 GMT
- Subject: O = Acme LLC
- Subject Public Key Info:
- Public Key Algorithm: id-ecPublicKey
- Public-Key: (256 bit)
- pub:
- 04:5a:4e:4d:fb:ff:17:f7:b6:13:e8:29:45:34:81:
- 39:ff:8c:9c:d9:8c:0a:9f:dd:b5:97:4c:2b:20:91:
- 1c:4f:6b:be:53:27:66:ec:4a:ad:08:93:6d:66:36:
- 0c:02:70:5d:01:ca:7f:c3:29:e9:4f:00:ba:b4:14:
- ec:c5:c3:34:b3
- ASN1 OID: prime256v1
- NIST CURVE: P-256
- X509v3 extensions:
- X509v3 Key Usage: critical
- Digital Signature, Key Encipherment
- X509v3 Extended Key Usage:
- TLS Web Server Authentication
- X509v3 Basic Constraints: critical
- CA:FALSE
- X509v3 Authority Key Identifier:
- keyid:C2:2B:5F:91:78:34:26:09:42:8D:6F:51:B2:C5:AF:4C:0B:DE:6A:42
-
- X509v3 Subject Alternative Name:
- DNS:example
- Signature Algorithm: ecdsa-with-SHA256
- 30:44:02:20:64:e0:ba:56:89:63:ce:22:5e:4f:22:15:fd:3c:
- 35:64:9a:3a:6b:7b:9a:32:a0:7f:f7:69:8c:06:f0:00:58:b8:
- 02:20:09:e4:9f:6d:8b:9e:38:e1:b6:01:d5:ee:32:a4:94:65:
- 93:2a:78:94:bb:26:57:4b:c7:dd:6c:3d:40:2b:63:90
------BEGIN CERTIFICATE-----
+-----END CERTIFICATE-----`
+
+const leafWithAKID = `-----BEGIN CERTIFICATE-----
MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa
MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
ZZMqeJS7JldLx91sPUArY5A=
------END CERTIFICATE-----
-`
-)
+-----END CERTIFICATE-----`
var unknownAuthorityErrorTests = []struct {
cert string
}
t.Logf("verification took %v", time.Since(start))
}
+
+func TestSystemRootsError(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("Windows does not use (or support) systemRoots")
+ }
+
+ defer func(oldSystemRoots *CertPool) { systemRoots = oldSystemRoots }(systemRootsPool())
+
+ opts := VerifyOptions{
+ Intermediates: NewCertPool(),
+ DNSName: "www.google.com",
+ CurrentTime: time.Unix(1395785200, 0),
+ }
+
+ if ok := opts.Intermediates.AppendCertsFromPEM([]byte(giag2Intermediate)); !ok {
+ t.Fatalf("failed to parse intermediate")
+ }
+
+ leaf, err := certificateFromPEM(googleLeaf)
+ if err != nil {
+ t.Fatalf("failed to parse leaf: %v", err)
+ }
+
+ systemRoots = nil
+
+ _, err = leaf.Verify(opts)
+ if _, ok := err.(SystemRootsError); !ok {
+ t.Errorf("error was not SystemRootsError: %v", err)
+ }
+}