diff options
Diffstat (limited to 'libgo/go/crypto/x509/verify.go')
-rw-r--r-- | libgo/go/crypto/x509/verify.go | 80 |
1 files changed, 66 insertions, 14 deletions
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 85c083fbb2c..29345a1755c 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -5,6 +5,7 @@ package x509 import ( + "bytes" "errors" "fmt" "net" @@ -33,6 +34,9 @@ const ( // IncompatibleUsage results when the certificate's key usage indicates // that it may only be used for a different purpose. IncompatibleUsage + // NameMismatch results when the subject name of a parent certificate + // does not match the issuer name in the child. + NameMismatch ) // CertificateInvalidError results when an odd error occurs. Users of this @@ -54,6 +58,8 @@ func (e CertificateInvalidError) Error() string { return "x509: too many intermediates for path length constraint" case IncompatibleUsage: return "x509: certificate specifies an incompatible key usage" + case NameMismatch: + return "x509: issuer name does not match subject from issuing certificate" } return "x509: unknown error" } @@ -87,12 +93,16 @@ func (h HostnameError) Error() string { valid = c.Subject.CommonName } } + + if len(valid) == 0 { + return "x509: certificate is not valid for any names, but wanted to match " + h.Host + } return "x509: certificate is valid for " + valid + ", not " + h.Host } // UnknownAuthorityError results when the certificate issuer is unknown type UnknownAuthorityError struct { - cert *Certificate + Cert *Certificate // hintErr contains an error that may be helpful in determining why an // authority wasn't found. hintErr error @@ -108,8 +118,9 @@ func (e UnknownAuthorityError) Error() string { if len(certName) == 0 { if len(e.hintCert.Subject.Organization) > 0 { certName = e.hintCert.Subject.Organization[0] + } else { + certName = "serial:" + e.hintCert.SerialNumber.String() } - certName = "serial:" + e.hintCert.SerialNumber.String() } s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) } @@ -142,7 +153,7 @@ type VerifyOptions struct { CurrentTime time.Time // if zero, the current time is used // KeyUsage specifies which Extended Key Usage values are acceptable. // An empty list means ExtKeyUsageServerAuth. Key usage is considered a - // constraint down the chain which mirrors Windows CryptoAPI behaviour, + // constraint down the chain which mirrors Windows CryptoAPI behavior, // but not the spec. To accept any key usage, include ExtKeyUsageAny. KeyUsages []ExtKeyUsage } @@ -153,8 +164,40 @@ const ( rootCertificate ) +func matchNameConstraint(domain, constraint string) bool { + // The meaning of zero length constraints is not specified, but this + // code follows NSS and accepts them as valid for everything. + if len(constraint) == 0 { + return true + } + + if len(domain) < len(constraint) { + return false + } + + prefixLen := len(domain) - len(constraint) + if !strings.EqualFold(domain[prefixLen:], constraint) { + return false + } + + if prefixLen == 0 { + return true + } + + isSubdomain := domain[prefixLen-1] == '.' + constraintHasLeadingDot := constraint[0] == '.' + return isSubdomain != constraintHasLeadingDot +} + // isValid performs validity checks on the c. func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { + if len(currentChain) > 0 { + child := currentChain[len(currentChain)-1] + if !bytes.Equal(child.RawIssuer, c.RawSubject) { + return CertificateInvalidError{c, NameMismatch} + } + } + now := opts.CurrentTime if now.IsZero() { now = time.Now() @@ -165,12 +208,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V if len(c.PermittedDNSDomains) > 0 { ok := false - for _, domain := range c.PermittedDNSDomains { - if opts.DNSName == domain || - (strings.HasSuffix(opts.DNSName, domain) && - len(opts.DNSName) >= 1+len(domain) && - opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') { - ok = true + for _, constraint := range c.PermittedDNSDomains { + ok = matchNameConstraint(opts.DNSName, constraint) + if ok { break } } @@ -222,7 +262,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V // WARNING: this doesn't do any revocation checking. func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { // Platform-specific verification needs the ASN.1 contents so - // this makes the behaviour consistent across platforms. + // this makes the behavior consistent across platforms. if len(c.Raw) == 0 { return nil, errNotParsed } @@ -262,9 +302,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e } } - candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) - if err != nil { - return + var candidateChains [][]*Certificate + if opts.Roots.contains(c) { + candidateChains = append(candidateChains, []*Certificate{c}) + } else { + if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil { + return nil, err + } } keyUsages := opts.KeyUsages @@ -302,8 +346,16 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) { possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c) +nextRoot: for _, rootNum := range possibleRoots { root := opts.Roots.certs[rootNum] + + for _, cert := range currentChain { + if cert.Equal(root) { + continue nextRoot + } + } + err = root.isValid(rootCertificate, currentChain, opts) if err != nil { continue @@ -316,7 +368,7 @@ nextIntermediate: for _, intermediateNum := range possibleIntermediates { intermediate := opts.Intermediates.certs[intermediateNum] for _, cert := range currentChain { - if cert == intermediate { + if cert.Equal(intermediate) { continue nextIntermediate } } |