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