summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/tls/handshake_server.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/tls/handshake_server.go')
-rw-r--r--libgo/go/crypto/tls/handshake_server.go246
1 files changed, 169 insertions, 77 deletions
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index e16cddcbd8..b786c3083a 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -19,28 +19,28 @@ import (
// serverHandshakeState contains details of a server handshake in progress.
// It's discarded once the handshake has completed.
type serverHandshakeState struct {
- c *Conn
- clientHello *clientHelloMsg
- hello *serverHelloMsg
- suite *cipherSuite
- ellipticOk bool
- ecdsaOk bool
- rsaDecryptOk bool
- rsaSignOk bool
- sessionState *sessionState
- finishedHash finishedHash
- masterSecret []byte
- certsFromClient [][]byte
- cert *Certificate
+ c *Conn
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ellipticOk bool
+ ecdsaOk bool
+ rsaDecryptOk bool
+ rsaSignOk bool
+ sessionState *sessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ certsFromClient [][]byte
+ cert *Certificate
+ cachedClientHelloInfo *ClientHelloInfo
}
// serverHandshake performs a TLS handshake as a server.
+// c.out.Mutex <= L; c.handshakeMutex <= L.
func (c *Conn) serverHandshake() error {
- config := c.config
-
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
- config.serverInitOnce.Do(config.serverInit)
+ c.config.serverInitOnce.Do(c.config.serverInit)
hs := serverHandshakeState{
c: c,
@@ -51,6 +51,7 @@ func (c *Conn) serverHandshake() error {
}
// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+ c.buffering = true
if isResume {
// The client has included a session ticket and so we do an abbreviated handshake.
if err := hs.doResumeHandshake(); err != nil {
@@ -67,9 +68,13 @@ func (c *Conn) serverHandshake() error {
return err
}
}
- if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+ if err := hs.sendFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
return err
}
+ c.clientFinishedIsFirst = false
if err := hs.readFinished(nil); err != nil {
return err
}
@@ -83,15 +88,20 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.readFinished(c.firstFinished[:]); err != nil {
+ if err := hs.readFinished(c.clientFinished[:]); err != nil {
return err
}
+ c.clientFinishedIsFirst = true
+ c.buffering = true
if err := hs.sendSessionTicket(); err != nil {
return err
}
if err := hs.sendFinished(nil); err != nil {
return err
}
+ if _, err := c.flush(); err != nil {
+ return err
+ }
}
c.handshakeComplete = true
@@ -101,7 +111,6 @@ func (c *Conn) serverHandshake() error {
// readClientHello reads a ClientHello message from the client and decides
// whether we will perform session resumption.
func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
- config := hs.c.config
c := hs.c
msg, err := c.readHandshake()
@@ -114,7 +123,22 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
c.sendAlert(alertUnexpectedMessage)
return false, unexpectedMessageError(hs.clientHello, msg)
}
- c.vers, ok = config.mutualVersion(hs.clientHello.vers)
+
+ if c.config.GetConfigForClient != nil {
+ if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
+ c.sendAlert(alertInternalError)
+ return false, err
+ } else if newConfig != nil {
+ newConfig.mutex.Lock()
+ newConfig.originalConfig = c.config
+ newConfig.mutex.Unlock()
+
+ newConfig.serverInitOnce.Do(newConfig.serverInit)
+ c.config = newConfig
+ }
+ }
+
+ c.vers, ok = c.config.mutualVersion(hs.clientHello.vers)
if !ok {
c.sendAlert(alertProtocolVersion)
return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
@@ -124,7 +148,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
hs.hello = new(serverHelloMsg)
supportedCurve := false
- preferredCurves := config.curvePreferences()
+ preferredCurves := c.config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
for _, supported := range preferredCurves {
@@ -160,12 +184,18 @@ Curves:
hs.hello.vers = c.vers
hs.hello.random = make([]byte, 32)
- _, err = io.ReadFull(config.rand(), hs.hello.random)
+ _, err = io.ReadFull(c.config.rand(), hs.hello.random)
if err != nil {
c.sendAlert(alertInternalError)
return false, err
}
- hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
@@ -179,20 +209,16 @@ Curves:
} else {
// Although sending an empty NPN extension is reasonable, Firefox has
// had a bug around this. Best to send nothing at all if
- // config.NextProtos is empty. See
+ // c.config.NextProtos is empty. See
// https://golang.org/issue/5445.
- if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+ if hs.clientHello.nextProtoNeg && len(c.config.NextProtos) > 0 {
hs.hello.nextProtoNeg = true
- hs.hello.nextProtos = config.NextProtos
+ hs.hello.nextProtos = c.config.NextProtos
}
}
- if hs.cert, err = config.getCertificate(&ClientHelloInfo{
- CipherSuites: hs.clientHello.cipherSuites,
- ServerName: hs.clientHello.serverName,
- SupportedCurves: hs.clientHello.supportedCurves,
- SupportedPoints: hs.clientHello.supportedPoints,
- }); err != nil {
+ hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
+ if err != nil {
c.sendAlert(alertInternalError)
return false, err
}
@@ -208,7 +234,7 @@ Curves:
hs.rsaSignOk = true
default:
c.sendAlert(alertInternalError)
- return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+ return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
}
}
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
@@ -217,7 +243,7 @@ Curves:
hs.rsaDecryptOk = true
default:
c.sendAlert(alertInternalError)
- return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+ return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
}
}
@@ -245,7 +271,7 @@ Curves:
return false, errors.New("tls: no cipher suite supported by both client and server")
}
- // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+ // See https://tools.ietf.org/html/rfc7507.
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
// The client is doing a fallback connection.
@@ -274,10 +300,8 @@ func (hs *serverHandshakeState) checkForResumption() bool {
return false
}
- if hs.sessionState.vers > hs.clientHello.vers {
- return false
- }
- if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+ // Never resume a session for a different TLS version.
+ if c.vers != hs.sessionState.vers {
return false
}
@@ -322,7 +346,9 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
hs.finishedHash.discardHandshakeBuffer()
hs.finishedHash.Write(hs.clientHello.marshal())
hs.finishedHash.Write(hs.hello.marshal())
- c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+ return err
+ }
if len(hs.sessionState.certificates) > 0 {
if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
@@ -336,51 +362,58 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
}
func (hs *serverHandshakeState) doFullHandshake() error {
- config := hs.c.config
c := hs.c
if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
hs.hello.ocspStapling = true
}
- hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
+ hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
- if config.ClientAuth == NoClientCert {
+ if c.config.ClientAuth == NoClientCert {
// No need to keep a full record of the handshake if client
// certificates won't be used.
hs.finishedHash.discardHandshakeBuffer()
}
hs.finishedHash.Write(hs.clientHello.marshal())
hs.finishedHash.Write(hs.hello.marshal())
- c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+ return err
+ }
certMsg := new(certificateMsg)
certMsg.certificates = hs.cert.Certificate
hs.finishedHash.Write(certMsg.marshal())
- c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+ return err
+ }
if hs.hello.ocspStapling {
certStatus := new(certificateStatusMsg)
certStatus.statusType = statusTypeOCSP
certStatus.response = hs.cert.OCSPStaple
hs.finishedHash.Write(certStatus.marshal())
- c.writeRecord(recordTypeHandshake, certStatus.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
+ return err
+ }
}
keyAgreement := hs.suite.ka(c.vers)
- skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
+ skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
if skx != nil {
hs.finishedHash.Write(skx.marshal())
- c.writeRecord(recordTypeHandshake, skx.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
+ return err
+ }
}
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := new(certificateRequestMsg)
certReq.certificateTypes = []byte{
@@ -397,16 +430,24 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// to our request. When we know the CAs we trust, then
// we can send them down, so that the client can choose
// an appropriate certificate to give to us.
- if config.ClientCAs != nil {
- certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
}
hs.finishedHash.Write(certReq.marshal())
- c.writeRecord(recordTypeHandshake, certReq.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+ return err
+ }
}
helloDone := new(serverHelloDoneMsg)
hs.finishedHash.Write(helloDone.marshal())
- c.writeRecord(recordTypeHandshake, helloDone.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
+ return err
+ }
+
+ if _, err := c.flush(); err != nil {
+ return err
+ }
var pub crypto.PublicKey // public key for client auth, if any
@@ -418,7 +459,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
var ok bool
// If we requested a client certificate, then the client must send a
// certificate message, even if it's empty.
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
@@ -427,7 +468,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if len(certMsg.certificates) == 0 {
// The client didn't actually send a certificate
- switch config.ClientAuth {
+ switch c.config.ClientAuth {
case RequireAnyClientCert, RequireAndVerifyClientCert:
c.sendAlert(alertBadCertificate)
return errors.New("tls: client didn't provide a certificate")
@@ -453,16 +494,20 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(ckx.marshal())
- preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ if err := c.config.writeKeyLog(hs.clientHello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
- // clientKeyExchangeMsg. This message is a digest of all preceding
+ // clientKeyExchangeMsg. This message is a digest of all preceding
// handshake-layer messages that is signed using the private key corresponding
// to the client's certificate. This allows us to verify that the client is in
// possession of the private key of the certificate.
@@ -499,7 +544,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
switch key := pub.(type) {
case *ecdsa.PublicKey:
if signatureAndHash.signature != signatureECDSA {
- err = errors.New("bad signature type for client's ECDSA certificate")
+ err = errors.New("tls: bad signature type for client's ECDSA certificate")
break
}
ecdsaSig := new(ecdsaSignature)
@@ -507,7 +552,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
break
}
if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- err = errors.New("ECDSA signature contained zero or negative values")
+ err = errors.New("tls: ECDSA signature contained zero or negative values")
break
}
var digest []byte
@@ -515,11 +560,11 @@ func (hs *serverHandshakeState) doFullHandshake() error {
break
}
if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
- err = errors.New("ECDSA verification failure")
+ err = errors.New("tls: ECDSA verification failure")
}
case *rsa.PublicKey:
if signatureAndHash.signature != signatureRSA {
- err = errors.New("bad signature type for client's RSA certificate")
+ err = errors.New("tls: bad signature type for client's RSA certificate")
break
}
var digest []byte
@@ -571,8 +616,8 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
- if err := c.in.error(); err != nil {
- return err
+ if c.in.err != nil {
+ return c.in.err
}
if hs.hello.nextProtoNeg {
@@ -632,7 +677,9 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
}
hs.finishedHash.Write(m.marshal())
- c.writeRecord(recordTypeHandshake, m.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+ return err
+ }
return nil
}
@@ -640,12 +687,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
func (hs *serverHandshakeState) sendFinished(out []byte) error {
c := hs.c
- c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+ if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+ return err
+ }
finished := new(finishedMsg)
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
hs.finishedHash.Write(finished.marshal())
- c.writeRecord(recordTypeHandshake, finished.marshal())
+ if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+ return err
+ }
c.cipherSuite = hs.suite.id
copy(out, finished.verifyData)
@@ -690,20 +741,27 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
c.verifiedChains = chains
}
- if len(certs) > 0 {
- var pub crypto.PublicKey
- switch key := certs[0].PublicKey.(type) {
- case *ecdsa.PublicKey, *rsa.PublicKey:
- pub = key
- default:
- c.sendAlert(alertUnsupportedCertificate)
- return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, err
}
- c.peerCertificates = certs
- return pub, nil
}
- return nil, nil
+ if len(certs) == 0 {
+ return nil, nil
+ }
+
+ var pub crypto.PublicKey
+ switch key := certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey:
+ pub = key
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ c.peerCertificates = certs
+ return pub, nil
}
// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
@@ -748,3 +806,37 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
}
return false
}
+
+// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
+var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
+
+func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
+ if hs.cachedClientHelloInfo != nil {
+ return hs.cachedClientHelloInfo
+ }
+
+ var supportedVersions []uint16
+ if hs.clientHello.vers > VersionTLS12 {
+ supportedVersions = suppVersArray[:]
+ } else if hs.clientHello.vers >= VersionSSL30 {
+ supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:]
+ }
+
+ signatureSchemes := make([]SignatureScheme, 0, len(hs.clientHello.signatureAndHashes))
+ for _, sah := range hs.clientHello.signatureAndHashes {
+ signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature))
+ }
+
+ hs.cachedClientHelloInfo = &ClientHelloInfo{
+ CipherSuites: hs.clientHello.cipherSuites,
+ ServerName: hs.clientHello.serverName,
+ SupportedCurves: hs.clientHello.supportedCurves,
+ SupportedPoints: hs.clientHello.supportedPoints,
+ SignatureSchemes: signatureSchemes,
+ SupportedProtos: hs.clientHello.alpnProtocols,
+ SupportedVersions: supportedVersions,
+ Conn: hs.c.conn,
+ }
+
+ return hs.cachedClientHelloInfo
+}