]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/crypto/x509/verify.go
crypto/x509: implement AddCertWithConstraint
[gostls13.git] / src / crypto / x509 / verify.go
index d47f8382ae2156bfa11c3dae3b2171ec54bba673..9d3c3246d3098dc474ed1f0b49db3ee316fe9b6c 100644 (file)
@@ -6,11 +6,12 @@ package x509
 
 import (
        "bytes"
+       "crypto"
+       "crypto/x509/pkix"
        "errors"
        "fmt"
        "net"
        "net/url"
-       "os"
        "reflect"
        "runtime"
        "strings"
@@ -18,9 +19,6 @@ import (
        "unicode/utf8"
 )
 
-// ignoreCN disables interpreting Common Name as a hostname. See issue 24151.
-var ignoreCN = !strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=0")
-
 type InvalidReason int
 
 const (
@@ -43,14 +41,7 @@ const (
        // NameMismatch results when the subject name of a parent certificate
        // does not match the issuer name in the child.
        NameMismatch
-       // NameConstraintsWithoutSANs results when a leaf certificate doesn't
-       // contain a Subject Alternative Name extension, but a CA certificate
-       // contains name constraints, and the Common Name can be interpreted as
-       // a hostname.
-       //
-       // 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 is a legacy error and is no longer returned.
        NameConstraintsWithoutSANs
        // UnconstrainedName results when a CA certificate contains permitted
        // name constraints, but leaf certificate contains a name of an
@@ -110,15 +101,7 @@ func (h HostnameError) Error() string {
        c := h.Certificate
 
        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"
-               }
+               return "x509: certificate relies on legacy Common Name field, use SANs instead"
        }
 
        var valid string
@@ -134,11 +117,7 @@ func (h HostnameError) Error() string {
                        valid += san.String()
                }
        } else {
-               if c.commonNameAsHostname() {
-                       valid = c.Subject.CommonName
-               } else {
-                       valid = strings.Join(c.DNSNames, ", ")
-               }
+               valid = strings.Join(c.DNSNames, ", ")
        }
 
        if len(valid) == 0 {
@@ -187,19 +166,16 @@ func (se SystemRootsError) Error() string {
        return msg
 }
 
+func (se SystemRootsError) Unwrap() error { return se.Err }
+
 // errNotParsed is returned when a certificate without ASN.1 contents is
 // 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.
 type VerifyOptions struct {
-       // IsBoring is a validity check for BoringCrypto.
-       // If not nil, it will be called to check whether a given certificate
-       // can be used for constructing verification chains.
-       IsBoring func(*Certificate) bool
-
        // DNSName, if set, is checked against the leaf certificate with
-       // Certificate.VerifyHostname.
+       // Certificate.VerifyHostname or the platform verifier.
        DNSName string
 
        // Intermediates is an optional pool of certificates that are not trust
@@ -214,20 +190,16 @@ type VerifyOptions struct {
        // chain. If zero, the current time is used.
        CurrentTime time.Time
 
-       // 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.)
+       // 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
 }
 
@@ -530,9 +502,9 @@ func (c *Certificate) checkNameConstraints(count *int,
        maxConstraintComparisons int,
        nameType string,
        name string,
-       parsedName interface{},
-       match func(parsedName, constraint interface{}) (match bool, err error),
-       permitted, excluded interface{}) error {
+       parsedName any,
+       match func(parsedName, constraint any) (match bool, err error),
+       permitted, excluded any) error {
 
        excludedValue := reflect.ValueOf(excluded)
 
@@ -619,88 +591,87 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
        }
        comparisonCount := 0
 
-       var leaf *Certificate
        if certType == intermediateCertificate || certType == rootCertificate {
                if len(currentChain) == 0 {
                        return errors.New("x509: internal error: empty chain when appending CA cert")
                }
-               leaf = currentChain[0]
-       }
-
-       checkNameConstraints := (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints()
-       if checkNameConstraints && leaf.commonNameAsHostname() {
-               // This is the deprecated, legacy case of depending on the commonName as
-               // a hostname. We don't enforce name constraints against the CN, but
-               // VerifyHostname will look for hostnames in there if there are no SANs.
-               // In order to ensure VerifyHostname will not accept an unchecked name,
-               // return an error here.
-               return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""}
-       } else if checkNameConstraints && leaf.hasSANExtension() {
-               err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error {
-                       switch tag {
-                       case nameTypeEmail:
-                               name := string(data)
-                               mailbox, ok := parseRFC2821Mailbox(name)
-                               if !ok {
-                                       return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
-                               }
-
-                               if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
-                                       func(parsedName, constraint interface{}) (bool, error) {
-                                               return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string))
-                                       }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
-                                       return err
-                               }
-
-                       case nameTypeDNS:
-                               name := string(data)
-                               if _, ok := domainToReverseLabels(name); !ok {
-                                       return fmt.Errorf("x509: cannot parse dnsName %q", name)
-                               }
-
-                               if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
-                                       func(parsedName, constraint interface{}) (bool, error) {
-                                               return matchDomainConstraint(parsedName.(string), constraint.(string))
-                                       }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
-                                       return err
-                               }
-
-                       case nameTypeURI:
-                               name := string(data)
-                               uri, err := url.Parse(name)
-                               if err != nil {
-                                       return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
-                               }
-
-                               if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
-                                       func(parsedName, constraint interface{}) (bool, error) {
-                                               return matchURIConstraint(parsedName.(*url.URL), constraint.(string))
-                                       }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
-                                       return err
-                               }
+       }
 
-                       case nameTypeIP:
-                               ip := net.IP(data)
-                               if l := len(ip); l != net.IPv4len && l != net.IPv6len {
-                                       return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
+       if (certType == intermediateCertificate || certType == rootCertificate) &&
+               c.hasNameConstraints() {
+               toCheck := []*Certificate{}
+               for _, c := range currentChain {
+                       if c.hasSANExtension() {
+                               toCheck = append(toCheck, c)
+                       }
+               }
+               for _, sanCert := range toCheck {
+                       err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error {
+                               switch tag {
+                               case nameTypeEmail:
+                                       name := string(data)
+                                       mailbox, ok := parseRFC2821Mailbox(name)
+                                       if !ok {
+                                               return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
+                                       }
+
+                                       if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
+                                               func(parsedName, constraint any) (bool, error) {
+                                                       return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string))
+                                               }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
+                                               return err
+                                       }
+
+                               case nameTypeDNS:
+                                       name := string(data)
+                                       if _, ok := domainToReverseLabels(name); !ok {
+                                               return fmt.Errorf("x509: cannot parse dnsName %q", name)
+                                       }
+
+                                       if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
+                                               func(parsedName, constraint any) (bool, error) {
+                                                       return matchDomainConstraint(parsedName.(string), constraint.(string))
+                                               }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
+                                               return err
+                                       }
+
+                               case nameTypeURI:
+                                       name := string(data)
+                                       uri, err := url.Parse(name)
+                                       if err != nil {
+                                               return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
+                                       }
+
+                                       if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
+                                               func(parsedName, constraint any) (bool, error) {
+                                                       return matchURIConstraint(parsedName.(*url.URL), constraint.(string))
+                                               }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
+                                               return err
+                                       }
+
+                               case nameTypeIP:
+                                       ip := net.IP(data)
+                                       if l := len(ip); l != net.IPv4len && l != net.IPv6len {
+                                               return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
+                                       }
+
+                                       if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
+                                               func(parsedName, constraint any) (bool, error) {
+                                                       return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
+                                               }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
+                                               return err
+                                       }
+
+                               default:
+                                       // Unknown SAN types are ignored.
                                }
 
-                               if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
-                                       func(parsedName, constraint interface{}) (bool, error) {
-                                               return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
-                                       }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
-                                       return err
-                               }
+                               return nil
+                       })
 
-                       default:
-                               // Unknown SAN types are ignored.
+                       if err != nil {
+                               return err
                        }
-
-                       return nil
-               })
-
-               if err != nil {
-                       return err
                }
        }
 
@@ -732,7 +703,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
                }
        }
 
-       if opts.IsBoring != nil && !opts.IsBoring(c) {
+       if !boringAllowCert(c) {
                // IncompatibleUsage is not quite right here,
                // but it's also the "no chains found" error
                // and is close enough.
@@ -747,8 +718,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
@@ -762,9 +734,15 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
 // 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 down a chain, so an intermediate or
-// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
-// list.
+// 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.)
+//
+// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported,
+// and will not be used to build chains.
+//
+// Certificates other than c in the returned chains should not be modified.
 //
 // WARNING: this function doesn't do any revocation checking.
 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
@@ -773,17 +751,33 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
        if len(c.Raw) == 0 {
                return nil, errNotParsed
        }
-       if opts.Intermediates != nil {
-               for _, intermediate := range opts.Intermediates.certs {
-                       if len(intermediate.Raw) == 0 {
-                               return nil, errNotParsed
-                       }
+       for i := 0; i < opts.Intermediates.len(); i++ {
+               c, _, err := opts.Intermediates.cert(i)
+               if err != nil {
+                       return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
+               }
+               if len(c.Raw) == 0 {
+                       return nil, errNotParsed
                }
        }
 
-       // Use Windows's own verification and chain building.
-       if opts.Roots == nil && runtime.GOOS == "windows" {
-               return c.systemVerify(&opts)
+       // Use platform verifiers, where available, if Roots is from SystemCertPool.
+       if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
+               // Don't use the system verifier if the system pool was replaced with a non-system pool,
+               // i.e. if SetFallbackRoots was called with x509usefallbackroots=1.
+               systemPool := systemRootsPool()
+               if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) {
+                       return c.systemVerify(&opts)
+               }
+               if opts.Roots != nil && opts.Roots.systemPool {
+                       platformChains, err := c.systemVerify(&opts)
+                       // If the platform verifier succeeded, or there are no additional
+                       // roots, return the platform verifier result. Otherwise, continue
+                       // with the Go verifier.
+                       if err == nil || opts.Roots.len() == 0 {
+                               return platformChains, err
+                       }
+               }
        }
 
        if opts.Roots == nil {
@@ -807,27 +801,29 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
 
        var candidateChains [][]*Certificate
        if opts.Roots.contains(c) {
-               candidateChains = append(candidateChains, []*Certificate{c})
+               candidateChains = [][]*Certificate{{c}}
        } else {
-               if candidateChains, err = c.buildChains(nil, []*Certificate{c}, nil, &opts); err != nil {
+               candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts)
+               if err != nil {
                        return nil, err
                }
        }
 
-       keyUsages := opts.KeyUsages
-       if len(keyUsages) == 0 {
-               keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+       if len(opts.KeyUsages) == 0 {
+               opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
        }
 
-       // If any key usage is acceptable then we're done.
-       for _, usage := range keyUsages {
-               if usage == ExtKeyUsageAny {
+       for _, eku := range opts.KeyUsages {
+               if eku == ExtKeyUsageAny {
+                       // If any key usage is acceptable, no need to check the chain for
+                       // key usages.
                        return candidateChains, nil
                }
        }
 
+       chains = make([][]*Certificate, 0, len(candidateChains))
        for _, candidate := range candidateChains {
-               if checkChainForKeyUsage(candidate, keyUsages) {
+               if checkChainForKeyUsage(candidate, opts.KeyUsages) {
                        chains = append(chains, candidate)
                }
        }
@@ -846,23 +842,65 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
        return n
 }
 
+// alreadyInChain checks whether a candidate certificate is present in a chain.
+// Rather than doing a direct byte for byte equivalency check, we check if the
+// subject, public key, and SAN, if present, are equal. This prevents loops that
+// are created by mutual cross-signatures, or other cross-signature bridge
+// oddities.
+func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
+       type pubKeyEqual interface {
+               Equal(crypto.PublicKey) bool
+       }
+
+       var candidateSAN *pkix.Extension
+       for _, ext := range candidate.Extensions {
+               if ext.Id.Equal(oidExtensionSubjectAltName) {
+                       candidateSAN = &ext
+                       break
+               }
+       }
+
+       for _, cert := range chain {
+               if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
+                       continue
+               }
+               if !candidate.PublicKey.(pubKeyEqual).Equal(cert.PublicKey) {
+                       continue
+               }
+               var certSAN *pkix.Extension
+               for _, ext := range cert.Extensions {
+                       if ext.Id.Equal(oidExtensionSubjectAltName) {
+                               certSAN = &ext
+                               break
+                       }
+               }
+               if candidateSAN == nil && certSAN == nil {
+                       return true
+               } else if candidateSAN == nil || certSAN == nil {
+                       return false
+               }
+               if bytes.Equal(candidateSAN.Value, certSAN.Value) {
+                       return true
+               }
+       }
+       return false
+}
+
 // maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
-// that an invocation of buildChains will (tranistively) make. Most chains are
+// that an invocation of buildChains will (transitively) make. Most chains are
 // less than 15 certificates long, so this leaves space for multiple chains and
 // for failed checks due to different intermediates having the same Subject.
 const maxChainSignatureChecks = 100
 
-func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
+func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
        var (
                hintErr  error
                hintCert *Certificate
        )
 
-       considerCandidate := func(certType int, candidate *Certificate) {
-               for _, cert := range currentChain {
-                       if cert.Equal(candidate) {
-                               return
-                       }
+       considerCandidate := func(certType int, candidate potentialParent) {
+               if alreadyInChain(candidate.cert, currentChain) {
+                       return
                }
 
                if sigChecks == nil {
@@ -874,40 +912,48 @@ func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, curre
                        return
                }
 
-               if err := c.CheckSignatureFrom(candidate); err != nil {
+               if err := c.CheckSignatureFrom(candidate.cert); err != nil {
                        if hintErr == nil {
                                hintErr = err
-                               hintCert = candidate
+                               hintCert = candidate.cert
                        }
                        return
                }
 
-               err = candidate.isValid(certType, currentChain, opts)
+               err = candidate.cert.isValid(certType, currentChain, opts)
                if err != nil {
+                       if hintErr == nil {
+                               hintErr = err
+                               hintCert = candidate.cert
+                       }
                        return
                }
 
+               if candidate.constraint != nil {
+                       if err := candidate.constraint(currentChain); err != nil {
+                               if hintErr == nil {
+                                       hintErr = err
+                                       hintCert = candidate.cert
+                               }
+                               return
+                       }
+               }
+
                switch certType {
                case rootCertificate:
-                       chains = append(chains, appendToFreshChain(currentChain, candidate))
+                       chains = append(chains, appendToFreshChain(currentChain, candidate.cert))
                case intermediateCertificate:
-                       if cache == nil {
-                               cache = make(map[*Certificate][][]*Certificate)
-                       }
-                       childChains, ok := cache[candidate]
-                       if !ok {
-                               childChains, err = candidate.buildChains(cache, appendToFreshChain(currentChain, candidate), sigChecks, opts)
-                               cache[candidate] = childChains
-                       }
+                       var childChains [][]*Certificate
+                       childChains, err = candidate.cert.buildChains(appendToFreshChain(currentChain, candidate.cert), sigChecks, opts)
                        chains = append(chains, childChains...)
                }
        }
 
-       for _, rootNum := range opts.Roots.findPotentialParents(c) {
-               considerCandidate(rootCertificate, opts.Roots.certs[rootNum])
+       for _, root := range opts.Roots.findPotentialParents(c) {
+               considerCandidate(rootCertificate, root)
        }
-       for _, intermediateNum := range opts.Intermediates.findPotentialParents(c) {
-               considerCandidate(intermediateCertificate, opts.Intermediates.certs[intermediateNum])
+       for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
+               considerCandidate(intermediateCertificate, intermediate)
        }
 
        if len(chains) > 0 {
@@ -970,18 +1016,6 @@ func validHostname(host string, isPattern bool) bool {
        return true
 }
 
-// commonNameAsHostname reports whether the Common Name field should be
-// considered the hostname that the certificate is valid for. This is a legacy
-// 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() && validHostnamePattern(c.Subject.CommonName)
-}
-
 func matchExactly(hostA, hostB string) bool {
        if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
                return false
@@ -1054,12 +1088,9 @@ func toLowerCaseASCII(in string) string {
 // 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.
+// fields can have a wildcard as the complete left-most label (e.g. *.example.com).
 //
-// 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.
+// Note that the legacy Common Name field is ignored.
 func (c *Certificate) VerifyHostname(h string) error {
        // IP addresses may be written in [ ].
        candidateIP := h
@@ -1077,15 +1108,10 @@ func (c *Certificate) VerifyHostname(h string) error {
                return HostnameError{c, candidateIP}
        }
 
-       names := c.DNSNames
-       if c.commonNameAsHostname() {
-               names = []string{c.Subject.CommonName}
-       }
-
        candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
        validCandidateName := validHostnameInput(candidateName)
 
-       for _, match := range names {
+       for _, match := range c.DNSNames {
                // 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,
@@ -1145,14 +1171,6 @@ NextCert:
                        for _, usage := range cert.ExtKeyUsage {
                                if requestedUsage == usage {
                                        continue NextRequestedUsage
-                               } else if requestedUsage == ExtKeyUsageServerAuth &&
-                                       (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
-                                               usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
-                                       // In order to support COMODO
-                                       // certificate chains, we have to
-                                       // accept Netscape or Microsoft SGC
-                                       // usages as equal to ServerAuth.
-                                       continue NextRequestedUsage
                                }
                        }