aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2020-07-14 14:39:38 -0400
committerKatie Hockman <katie@golang.org>2020-07-14 14:39:38 -0400
commit6e1b89a431337a1e4584bd15f3a1af9c5c7b1bb0 (patch)
tree68cdf9589c548f360fc34c88dab787e6addef9c2
parente19af0f1447e0f99688949c68cd8c39d188f699c (diff)
parent1f8859c22ccdeb969b252c8139bf4b1aae5c4909 (diff)
downloadgo-6e1b89a431337a1e4584bd15f3a1af9c5c7b1bb0.tar.gz
go-6e1b89a431337a1e4584bd15f3a1af9c5c7b1bb0.zip
[release-branch.go1.13] all: merge release-branch.go1.13-security into release-branch.go1.13
Change-Id: Id0cca0e1006d92960e7f665d41111483c0fcea13
-rw-r--r--VERSION2
-rw-r--r--src/crypto/x509/root_windows.go46
-rw-r--r--src/crypto/x509/verify.go44
-rw-r--r--src/crypto/x509/verify_test.go888
-rw-r--r--src/net/http/server.go43
5 files changed, 467 insertions, 556 deletions
diff --git a/VERSION b/VERSION
index 0b3e27fd11..4e2f10ea6b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.13.12 \ No newline at end of file
+go1.13.13 \ No newline at end of file
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
index ebf159c178..94669f229e 100644
--- a/src/crypto/x509/root_windows.go
+++ b/src/crypto/x509/root_windows.go
@@ -88,6 +88,9 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
switch status {
case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
return CertificateInvalidError{c, Expired, ""}
+ case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
+ return CertificateInvalidError{c, IncompatibleUsage, ""}
+ // TODO(filippo): surface more error statuses.
default:
return UnknownAuthorityError{c, nil, nil}
}
@@ -138,11 +141,19 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
return nil
}
+// windowsExtKeyUsageOIDs are the C NUL-terminated string representations of the
+// OIDs for use with the Windows API.
+var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
+
+func init() {
+ for _, eku := range extKeyUsageOIDs {
+ windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
+ }
+}
+
// systemVerify is like Verify, except that it uses CryptoAPI calls
// to build certificate chains and verify them.
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
- hasDNSName := opts != nil && len(opts.DNSName) > 0
-
storeCtx, err := createStoreContext(c, opts)
if err != nil {
return nil, err
@@ -152,17 +163,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
para := new(syscall.CertChainPara)
para.Size = uint32(unsafe.Sizeof(*para))
- // If there's a DNSName set in opts, assume we're verifying
- // a certificate from a TLS server.
- if hasDNSName {
- oids := []*byte{
- &syscall.OID_PKIX_KP_SERVER_AUTH[0],
- // Both IE and Chrome allow certificates with
- // Server Gated Crypto as well. Some certificates
- // in the wild require them.
- &syscall.OID_SERVER_GATED_CRYPTO[0],
- &syscall.OID_SGC_NETSCAPE[0],
+ keyUsages := opts.KeyUsages
+ if len(keyUsages) == 0 {
+ keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ }
+ oids := make([]*byte, 0, len(keyUsages))
+ for _, eku := range keyUsages {
+ if eku == ExtKeyUsageAny {
+ oids = nil
+ break
+ }
+ if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
+ oids = append(oids, &oid[0])
}
+ // Like the standard verifier, accept SGC EKUs as equivalent to ServerAuth.
+ if eku == ExtKeyUsageServerAuth {
+ oids = append(oids, &syscall.OID_SERVER_GATED_CRYPTO[0])
+ oids = append(oids, &syscall.OID_SGC_NETSCAPE[0])
+ }
+ }
+ if oids != nil {
para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
para.RequestedUsage.Usage.Length = uint32(len(oids))
para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
@@ -208,7 +228,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return nil, err
}
- if hasDNSName {
+ if opts != nil && len(opts.DNSName) > 0 {
err = checkChainSSLServerPolicy(c, chainCtx, opts)
if err != nil {
return nil, err
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 3b5b3576bd..4f11647c81 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -188,23 +188,32 @@ var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificat
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
// because other PKIX verification APIs have ended up needing many options.
type VerifyOptions struct {
- DNSName string
+ // DNSName, if set, is checked against the leaf certificate with
+ // Certificate.VerifyHostname or the platform verifier.
+ DNSName string
+
+ // Intermediates is an optional pool of certificates that are not trust
+ // anchors, but can be used to form a chain from the leaf certificate to a
+ // root certificate.
Intermediates *CertPool
- Roots *CertPool // if nil, the system roots are used
- CurrentTime time.Time // if zero, the current time is used
- // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
- // certificate is accepted if it contains any of the listed values. An empty
- // list means ExtKeyUsageServerAuth. To accept any key usage, include
- // ExtKeyUsageAny.
- //
- // Certificate chains are required to nest these extended key usage values.
- // (This matches the Windows CryptoAPI behavior, but not the spec.)
+ // Roots is the set of trusted root certificates the leaf certificate needs
+ // to chain up to. If nil, the system roots or the platform verifier are used.
+ Roots *CertPool
+
+ // CurrentTime is used to check the validity of all certificates in the
+ // chain. If zero, the current time is used.
+ CurrentTime time.Time
+
+ // KeyUsages specifies which Extended Key Usage values are acceptable. A
+ // chain is accepted if it allows any of the listed values. An empty list
+ // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny.
KeyUsages []ExtKeyUsage
+
// MaxConstraintComparisions is the maximum number of comparisons to
// perform when checking a given certificate's name constraints. If
// zero, a sensible default is used. This limit prevents pathological
// certificates from consuming excessive amounts of CPU time when
- // validating.
+ // validating. It does not apply to the platform verifier.
MaxConstraintComparisions int
}
@@ -707,8 +716,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// needed. If successful, it returns one or more chains where the first
// element of the chain is c and the last element is from opts.Roots.
//
-// If opts.Roots is nil and system roots are unavailable the returned error
-// will be of type SystemRootsError.
+// If opts.Roots is nil, the platform verifier might be used, and
+// verification details might differ from what is described below. If system
+// roots are unavailable the returned error will be of type SystemRootsError.
//
// Name constraints in the intermediates will be applied to all names claimed
// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
@@ -716,9 +726,11 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// the name being validated. Note that DirectoryName constraints are not
// supported.
//
-// Extended Key Usage values are enforced down a chain, so an intermediate or
-// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
-// list.
+//
+// Extended Key Usage values are enforced nested down a chain, so an intermediate
+// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
+// list. (While this is not specified, it is common practice in order to limit
+// the types of certificates a CA can issue.)
//
// WARNING: this function doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 86fe76a57d..bbb68db857 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -21,34 +21,24 @@ import (
)
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},
@@ -60,6 +50,7 @@ var verifyTests = []verifyTest{
},
},
{
+ name: "MixedCase",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
@@ -71,6 +62,7 @@ var verifyTests = []verifyTest{
},
},
{
+ name: "HostnameMismatch",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
@@ -80,6 +72,7 @@ var verifyTests = []verifyTest{
errorCallback: expectHostnameError("certificate is valid for"),
},
{
+ name: "IPMissing",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
@@ -89,6 +82,7 @@ var verifyTests = []verifyTest{
errorCallback: expectHostnameError("doesn't contain any IP SANs"),
},
{
+ name: "Expired",
leaf: googleLeaf,
intermediates: []string{giag2Intermediate},
roots: []string{geoTrustRoot},
@@ -98,6 +92,7 @@ var verifyTests = []verifyTest{
errorCallback: expectExpired,
},
{
+ name: "MissingIntermediate",
leaf: googleLeaf,
roots: []string{geoTrustRoot},
currentTime: 1395785200,
@@ -109,6 +104,7 @@ var verifyTests = []verifyTest{
errorCallback: expectAuthorityUnknown,
},
{
+ name: "RootInIntermediates",
leaf: googleLeaf,
intermediates: []string{geoTrustRoot, giag2Intermediate},
roots: []string{geoTrustRoot},
@@ -119,31 +115,50 @@ var verifyTests = []verifyTest{
{"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},
@@ -152,50 +167,52 @@ var verifyTests = []verifyTest{
// 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"},
},
@@ -203,6 +220,7 @@ var verifyTests = []verifyTest{
{
// Check that a name constrained intermediate works even when
// it lists multiple constraints.
+ name: "MultipleConstraints",
leaf: nameConstraintsLeaf,
intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
roots: []string{globalSignRoot},
@@ -221,17 +239,16 @@ var verifyTests = []verifyTest{
{
// 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",
@@ -244,11 +261,12 @@ var verifyTests = []verifyTest{
{
// 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"},
@@ -257,11 +275,12 @@ var verifyTests = []verifyTest{
{
// 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"),
},
@@ -269,87 +288,95 @@ var verifyTests = []verifyTest{
// 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"},
@@ -357,31 +384,34 @@ var verifyTests = []verifyTest{
},
// 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"),
@@ -389,11 +419,12 @@ var verifyTests = []verifyTest{
{
// 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"},
@@ -401,98 +432,70 @@ var verifyTests = []verifyTest{
},
}
-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) {
@@ -503,107 +506,91 @@ 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) {
@@ -611,7 +598,14 @@ 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 {
@@ -648,8 +642,7 @@ tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const giag2Intermediate = `-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
@@ -674,8 +667,7 @@ zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const googleLeaf = `-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
@@ -702,8 +694,7 @@ tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
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.
@@ -732,8 +723,7 @@ tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
@@ -858,58 +848,127 @@ NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
-----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-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
+MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
+ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
+VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
+b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
+scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
+xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
+LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
+uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
+yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
+rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
+BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
+hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
+QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
+Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
+QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
+BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
+A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
+laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
+awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
+JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
+LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
+VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
+LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
+UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
+QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
+QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----`
var megaLeaf = `-----BEGIN CERTIFICATE-----
@@ -1315,50 +1374,7 @@ vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
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
@@ -1373,53 +1389,7 @@ RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
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
@@ -1432,11 +1402,9 @@ Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
------END CERTIFICATE-----
-`
+-----END CERTIFICATE-----`
-const x509v1TestRoot = `
------BEGIN CERTIFICATE-----
+const x509v1TestRoot = `-----BEGIN CERTIFICATE-----
MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
@@ -1451,8 +1419,7 @@ h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB
/1JmacUUofl+HusHuLkDxmadogI=
-----END CERTIFICATE-----`
-const x509v1TestIntermediate = `
------BEGIN CERTIFICATE-----
+const x509v1TestIntermediate = `-----BEGIN CERTIFICATE-----
MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
@@ -1465,8 +1432,7 @@ zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur
x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
-----END CERTIFICATE-----`
-const x509v1TestLeaf = `
------BEGIN CERTIFICATE-----
+const x509v1TestLeaf = `-----BEGIN CERTIFICATE-----
MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
@@ -1481,8 +1447,7 @@ CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9
/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
-----END CERTIFICATE-----`
-const ignoreCNWithSANRoot = `
------BEGIN CERTIFICATE-----
+const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE-----
MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
@@ -1503,8 +1468,7 @@ aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu
BJ6bvwEAasFiLGP6Zbdmxb2hIA==
-----END CERTIFICATE-----`
-const ignoreCNWithSANLeaf = `
------BEGIN CERTIFICATE-----
+const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE-----
MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
@@ -1526,8 +1490,7 @@ j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn
xZbqP3Krgjj4XNaXjg==
-----END CERTIFICATE-----`
-const excludedNamesLeaf = `
------BEGIN CERTIFICATE-----
+const excludedNamesLeaf = `-----BEGIN CERTIFICATE-----
MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
@@ -1549,11 +1512,9 @@ hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt
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
@@ -1577,8 +1538,7 @@ LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS
zMBX1/lk4wkFckeUIlkD55Y=
-----END CERTIFICATE-----`
-const excludedNamesRoot = `
------BEGIN CERTIFICATE-----
+const excludedNamesRoot = `-----BEGIN CERTIFICATE-----
MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
@@ -1603,46 +1563,16 @@ yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT
+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
@@ -1650,38 +1580,9 @@ AASnpnwiM6dHfwiTLV9hNS7aRWd28pdzGLABEkoa1bdvQTy7BWn0Bl3/6yunhQtM
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
@@ -1689,48 +1590,9 @@ AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr
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
@@ -1739,49 +1601,9 @@ ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
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
@@ -1791,9 +1613,7 @@ CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R
ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
ZZMqeJS7JldLx91sPUArY5A=
------END CERTIFICATE-----
-`
-)
+-----END CERTIFICATE-----`
var unknownAuthorityErrorTests = []struct {
cert string
@@ -2124,3 +1944,33 @@ func TestLongChain(t *testing.T) {
}
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)
+ }
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 8252e45aca..a66e798be6 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -424,6 +424,16 @@ type response struct {
wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive"
wantsClose bool // HTTP request has Connection "close"
+ // canWriteContinue is a boolean value accessed as an atomic int32
+ // that says whether or not a 100 Continue header can be written
+ // to the connection.
+ // writeContinueMu must be held while writing the header.
+ // These two fields together synchronize the body reader
+ // (the expectContinueReader, which wants to write 100 Continue)
+ // against the main writer.
+ canWriteContinue atomicBool
+ writeContinueMu sync.Mutex
+
w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter
@@ -514,6 +524,7 @@ type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
+func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
// declareTrailer is called for each Trailer header when the
// response header is written. It notes that a header will need to be
@@ -876,21 +887,27 @@ type expectContinueReader struct {
resp *response
readCloser io.ReadCloser
closed bool
- sawEOF bool
+ sawEOF atomicBool
}
func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
if ecr.closed {
return 0, ErrBodyReadAfterClose
}
- if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked() {
- ecr.resp.wroteContinue = true
- ecr.resp.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
- ecr.resp.conn.bufw.Flush()
+ w := ecr.resp
+ if !w.wroteContinue && w.canWriteContinue.isSet() && !w.conn.hijacked() {
+ w.wroteContinue = true
+ w.writeContinueMu.Lock()
+ if w.canWriteContinue.isSet() {
+ w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
+ w.conn.bufw.Flush()
+ w.canWriteContinue.setFalse()
+ }
+ w.writeContinueMu.Unlock()
}
n, err = ecr.readCloser.Read(p)
if err == io.EOF {
- ecr.sawEOF = true
+ ecr.sawEOF.setTrue()
}
return
}
@@ -1309,7 +1326,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// because we don't know if the next bytes on the wire will be
// the body-following-the-timer or the subsequent request.
// See Issue 11549.
- if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF {
+ if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.isSet() {
w.closeAfterReply = true
}
@@ -1554,6 +1571,17 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er
}
return 0, ErrHijacked
}
+
+ if w.canWriteContinue.isSet() {
+ // Body reader wants to write 100 Continue but hasn't yet.
+ // Tell it not to. The store must be done while holding the lock
+ // because the lock makes sure that there is not an active write
+ // this very moment.
+ w.writeContinueMu.Lock()
+ w.canWriteContinue.setFalse()
+ w.writeContinueMu.Unlock()
+ }
+
if !w.wroteHeader {
w.WriteHeader(StatusOK)
}
@@ -1866,6 +1894,7 @@ func (c *conn) serve(ctx context.Context) {
if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
+ w.canWriteContinue.setTrue()
}
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()