diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 7cc0fb2..b590adf 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -17,6 +17,7 @@
"net/url"
"reflect"
"runtime"
+ "slices"
"strings"
"time"
"unicode/utf8"
@@ -777,7 +778,7 @@
// Certificates other than c in the returned chains should not be modified.
//
// WARNING: this function doesn't do any revocation checking.
-func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
+func (c *Certificate) Verify(opts VerifyOptions) ([][]*Certificate, error) {
// Platform-specific verification needs the ASN.1 contents so
// this makes the behavior consistent across platforms.
if len(c.Raw) == 0 {
@@ -819,15 +820,15 @@
}
}
- err = c.isValid(leafCertificate, nil, &opts)
+ err := c.isValid(leafCertificate, nil, &opts)
if err != nil {
- return
+ return nil, err
}
if len(opts.DNSName) > 0 {
err = c.VerifyHostname(opts.DNSName)
if err != nil {
- return
+ return nil, err
}
}
@@ -841,26 +842,10 @@
}
}
- chains = make([][]*Certificate, 0, len(candidateChains))
-
- var invalidPoliciesChains int
- for _, candidate := range candidateChains {
- if !policiesValid(candidate, opts) {
- invalidPoliciesChains++
- continue
- }
- chains = append(chains, candidate)
- }
-
- if len(chains) == 0 {
- return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"}
- }
-
+ anyKeyUsage := false
for _, eku := range opts.KeyUsages {
if eku == ExtKeyUsageAny {
- // If any key usage is acceptable, no need to check the chain for
- // key usages.
- return chains, nil
+ anyKeyUsage = true
}
}
@@ -868,34 +853,38 @@
opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
}
- candidateChains = chains
- chains = chains[:0]
-
+ var invalidPoliciesChains int
var incompatibleKeyUsageChains int
- for _, candidate := range candidateChains {
- if !checkChainForKeyUsage(candidate, opts.KeyUsages) {
- incompatibleKeyUsageChains++
- continue
+ candidateChains = slices.DeleteFunc(candidateChains, func(chain []*Certificate) bool {
+ if !policiesValid(chain, opts) {
+ invalidPoliciesChains++
+ return true
}
- chains = append(chains, candidate)
- }
+ // If any key usage is acceptable, no need to check the chain for
+ // key usages.
+ if !anyKeyUsage && !checkChainForKeyUsage(chain, opts.KeyUsages) {
+ incompatibleKeyUsageChains++
+ return true
+ }
+ return false
+ })
- if len(chains) == 0 {
+ if len(candidateChains) == 0 {
var details []string
if incompatibleKeyUsageChains > 0 {
if invalidPoliciesChains == 0 {
return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
}
- details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains))
+ details = append(details, fmt.Sprintf("%d candidate chains with incompatible key usage", incompatibleKeyUsageChains))
}
if invalidPoliciesChains > 0 {
- details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains))
+ details = append(details, fmt.Sprintf("%d candidate chains with invalid policies", invalidPoliciesChains))
}
err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")}
return nil, err
}
- return chains, nil
+ return candidateChains, nil
}
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 7991f49..30c6173 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -3030,7 +3030,7 @@
testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3})
root, intermediate, leaf := loadTestCert(t, "testdata/policy_root.pem"), loadTestCert(t, "testdata/policy_intermediate_require.pem"), loadTestCert(t, "testdata/policy_leaf.pem")
- expectedErr := "x509: no valid chains built: all candidate chains have invalid policies"
+ expectedErr := "x509: no valid chains built: 1 candidate chains with invalid policies"
roots, intermediates := NewCertPool(), NewCertPool()
roots.AddCert(root)