Skip to content

Commit 0d3dab9

Browse files
crypto/x509: simplify candidate chain filtering
Use slices.DeleteFunc to remove chains with invalid policies and incompatible key usage, instead of iterating over the chains and reconstructing the slice. Change-Id: I8ad2bc1ac2469d0d18b2c090e3d4f702b1b577cb Reviewed-on: https://go-review.googlesource.com/c/go/+/708415 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Daniel McCarney <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 2904639 commit 0d3dab9

File tree

2 files changed

+26
-35
lines changed

2 files changed

+26
-35
lines changed

src/crypto/x509/verify.go

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"net/url"
1818
"reflect"
1919
"runtime"
20+
"slices"
2021
"strings"
2122
"time"
2223
"unicode/utf8"
@@ -801,7 +802,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
801802
// Certificates other than c in the returned chains should not be modified.
802803
//
803804
// WARNING: this function doesn't do any revocation checking.
804-
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
805+
func (c *Certificate) Verify(opts VerifyOptions) ([][]*Certificate, error) {
805806
// Platform-specific verification needs the ASN.1 contents so
806807
// this makes the behavior consistent across platforms.
807808
if len(c.Raw) == 0 {
@@ -843,15 +844,15 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
843844
}
844845
}
845846

846-
err = c.isValid(leafCertificate, nil, &opts)
847+
err := c.isValid(leafCertificate, nil, &opts)
847848
if err != nil {
848-
return
849+
return nil, err
849850
}
850851

851852
if len(opts.DNSName) > 0 {
852853
err = c.VerifyHostname(opts.DNSName)
853854
if err != nil {
854-
return
855+
return nil, err
855856
}
856857
}
857858

@@ -865,61 +866,51 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
865866
}
866867
}
867868

868-
chains = make([][]*Certificate, 0, len(candidateChains))
869-
870-
var invalidPoliciesChains int
871-
for _, candidate := range candidateChains {
872-
if !policiesValid(candidate, opts) {
873-
invalidPoliciesChains++
874-
continue
875-
}
876-
chains = append(chains, candidate)
877-
}
878-
879-
if len(chains) == 0 {
880-
return nil, CertificateInvalidError{c, NoValidChains, "all candidate chains have invalid policies"}
881-
}
882-
869+
anyKeyUsage := false
883870
for _, eku := range opts.KeyUsages {
884871
if eku == ExtKeyUsageAny {
885-
// If any key usage is acceptable, no need to check the chain for
886-
// key usages.
887-
return chains, nil
872+
// The presence of anyExtendedKeyUsage overrides any other key usage.
873+
anyKeyUsage = true
874+
break
888875
}
889876
}
890877

891878
if len(opts.KeyUsages) == 0 {
892879
opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
893880
}
894881

895-
candidateChains = chains
896-
chains = chains[:0]
897-
882+
var invalidPoliciesChains int
898883
var incompatibleKeyUsageChains int
899-
for _, candidate := range candidateChains {
900-
if !checkChainForKeyUsage(candidate, opts.KeyUsages) {
884+
candidateChains = slices.DeleteFunc(candidateChains, func(chain []*Certificate) bool {
885+
if !policiesValid(chain, opts) {
886+
invalidPoliciesChains++
887+
return true
888+
}
889+
// If any key usage is acceptable, no need to check the chain for
890+
// key usages.
891+
if !anyKeyUsage && !checkChainForKeyUsage(chain, opts.KeyUsages) {
901892
incompatibleKeyUsageChains++
902-
continue
893+
return true
903894
}
904-
chains = append(chains, candidate)
905-
}
895+
return false
896+
})
906897

907-
if len(chains) == 0 {
898+
if len(candidateChains) == 0 {
908899
var details []string
909900
if incompatibleKeyUsageChains > 0 {
910901
if invalidPoliciesChains == 0 {
911902
return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
912903
}
913-
details = append(details, fmt.Sprintf("%d chains with incompatible key usage", incompatibleKeyUsageChains))
904+
details = append(details, fmt.Sprintf("%d candidate chains with incompatible key usage", incompatibleKeyUsageChains))
914905
}
915906
if invalidPoliciesChains > 0 {
916-
details = append(details, fmt.Sprintf("%d chains with invalid policies", invalidPoliciesChains))
907+
details = append(details, fmt.Sprintf("%d candidate chains with invalid policies", invalidPoliciesChains))
917908
}
918909
err = CertificateInvalidError{c, NoValidChains, strings.Join(details, ", ")}
919910
return nil, err
920911
}
921912

922-
return chains, nil
913+
return candidateChains, nil
923914
}
924915

925916
func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {

src/crypto/x509/verify_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,7 @@ func TestInvalidPolicyWithAnyKeyUsage(t *testing.T) {
30313031
testOID3 := mustNewOIDFromInts([]uint64{1, 2, 840, 113554, 4, 1, 72585, 2, 3})
30323032
root, intermediate, leaf := loadTestCert(t, "testdata/policy_root.pem"), loadTestCert(t, "testdata/policy_intermediate_require.pem"), loadTestCert(t, "testdata/policy_leaf.pem")
30333033

3034-
expectedErr := "x509: no valid chains built: all candidate chains have invalid policies"
3034+
expectedErr := "x509: no valid chains built: 1 candidate chains with invalid policies"
30353035

30363036
roots, intermediates := NewCertPool(), NewCertPool()
30373037
roots.AddCert(root)

0 commit comments

Comments
 (0)