@@ -636,107 +636,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
636636 }
637637 }
638638
639- maxConstraintComparisons := opts .MaxConstraintComparisions
640- if maxConstraintComparisons == 0 {
641- maxConstraintComparisons = 250000
642- }
643- comparisonCount := 0
644-
645- if certType == intermediateCertificate || certType == rootCertificate {
646- if len (currentChain ) == 0 {
647- return errors .New ("x509: internal error: empty chain when appending CA cert" )
648- }
649- }
650-
651- // Each time we do constraint checking, we need to check the constraints in
652- // the current certificate against all of the names that preceded it. We
653- // reverse these names using domainToReverseLabels, which is a relatively
654- // expensive operation. Since we check each name against each constraint,
655- // this requires us to do N*C calls to domainToReverseLabels (where N is the
656- // total number of names that preceed the certificate, and C is the total
657- // number of constraints in the certificate). By caching the results of
658- // calling domainToReverseLabels, we can reduce that to N+C calls at the
659- // cost of keeping all of the parsed names and constraints in memory until
660- // we return from isValid.
661- reversedDomainsCache := map [string ][]string {}
662- reversedConstraintsCache := map [string ][]string {}
663-
664- if (certType == intermediateCertificate || certType == rootCertificate ) &&
665- c .hasNameConstraints () {
666- toCheck := []* Certificate {}
667- for _ , c := range currentChain {
668- if c .hasSANExtension () {
669- toCheck = append (toCheck , c )
670- }
671- }
672- for _ , sanCert := range toCheck {
673- err := forEachSAN (sanCert .getSANExtension (), func (tag int , data []byte ) error {
674- switch tag {
675- case nameTypeEmail :
676- name := string (data )
677- mailbox , ok := parseRFC2821Mailbox (name )
678- if ! ok {
679- return fmt .Errorf ("x509: cannot parse rfc822Name %q" , mailbox )
680- }
681-
682- if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "email address" , name , mailbox ,
683- func (parsedName , constraint any ) (bool , error ) {
684- return matchEmailConstraint (parsedName .(rfc2821Mailbox ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
685- }, c .PermittedEmailAddresses , c .ExcludedEmailAddresses ); err != nil {
686- return err
687- }
688-
689- case nameTypeDNS :
690- name := string (data )
691- if ! domainNameValid (name , false ) {
692- return fmt .Errorf ("x509: cannot parse dnsName %q" , name )
693- }
694-
695- if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "DNS name" , name , name ,
696- func (parsedName , constraint any ) (bool , error ) {
697- return matchDomainConstraint (parsedName .(string ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
698- }, c .PermittedDNSDomains , c .ExcludedDNSDomains ); err != nil {
699- return err
700- }
701-
702- case nameTypeURI :
703- name := string (data )
704- uri , err := url .Parse (name )
705- if err != nil {
706- return fmt .Errorf ("x509: internal error: URI SAN %q failed to parse" , name )
707- }
708-
709- if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "URI" , name , uri ,
710- func (parsedName , constraint any ) (bool , error ) {
711- return matchURIConstraint (parsedName .(* url.URL ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
712- }, c .PermittedURIDomains , c .ExcludedURIDomains ); err != nil {
713- return err
714- }
715-
716- case nameTypeIP :
717- ip := net .IP (data )
718- if l := len (ip ); l != net .IPv4len && l != net .IPv6len {
719- return fmt .Errorf ("x509: internal error: IP SAN %x failed to parse" , data )
720- }
721-
722- if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "IP address" , ip .String (), ip ,
723- func (parsedName , constraint any ) (bool , error ) {
724- return matchIPConstraint (parsedName .(net.IP ), constraint .(* net.IPNet ))
725- }, c .PermittedIPRanges , c .ExcludedIPRanges ); err != nil {
726- return err
727- }
728-
729- default :
730- // Unknown SAN types are ignored.
731- }
732-
733- return nil
734- })
735-
736- if err != nil {
737- return err
738- }
739- }
639+ if (certType == intermediateCertificate || certType == rootCertificate ) && len (currentChain ) == 0 {
640+ return errors .New ("x509: internal error: empty chain when appending CA cert" )
740641 }
741642
742643 // KeyUsage status flags are ignored. From Engineering Security, Peter
@@ -881,6 +782,7 @@ func (c *Certificate) Verify(opts VerifyOptions) ([][]*Certificate, error) {
881782
882783 var invalidPoliciesChains int
883784 var incompatibleKeyUsageChains int
785+ var constraintsHintErr error
884786 candidateChains = slices .DeleteFunc (candidateChains , func (chain []* Certificate ) bool {
885787 if ! policiesValid (chain , opts ) {
886788 invalidPoliciesChains ++
@@ -892,10 +794,19 @@ func (c *Certificate) Verify(opts VerifyOptions) ([][]*Certificate, error) {
892794 incompatibleKeyUsageChains ++
893795 return true
894796 }
797+ if err := checkChainConstraints (chain , opts ); err != nil {
798+ if constraintsHintErr == nil {
799+ constraintsHintErr = err
800+ }
801+ return true
802+ }
895803 return false
896804 })
897805
898806 if len (candidateChains ) == 0 {
807+ if constraintsHintErr != nil {
808+ return nil , constraintsHintErr // Preserve previous constraint behavior
809+ }
899810 var details []string
900811 if incompatibleKeyUsageChains > 0 {
901812 if invalidPoliciesChains == 0 {
@@ -1271,6 +1182,106 @@ NextCert:
12711182 return true
12721183}
12731184
1185+ func checkChainConstraints (chain []* Certificate , opts VerifyOptions ) error {
1186+ maxConstraintComparisons := opts .MaxConstraintComparisions
1187+ if maxConstraintComparisons == 0 {
1188+ maxConstraintComparisons = 250000
1189+ }
1190+ comparisonCount := 0
1191+
1192+ // Each time we do constraint checking, we need to check the constraints in
1193+ // the current certificate against all of the names that preceded it. We
1194+ // reverse these names using domainToReverseLabels, which is a relatively
1195+ // expensive operation. Since we check each name against each constraint,
1196+ // this requires us to do N*C calls to domainToReverseLabels (where N is the
1197+ // total number of names that preceed the certificate, and C is the total
1198+ // number of constraints in the certificate). By caching the results of
1199+ // calling domainToReverseLabels, we can reduce that to N+C calls at the
1200+ // cost of keeping all of the parsed names and constraints in memory until
1201+ // we return from isValid.
1202+ reversedDomainsCache := map [string ][]string {}
1203+ reversedConstraintsCache := map [string ][]string {}
1204+
1205+ for i , c := range chain {
1206+ if ! c .hasNameConstraints () {
1207+ continue
1208+ }
1209+ for _ , sanCert := range chain [:i ] {
1210+ if ! sanCert .hasSANExtension () {
1211+ continue
1212+ }
1213+ err := forEachSAN (sanCert .getSANExtension (), func (tag int , data []byte ) error {
1214+ switch tag {
1215+ case nameTypeEmail :
1216+ name := string (data )
1217+ mailbox , ok := parseRFC2821Mailbox (name )
1218+ if ! ok {
1219+ return fmt .Errorf ("x509: cannot parse rfc822Name %q" , mailbox )
1220+ }
1221+
1222+ if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "email address" , name , mailbox ,
1223+ func (parsedName , constraint any ) (bool , error ) {
1224+ return matchEmailConstraint (parsedName .(rfc2821Mailbox ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
1225+ }, c .PermittedEmailAddresses , c .ExcludedEmailAddresses ); err != nil {
1226+ return err
1227+ }
1228+
1229+ case nameTypeDNS :
1230+ name := string (data )
1231+ if ! domainNameValid (name , false ) {
1232+ return fmt .Errorf ("x509: cannot parse dnsName %q" , name )
1233+ }
1234+
1235+ if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "DNS name" , name , name ,
1236+ func (parsedName , constraint any ) (bool , error ) {
1237+ return matchDomainConstraint (parsedName .(string ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
1238+ }, c .PermittedDNSDomains , c .ExcludedDNSDomains ); err != nil {
1239+ return err
1240+ }
1241+
1242+ case nameTypeURI :
1243+ name := string (data )
1244+ uri , err := url .Parse (name )
1245+ if err != nil {
1246+ return fmt .Errorf ("x509: internal error: URI SAN %q failed to parse" , name )
1247+ }
1248+
1249+ if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "URI" , name , uri ,
1250+ func (parsedName , constraint any ) (bool , error ) {
1251+ return matchURIConstraint (parsedName .(* url.URL ), constraint .(string ), reversedDomainsCache , reversedConstraintsCache )
1252+ }, c .PermittedURIDomains , c .ExcludedURIDomains ); err != nil {
1253+ return err
1254+ }
1255+
1256+ case nameTypeIP :
1257+ ip := net .IP (data )
1258+ if l := len (ip ); l != net .IPv4len && l != net .IPv6len {
1259+ return fmt .Errorf ("x509: internal error: IP SAN %x failed to parse" , data )
1260+ }
1261+
1262+ if err := c .checkNameConstraints (& comparisonCount , maxConstraintComparisons , "IP address" , ip .String (), ip ,
1263+ func (parsedName , constraint any ) (bool , error ) {
1264+ return matchIPConstraint (parsedName .(net.IP ), constraint .(* net.IPNet ))
1265+ }, c .PermittedIPRanges , c .ExcludedIPRanges ); err != nil {
1266+ return err
1267+ }
1268+
1269+ default :
1270+ // Unknown SAN types are ignored.
1271+ }
1272+
1273+ return nil
1274+ })
1275+
1276+ if err != nil {
1277+ return err
1278+ }
1279+ }
1280+ }
1281+
1282+ return nil
1283+ }
1284+
12741285func mustNewOIDFromInts (ints []uint64 ) OID {
12751286 oid , err := OIDFromInts (ints )
12761287 if err != nil {
0 commit comments