mirror of
https://github.com/golang/go
synced 2024-11-21 21:04:41 -07:00
crypto/x509: enforce path length constraint.
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
This commit is contained in:
parent
52d6ca2f86
commit
ed35d5e0fb
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user