@@ -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
925916func appendToFreshChain (chain []* Certificate , cert * Certificate ) []* Certificate {
0 commit comments