aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/crypto/x509/verify.go
diff options
context:
space:
mode:
authorGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-22 17:43:43 -0300
committerGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-22 17:43:43 -0300
commita926878ddbd5a98b272c22171ce58663fc04c3e0 (patch)
tree86af256e5d9a9c06263c00adc90e5fe348008c43 /libgo/go/crypto/x509/verify.go
parent542730f087133690b47e036dfd43eb0db8a650ce (diff)
parent07cbaed8ba7d1b6e4ab3a9f44175502a4e1ecdb1 (diff)
downloadgcc-devel/autopar_devel.zip
gcc-devel/autopar_devel.tar.gz
gcc-devel/autopar_devel.tar.bz2
Merge branch 'autopar_rebase2' into autopar_develdevel/autopar_devel
Quickly commit changes in the rebase branch.
Diffstat (limited to 'libgo/go/crypto/x509/verify.go')
-rw-r--r--libgo/go/crypto/x509/verify.go142
1 files changed, 98 insertions, 44 deletions
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 358fca4..cb8d8f8 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -19,7 +19,7 @@ import (
)
// ignoreCN disables interpreting Common Name as a hostname. See issue 24151.
-var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1")
+var ignoreCN = !strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=0")
type InvalidReason int
@@ -48,9 +48,9 @@ const (
// contains name constraints, and the Common Name can be interpreted as
// a hostname.
//
- // You can avoid this error by setting the experimental GODEBUG environment
- // variable to "x509ignoreCN=1", disabling Common Name matching entirely.
- // This behavior might become the default in the future.
+ // This error is only returned when legacy Common Name matching is enabled
+ // by setting the GODEBUG environment variable to "x509ignoreCN=1". This
+ // setting might be removed in the future.
NameConstraintsWithoutSANs
// UnconstrainedName results when a CA certificate contains permitted
// name constraints, but leaf certificate contains a name of an
@@ -109,10 +109,16 @@ type HostnameError struct {
func (h HostnameError) Error() string {
c := h.Certificate
- if !c.hasSANExtension() && !validHostname(c.Subject.CommonName) &&
- matchHostnames(toLowerCaseASCII(c.Subject.CommonName), toLowerCaseASCII(h.Host)) {
- // This would have validated, if it weren't for the validHostname check on Common Name.
- return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+ if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
+ if !ignoreCN && !validHostnamePattern(c.Subject.CommonName) {
+ // This would have validated, if it weren't for the validHostname check on Common Name.
+ return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+ }
+ if ignoreCN && validHostnamePattern(c.Subject.CommonName) {
+ // This would have validated if x509ignoreCN=0 were set.
+ return "x509: certificate relies on legacy Common Name field, " +
+ "use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0"
+ }
}
var valid string
@@ -185,26 +191,34 @@ func (se SystemRootsError) Error() string {
// verified. Platform-specific verification needs the ASN.1 contents.
var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
-// VerifyOptions contains parameters for Certificate.Verify. It's a structure
-// because other PKIX verification APIs have ended up needing many options.
+// VerifyOptions contains parameters for Certificate.Verify.
type VerifyOptions struct {
- DNSName string
+ // DNSName, if set, is checked against the leaf certificate with
+ // Certificate.VerifyHostname or the platform verifier.
+ DNSName string
+
+ // Intermediates is an optional pool of certificates that are not trust
+ // anchors, but can be used to form a chain from the leaf certificate to a
+ // root certificate.
Intermediates *CertPool
- Roots *CertPool // if nil, the system roots are used
- CurrentTime time.Time // if zero, the current time is used
- // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
- // certificate is accepted if it contains any of the listed values. An empty
- // list means ExtKeyUsageServerAuth. To accept any key usage, include
- // ExtKeyUsageAny.
- //
- // Certificate chains are required to nest these extended key usage values.
- // (This matches the Windows CryptoAPI behavior, but not the spec.)
+ // Roots is the set of trusted root certificates the leaf certificate needs
+ // to chain up to. If nil, the system roots or the platform verifier are used.
+ Roots *CertPool
+
+ // CurrentTime is used to check the validity of all certificates in the
+ // chain. If zero, the current time is used.
+ CurrentTime time.Time
+
+ // KeyUsages specifies which Extended Key Usage values are acceptable. A
+ // chain is accepted if it allows any of the listed values. An empty list
+ // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny.
KeyUsages []ExtKeyUsage
+
// MaxConstraintComparisions is the maximum number of comparisons to
// perform when checking a given certificate's name constraints. If
// zero, a sensible default is used. This limit prevents pathological
// certificates from consuming excessive amounts of CPU time when
- // validating.
+ // validating. It does not apply to the platform verifier.
MaxConstraintComparisions int
}
@@ -717,8 +731,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// needed. If successful, it returns one or more chains where the first
// element of the chain is c and the last element is from opts.Roots.
//
-// If opts.Roots is nil and system roots are unavailable the returned error
-// will be of type SystemRootsError.
+// If opts.Roots is nil, the platform verifier might be used, and
+// verification details might differ from what is described below. If system
+// roots are unavailable the returned error will be of type SystemRootsError.
//
// Name constraints in the intermediates will be applied to all names claimed
// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
@@ -726,9 +741,16 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// the name being validated. Note that DirectoryName constraints are not
// supported.
//
-// Extended Key Usage values are enforced down a chain, so an intermediate or
-// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
-// list.
+// Name constraint validation follows the rules from RFC 5280, with the
+// addition that DNS name constraints may use the leading period format
+// defined for emails and URIs. When a constraint has a leading period
+// it indicates that at least one additional label must be prepended to
+// the constrained name to be considered valid.
+//
+// Extended Key Usage values are enforced nested down a chain, so an intermediate
+// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
+// list. (While this is not specified, it is common practice in order to limit
+// the types of certificates a CA can issue.)
//
// WARNING: this function doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
@@ -884,12 +906,16 @@ func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, curre
return
}
+func validHostnamePattern(host string) bool { return validHostname(host, true) }
+func validHostnameInput(host string) bool { return validHostname(host, false) }
+
// validHostname reports whether host is a valid hostname that can be matched or
// matched against according to RFC 6125 2.2, with some leniency to accommodate
// legacy values.
-func validHostname(host string) bool {
- host = strings.TrimSuffix(host, ".")
-
+func validHostname(host string, isPattern bool) bool {
+ if !isPattern {
+ host = strings.TrimSuffix(host, ".")
+ }
if len(host) == 0 {
return false
}
@@ -899,7 +925,7 @@ func validHostname(host string) bool {
// Empty label.
return false
}
- if i == 0 && part == "*" {
+ if isPattern && i == 0 && part == "*" {
// Only allow full left-most wildcards, as those are the only ones
// we match, and matching literal '*' characters is probably never
// the expected behavior.
@@ -918,8 +944,8 @@ func validHostname(host string) bool {
if c == '-' && j != 0 {
continue
}
- if c == '_' || c == ':' {
- // Not valid characters in hostnames, but commonly
+ if c == '_' {
+ // Not a valid character in hostnames, but commonly
// found in deployments outside the WebPKI.
continue
}
@@ -932,19 +958,26 @@ func validHostname(host string) bool {
// commonNameAsHostname reports whether the Common Name field should be
// considered the hostname that the certificate is valid for. This is a legacy
-// behavior, disabled if the Subject Alt Name extension is present.
+// behavior, disabled by default or if the Subject Alt Name extension is present.
//
// It applies the strict validHostname check to the Common Name field, so that
// certificates without SANs can still be validated against CAs with name
// constraints if there is no risk the CN would be matched as a hostname.
// See NameConstraintsWithoutSANs and issue 24151.
func (c *Certificate) commonNameAsHostname() bool {
- return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName)
+ return !ignoreCN && !c.hasSANExtension() && validHostnamePattern(c.Subject.CommonName)
+}
+
+func matchExactly(hostA, hostB string) bool {
+ if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
+ return false
+ }
+ return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
}
func matchHostnames(pattern, host string) bool {
- host = strings.TrimSuffix(host, ".")
- pattern = strings.TrimSuffix(pattern, ".")
+ pattern = toLowerCaseASCII(pattern)
+ host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
if len(pattern) == 0 || len(host) == 0 {
return false
@@ -1003,6 +1036,16 @@ func toLowerCaseASCII(in string) string {
// VerifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an error describing the mismatch.
+//
+// IP addresses can be optionally enclosed in square brackets and are checked
+// against the IPAddresses field. Other names are checked case insensitively
+// against the DNSNames field. If the names are valid hostnames, the certificate
+// fields can have a wildcard as the left-most label.
+//
+// The legacy Common Name field is ignored unless it's a valid hostname, the
+// certificate doesn't have any Subject Alternative Names, and the GODEBUG
+// environment variable is set to "x509ignoreCN=0". Support for Common Name is
+// deprecated will be entirely removed in the future.
func (c *Certificate) VerifyHostname(h string) error {
// IP addresses may be written in [ ].
candidateIP := h
@@ -1020,15 +1063,26 @@ func (c *Certificate) VerifyHostname(h string) error {
return HostnameError{c, candidateIP}
}
- lowered := toLowerCaseASCII(h)
-
+ names := c.DNSNames
if c.commonNameAsHostname() {
- if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
- return nil
- }
- } else {
- for _, match := range c.DNSNames {
- if matchHostnames(toLowerCaseASCII(match), lowered) {
+ names = []string{c.Subject.CommonName}
+ }
+
+ candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
+ validCandidateName := validHostnameInput(candidateName)
+
+ for _, match := range names {
+ // Ideally, we'd only match valid hostnames according to RFC 6125 like
+ // browsers (more or less) do, but in practice Go is used in a wider
+ // array of contexts and can't even assume DNS resolution. Instead,
+ // always allow perfect matches, and only apply wildcard and trailing
+ // dot processing to valid hostnames.
+ if validCandidateName && validHostnamePattern(match) {
+ if matchHostnames(match, candidateName) {
+ return nil
+ }
+ } else {
+ if matchExactly(match, candidateName) {
return nil
}
}