summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/tls/common.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/tls/common.go')
-rw-r--r--src/pkg/crypto/tls/common.go151
1 files changed, 111 insertions, 40 deletions
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index 8fb1a8848..25f7a920c 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -5,11 +5,11 @@
package tls
import (
+ "crypto"
"crypto/rand"
- "crypto/rsa"
"crypto/x509"
"io"
- "io/ioutil"
+ "strings"
"sync"
"time"
)
@@ -101,12 +101,28 @@ 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.
VerifiedChains [][]*x509.Certificate
}
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+ NoClientCert ClientAuthType = iota
+ RequestClientCert
+ RequireAnyClientCert
+ VerifyClientCertIfGiven
+ RequireAndVerifyClientCert
+)
+
// A Config structure is used to configure a TLS client or server. After one
// has been passed to a TLS function it must not be modified.
type Config struct {
@@ -116,14 +132,22 @@ type Config struct {
Rand io.Reader
// Time returns the current time as the number of seconds since the epoch.
- // If Time is nil, TLS uses the system time.Seconds.
- Time func() int64
+ // If Time is nil, TLS uses time.Now.
+ Time func() time.Time
// Certificates contains one or more certificate chains
// to present to the other side of the connection.
// 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.
@@ -136,11 +160,22 @@ type Config struct {
// hosting.
ServerName string
- // AuthenticateClient controls whether a server will request a certificate
- // from the client. It does not require that the client send a
- // certificate nor does it require that the certificate sent be
- // anything more than self-signed.
- AuthenticateClient bool
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // InsecureSkipVerify controls whether a client verifies the
+ // server's certificate chain and host name.
+ // If InsecureSkipVerify is true, TLS accepts any certificate
+ // presented by the server and any host name in that certificate.
+ // In this mode, TLS is susceptible to man-in-the-middle attacks.
+ // This should be used only for testing.
+ InsecureSkipVerify bool
// CipherSuites is a list of supported cipher suites. If CipherSuites
// is nil, TLS uses a list of suites supported by the implementation.
@@ -155,10 +190,10 @@ func (c *Config) rand() io.Reader {
return r
}
-func (c *Config) time() int64 {
+func (c *Config) time() time.Time {
t := c.Time
if t == nil {
- t = time.Seconds
+ t = time.Now
}
return t()
}
@@ -179,13 +214,71 @@ 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
- PrivateKey *rsa.PrivateKey
+ PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte
+ // Leaf is the parsed form of the leaf certificate, which may be
+ // initialized using x509.ParseCertificate to reduce per-handshake
+ // processing for TLS clients doing client authentication. If nil, the
+ // leaf certificate will be parsed as needed.
+ Leaf *x509.Certificate
}
// A TLS record.
@@ -218,15 +311,6 @@ func defaultConfig() *Config {
return &emptyConfig
}
-// Possible certificate files; stop after finding one.
-// On OS X we should really be using the Directory Services keychain
-// but that requires a lot of Mach goo to get at. Instead we use
-// the same root set that curl uses.
-var certFiles = []string{
- "/etc/ssl/certs/ca-certificates.crt", // Linux etc
- "/usr/share/curl/curl-ca-bundle.crt", // OS X
-}
-
var once sync.Once
func defaultRoots() *x509.CertPool {
@@ -244,27 +328,14 @@ func initDefaults() {
initDefaultCipherSuites()
}
-var varDefaultRoots *x509.CertPool
-
-func initDefaultRoots() {
- roots := x509.NewCertPool()
- for _, file := range certFiles {
- data, err := ioutil.ReadFile(file)
- if err == nil {
- roots.AppendCertsFromPEM(data)
- break
- }
- }
- varDefaultRoots = roots
-}
-
-var varDefaultCipherSuites []uint16
+var (
+ varDefaultRoots *x509.CertPool
+ varDefaultCipherSuites []uint16
+)
func initDefaultCipherSuites() {
varDefaultCipherSuites = make([]uint16, len(cipherSuites))
- i := 0
- for id := range cipherSuites {
- varDefaultCipherSuites[i] = id
- i++
+ for i, suite := range cipherSuites {
+ varDefaultCipherSuites[i] = suite.id
}
}