summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/x509/verify.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/x509/verify.go')
-rw-r--r--libgo/go/crypto/x509/verify.go80
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
}
}