]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: enforce path length constraint.
authorAdam Langley <agl@golang.org>
Mon, 5 Mar 2012 17:08:42 +0000 (12:08 -0500)
committerAdam Langley <agl@golang.org>
Mon, 5 Mar 2012 17:08:42 +0000 (12:08 -0500)
An X.509 path length constrains the number of certificate that may
follow in the chain. This is a little simplistic for a first pass as it
doesn't check self-signed certificates (which don't count towards the
length), but it's conservatively simplistic.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5727057

src/pkg/crypto/x509/verify.go
src/pkg/crypto/x509/x509.go

index 3859dd8d4888cbc19fe401274056f69d084055c0..3497f34dd12194b21336463260287f59f4b13eeb 100644 (file)
@@ -23,6 +23,9 @@ const (
        // certificate has a name constraint which doesn't include the name
        // being checked.
        CANotAuthorizedForThisName
+       // TooManyIntermediates results when a path length constraint is
+       // violated.
+       TooManyIntermediates
 )
 
 // CertificateInvalidError results when an odd error occurs. Users of this
@@ -40,6 +43,8 @@ func (e CertificateInvalidError) Error() string {
                return "x509: certificate has expired or is not yet valid"
        case CANotAuthorizedForThisName:
                return "x509: a root or intermediate certificate is not authorized to sign in this domain"
+       case TooManyIntermediates:
+               return "x509: too many intermediates for path length constraint"
        }
        return "x509: unknown error"
 }
@@ -87,7 +92,7 @@ const (
 )
 
 // isValid performs validity checks on the c.
-func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
+func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
        now := opts.CurrentTime
        if now.IsZero() {
                now = time.Now()
@@ -130,6 +135,13 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
                return CertificateInvalidError{c, NotAuthorizedToSign}
        }
 
+       if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
+               numIntermediates := len(currentChain) - 1
+               if numIntermediates > c.MaxPathLen {
+                       return CertificateInvalidError{c, TooManyIntermediates}
+               }
+       }
+
        return nil
 }
 
@@ -140,7 +152,7 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
 //
 // WARNING: this doesn't do any revocation checking.
 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
-       err = c.isValid(leafCertificate, &opts)
+       err = c.isValid(leafCertificate, nil, &opts)
        if err != nil {
                return
        }
@@ -163,7 +175,7 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
        for _, rootNum := range opts.Roots.findVerifiedParents(c) {
                root := opts.Roots.certs[rootNum]
-               err = root.isValid(rootCertificate, opts)
+               err = root.isValid(rootCertificate, currentChain, opts)
                if err != nil {
                        continue
                }
@@ -178,7 +190,7 @@ nextIntermediate:
                                continue nextIntermediate
                        }
                }
-               err = intermediate.isValid(intermediateCertificate, opts)
+               err = intermediate.isValid(intermediateCertificate, currentChain, opts)
                if err != nil {
                        continue
                }
index f5da86b54a021c0d560693b001aca6642ad4d2eb..8dae7e7fcf948c302c0ac97dd1fa415e5fb6334a 100644 (file)
@@ -429,7 +429,7 @@ func (h UnhandledCriticalExtension) Error() string {
 
 type basicConstraints struct {
        IsCA       bool `asn1:"optional"`
-       MaxPathLen int  `asn1:"optional"`
+       MaxPathLen int  `asn1:"optional,default:-1"`
 }
 
 // RFC 5280 4.2.1.4