mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/tls: add server side SNI support.
With this in place, a TLS server is capable of selecting the correct certificate based on the client's ServerNameIndication extension. The need to call Config.BuildNameToCertificate is unfortunate, but adding a sync.Once to the Config structure made it uncopyable and I felt that was too high a price to pay. Parsing the leaf certificates in each handshake was too inefficient to consider. R=bradfitz, rsc CC=golang-dev https://golang.org/cl/5151048
This commit is contained in:
parent
060ffabd18
commit
7e48cb5ffe
3 changed files with 126 additions and 1 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
"crypto/x509"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -101,6 +102,10 @@ type ConnectionState struct {
|
|||
NegotiatedProtocol string
|
||||
NegotiatedProtocolIsMutual bool
|
||||
|
||||
// ServerName contains the server name indicated by the client, if any.
|
||||
// (Only valid for server connections.)
|
||||
ServerName string
|
||||
|
||||
// the certificate chain that was presented by the other side
|
||||
PeerCertificates []*x509.Certificate
|
||||
// the verified certificate chains built from PeerCertificates.
|
||||
|
|
@ -124,6 +129,14 @@ type Config struct {
|
|||
// Server configurations must include at least one certificate.
|
||||
Certificates []Certificate
|
||||
|
||||
// NameToCertificate maps from a certificate name to an element of
|
||||
// Certificates. Note that a certificate name can be of the form
|
||||
// '*.example.com' and so doesn't have to be a domain name as such.
|
||||
// See Config.BuildNameToCertificate
|
||||
// The nil value causes the first element of Certificates to be used
|
||||
// for all connections.
|
||||
NameToCertificate map[string]*Certificate
|
||||
|
||||
// RootCAs defines the set of root certificate authorities
|
||||
// that clients use when verifying server certificates.
|
||||
// If RootCAs is nil, TLS uses the host's root CA set.
|
||||
|
|
@ -179,6 +192,59 @@ func (c *Config) cipherSuites() []uint16 {
|
|||
return s
|
||||
}
|
||||
|
||||
// getCertificateForName returns the best certificate for the given name,
|
||||
// defaulting to the first element of c.Certificates if there are no good
|
||||
// options.
|
||||
func (c *Config) getCertificateForName(name string) *Certificate {
|
||||
if len(c.Certificates) == 1 || c.NameToCertificate == nil {
|
||||
// There's only one choice, so no point doing any work.
|
||||
return &c.Certificates[0]
|
||||
}
|
||||
|
||||
name = strings.ToLower(name)
|
||||
for len(name) > 0 && name[len(name)-1] == '.' {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
|
||||
if cert, ok := c.NameToCertificate[name]; ok {
|
||||
return cert
|
||||
}
|
||||
|
||||
// try replacing labels in the name with wildcards until we get a
|
||||
// match.
|
||||
labels := strings.Split(name, ".")
|
||||
for i := range labels {
|
||||
labels[i] = "*"
|
||||
candidate := strings.Join(labels, ".")
|
||||
if cert, ok := c.NameToCertificate[candidate]; ok {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing matches, return the first certificate.
|
||||
return &c.Certificates[0]
|
||||
}
|
||||
|
||||
// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
|
||||
// from the CommonName and SubjectAlternateName fields of each of the leaf
|
||||
// certificates.
|
||||
func (c *Config) BuildNameToCertificate() {
|
||||
c.NameToCertificate = make(map[string]*Certificate)
|
||||
for i := range c.Certificates {
|
||||
cert := &c.Certificates[i]
|
||||
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(x509Cert.Subject.CommonName) > 0 {
|
||||
c.NameToCertificate[x509Cert.Subject.CommonName] = cert
|
||||
}
|
||||
for _, san := range x509Cert.DNSNames {
|
||||
c.NameToCertificate[san] = cert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A Certificate is a chain of one or more certificates, leaf first.
|
||||
type Certificate struct {
|
||||
Certificate [][]byte
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue