summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/tls/common.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/tls/common.go')
-rw-r--r--libgo/go/crypto/tls/common.go175
1 files changed, 133 insertions, 42 deletions
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index 776b70c93c8..a3d75d69cbf 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -8,7 +8,9 @@ import (
"container/list"
"crypto"
"crypto/rand"
+ "crypto/sha512"
"crypto/x509"
+ "errors"
"fmt"
"io"
"math/big"
@@ -30,7 +32,7 @@ const (
recordHeaderLen = 5 // record header length
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
- minVersion = VersionSSL30
+ minVersion = VersionTLS10
maxVersion = VersionTLS12
)
@@ -73,6 +75,7 @@ const (
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
+ extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
@@ -123,6 +126,7 @@ const (
const (
hashSHA1 uint8 = 2
hashSHA256 uint8 = 4
+ hashSHA384 uint8 = 5
)
// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
@@ -137,34 +141,31 @@ type signatureAndHash struct {
hash, signature uint8
}
-// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
-// that the code advertises as supported in a TLS 1.2 ClientHello.
-var supportedSKXSignatureAlgorithms = []signatureAndHash{
+// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2
+// CertificateRequest.
+var supportedSignatureAlgorithms = []signatureAndHash{
{hashSHA256, signatureRSA},
{hashSHA256, signatureECDSA},
+ {hashSHA384, signatureRSA},
+ {hashSHA384, signatureECDSA},
{hashSHA1, signatureRSA},
{hashSHA1, signatureECDSA},
}
-// supportedClientCertSignatureAlgorithms contains the signature and hash
-// algorithms that the code advertises as supported in a TLS 1.2
-// CertificateRequest.
-var supportedClientCertSignatureAlgorithms = []signatureAndHash{
- {hashSHA256, signatureRSA},
- {hashSHA256, signatureECDSA},
-}
-
// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
- Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
- HandshakeComplete bool // TLS handshake is complete
- DidResume bool // connection resumes a previous TLS connection
- CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
- NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos)
- NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server
- ServerName string // server name requested by client, if any (server side only)
- PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
- VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
+ Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
+ HandshakeComplete bool // TLS handshake is complete
+ DidResume bool // connection resumes a previous TLS connection
+ CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+ NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos)
+ NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server
+ ServerName string // server name requested by client, if any (server side only)
+ PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
+ VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
+ SignedCertificateTimestamps [][]byte // SCTs from the server, if any
+ OCSPResponse []byte // stapled OCSP response from server, if any
// TLSUnique contains the "tls-unique" channel binding value (see RFC
// 5929, section 3). For resumed sessions this value will be nil
@@ -190,11 +191,12 @@ const (
// ClientSessionState contains the state needed by clients to resume TLS
// sessions.
type ClientSessionState struct {
- sessionTicket []uint8 // Encrypted ticket used for session resumption with server
- vers uint16 // SSL/TLS version negotiated for the session
- cipherSuite uint16 // Ciphersuite negotiated for the session
- masterSecret []byte // MasterSecret generated by client on a full handshake
- serverCertificates []*x509.Certificate // Certificate chain presented by the server
+ sessionTicket []uint8 // Encrypted ticket used for session resumption with server
+ vers uint16 // SSL/TLS version negotiated for the session
+ cipherSuite uint16 // Ciphersuite negotiated for the session
+ masterSecret []byte // MasterSecret generated by client on a full handshake
+ serverCertificates []*x509.Certificate // Certificate chain presented by the server
+ verifiedChains [][]*x509.Certificate // Certificate chains we built for verification
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -265,10 +267,12 @@ type Config struct {
NameToCertificate map[string]*Certificate
// GetCertificate returns a Certificate based on the given
- // ClientHelloInfo. If GetCertificate is nil or returns nil, then the
- // certificate is retrieved from NameToCertificate. If
- // NameToCertificate is nil, the first element of Certificates will be
- // used.
+ // ClientHelloInfo. It will only be called if the client supplies SNI
+ // information or if Certificates is empty.
+ //
+ // If GetCertificate is nil or returns nil, then the certificate is
+ // retrieved from NameToCertificate. If NameToCertificate is nil, the
+ // first element of Certificates will be used.
GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
// RootCAs defines the set of root certificate authorities
@@ -330,7 +334,7 @@ type Config struct {
ClientSessionCache ClientSessionCache
// MinVersion contains the minimum SSL/TLS version that is acceptable.
- // If zero, then SSLv3 is taken as the minimum.
+ // If zero, then TLS 1.0 is taken as the minimum.
MinVersion uint16
// MaxVersion contains the maximum SSL/TLS version that is acceptable.
@@ -344,6 +348,38 @@ type Config struct {
CurvePreferences []CurveID
serverInitOnce sync.Once // guards calling (*Config).serverInit
+
+ // mutex protects sessionTicketKeys
+ mutex sync.RWMutex
+ // sessionTicketKeys contains zero or more ticket keys. If the length
+ // is zero, SessionTicketsDisabled must be true. The first key is used
+ // for new tickets and any subsequent keys can be used to decrypt old
+ // tickets.
+ sessionTicketKeys []ticketKey
+}
+
+// ticketKeyNameLen is the number of bytes of identifier that is prepended to
+// an encrypted session ticket in order to identify the key used to encrypt it.
+const ticketKeyNameLen = 16
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+ // keyName is an opaque byte string that serves to identify the session
+ // ticket key. It's exposed as plaintext in every session ticket.
+ keyName [ticketKeyNameLen]byte
+ aesKey [16]byte
+ hmacKey [16]byte
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+ hashed := sha512.Sum512(b[:])
+ copy(key.keyName[:], hashed[:ticketKeyNameLen])
+ copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+ copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+ return key
}
func (c *Config) serverInit() {
@@ -351,16 +387,51 @@ func (c *Config) serverInit() {
return
}
- // If the key has already been set then we have nothing to do.
+ alreadySet := false
for _, b := range c.SessionTicketKey {
if b != 0 {
+ alreadySet = true
+ break
+ }
+ }
+
+ if !alreadySet {
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ c.SessionTicketsDisabled = true
return
}
}
- if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
- c.SessionTicketsDisabled = true
+ c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+}
+
+func (c *Config) ticketKeys() []ticketKey {
+ c.mutex.RLock()
+ // c.sessionTicketKeys is constant once created. SetSessionTicketKeys
+ // will only update it by replacing it with a new value.
+ ret := c.sessionTicketKeys
+ c.mutex.RUnlock()
+ return ret
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server. The first
+// key will be used when creating new tickets, while all keys can be used for
+// decrypting tickets. It is safe to call this function while the server is
+// running in order to rotate the session ticket keys. The function will panic
+// if keys is empty.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+ if len(keys) == 0 {
+ panic("tls: keys must have at least one key")
}
+
+ newKeys := make([]ticketKey, len(keys))
+ for i, bytes := range keys {
+ newKeys[i] = ticketKeyFromBytes(bytes)
+ }
+
+ c.mutex.Lock()
+ c.sessionTicketKeys = newKeys
+ c.mutex.Unlock()
}
func (c *Config) rand() io.Reader {
@@ -428,13 +499,18 @@ func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
// getCertificate returns the best certificate for the given ClientHelloInfo,
// defaulting to the first element of c.Certificates.
func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
- if c.GetCertificate != nil {
+ if c.GetCertificate != nil &&
+ (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
cert, err := c.GetCertificate(clientHello)
if cert != nil || err != nil {
return cert, err
}
}
+ if len(c.Certificates) == 0 {
+ return nil, errors.New("crypto/tls: no certificates configured")
+ }
+
if len(c.Certificates) == 1 || c.NameToCertificate == nil {
// There's only one choice, so no point doing any work.
return &c.Certificates[0], nil
@@ -488,14 +564,17 @@ func (c *Config) BuildNameToCertificate() {
type Certificate struct {
Certificate [][]byte
// PrivateKey contains the private key corresponding to the public key
- // in Leaf. For a server, this must be a *rsa.PrivateKey or
- // *ecdsa.PrivateKey. For a client doing client authentication, this
- // can be any type that implements crypto.Signer (which includes RSA
- // and ECDSA private keys).
+ // in Leaf. For a server, this must implement crypto.Signer and/or
+ // crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
+ // (performing client authentication), this must be a crypto.Signer
+ // with an RSA or ECDSA PublicKey.
PrivateKey crypto.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte
+ // SignedCertificateTimestamps contains an optional list of Signed
+ // Certificate Timestamps which will be served to clients that request it.
+ SignedCertificateTimestamps [][]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
@@ -610,12 +689,24 @@ func defaultCipherSuites() []uint16 {
}
func initDefaultCipherSuites() {
- varDefaultCipherSuites = make([]uint16, len(cipherSuites))
- for i, suite := range cipherSuites {
- varDefaultCipherSuites[i] = suite.id
+ varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+ for _, suite := range cipherSuites {
+ if suite.flags&suiteDefaultOff != 0 {
+ continue
+ }
+ varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
}
}
func unexpectedMessageError(wanted, got interface{}) error {
return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
}
+
+func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool {
+ for _, s := range sigHashes {
+ if s == sigHash {
+ return true
+ }
+ }
+ return false
+}