diff options
Diffstat (limited to 'libgo/go/crypto/tls/common.go')
-rw-r--r-- | libgo/go/crypto/tls/common.go | 175 |
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 +} |