mirror of
https://github.com/golang/go
synced 2024-11-22 09:34:54 -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
|
// certificate has a name constraint which doesn't include the name
|
||||||
// being checked.
|
// being checked.
|
||||||
CANotAuthorizedForThisName
|
CANotAuthorizedForThisName
|
||||||
|
// TooManyIntermediates results when a path length constraint is
|
||||||
|
// violated.
|
||||||
|
TooManyIntermediates
|
||||||
)
|
)
|
||||||
|
|
||||||
// CertificateInvalidError results when an odd error occurs. Users of this
|
// 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"
|
return "x509: certificate has expired or is not yet valid"
|
||||||
case CANotAuthorizedForThisName:
|
case CANotAuthorizedForThisName:
|
||||||
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
|
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"
|
return "x509: unknown error"
|
||||||
}
|
}
|
||||||
@ -87,7 +92,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// isValid performs validity checks on the c.
|
// 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
|
now := opts.CurrentTime
|
||||||
if now.IsZero() {
|
if now.IsZero() {
|
||||||
now = time.Now()
|
now = time.Now()
|
||||||
@ -130,6 +135,13 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
|
|||||||
return CertificateInvalidError{c, NotAuthorizedToSign}
|
return CertificateInvalidError{c, NotAuthorizedToSign}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
|
||||||
|
numIntermediates := len(currentChain) - 1
|
||||||
|
if numIntermediates > c.MaxPathLen {
|
||||||
|
return CertificateInvalidError{c, TooManyIntermediates}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +152,7 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
|
|||||||
//
|
//
|
||||||
// WARNING: this doesn't do any revocation checking.
|
// WARNING: this doesn't do any revocation checking.
|
||||||
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
|
||||||
err = c.isValid(leafCertificate, &opts)
|
err = c.isValid(leafCertificate, nil, &opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
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) {
|
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||||
for _, rootNum := range opts.Roots.findVerifiedParents(c) {
|
for _, rootNum := range opts.Roots.findVerifiedParents(c) {
|
||||||
root := opts.Roots.certs[rootNum]
|
root := opts.Roots.certs[rootNum]
|
||||||
err = root.isValid(rootCertificate, opts)
|
err = root.isValid(rootCertificate, currentChain, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -178,7 +190,7 @@ nextIntermediate:
|
|||||||
continue nextIntermediate
|
continue nextIntermediate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = intermediate.isValid(intermediateCertificate, opts)
|
err = intermediate.isValid(intermediateCertificate, currentChain, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ func (h UnhandledCriticalExtension) Error() string {
|
|||||||
|
|
||||||
type basicConstraints struct {
|
type basicConstraints struct {
|
||||||
IsCA bool `asn1:"optional"`
|
IsCA bool `asn1:"optional"`
|
||||||
MaxPathLen int `asn1:"optional"`
|
MaxPathLen int `asn1:"optional,default:-1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RFC 5280 4.2.1.4
|
// RFC 5280 4.2.1.4
|
||||||
|
Loading…
Reference in New Issue
Block a user