Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package tls

import (
	
	
	
	
	
	
	
	
	
	
	
	
)
serverHandshakeState contains details of a server handshake in progress. It's discarded once the handshake has completed.
serverHandshake performs a TLS handshake as a server.
func ( *Conn) () error {
	,  := .readClientHello()
	if  != nil {
		return 
	}

	if .vers == VersionTLS13 {
		 := serverHandshakeStateTLS13{
			c:           ,
			clientHello: ,
		}
		return .handshake()
	}

	 := serverHandshakeState{
		c:           ,
		clientHello: ,
	}
	return .handshake()
}

func ( *serverHandshakeState) () error {
	 := .c

	if  := .processClientHello();  != nil {
		return 
	}
For an overview of TLS handshaking, see RFC 5246, Section 7.3.
The client has included a session ticket and so we do an abbreviated handshake.
		.didResume = true
		if  := .doResumeHandshake();  != nil {
			return 
		}
		if  := .establishKeys();  != nil {
			return 
		}
		if  := .sendSessionTicket();  != nil {
			return 
		}
		if  := .sendFinished(.serverFinished[:]);  != nil {
			return 
		}
		if ,  := .flush();  != nil {
			return 
		}
		.clientFinishedIsFirst = false
		if  := .readFinished(nil);  != nil {
			return 
		}
The client didn't include a session ticket, or it wasn't valid so we do a full handshake.
		if  := .pickCipherSuite();  != nil {
			return 
		}
		if  := .doFullHandshake();  != nil {
			return 
		}
		if  := .establishKeys();  != nil {
			return 
		}
		if  := .readFinished(.clientFinished[:]);  != nil {
			return 
		}
		.clientFinishedIsFirst = true
		.buffering = true
		if  := .sendSessionTicket();  != nil {
			return 
		}
		if  := .sendFinished(nil);  != nil {
			return 
		}
		if ,  := .flush();  != nil {
			return 
		}
	}

	.ekm = ekmFromMasterSecret(.vers, .suite, .masterSecret, .clientHello.random, .hello.random)
	atomic.StoreUint32(&.handshakeStatus, 1)

	return nil
}
readClientHello reads a ClientHello message and selects the protocol version.
func ( *Conn) () (*clientHelloMsg, error) {
	,  := .readHandshake()
	if  != nil {
		return nil, 
	}
	,  := .(*clientHelloMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return nil, unexpectedMessageError(, )
	}

	var  *Config
	 := .config
	if .config.GetConfigForClient != nil {
		 := clientHelloInfo(, )
		if ,  = .config.GetConfigForClient();  != nil {
			.sendAlert(alertInternalError)
			return nil, 
		} else if  != nil {
			.config = 
		}
	}
	.ticketKeys = .ticketKeys()

	 := .supportedVersions
	if len(.supportedVersions) == 0 {
		 = supportedVersionsFromMax(.vers)
	}
	.vers,  = .config.mutualVersion()
	if ! {
		.sendAlert(alertProtocolVersion)
		return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", )
	}
	.haveVers = true
	.in.version = .vers
	.out.version = .vers

	return , nil
}

func ( *serverHandshakeState) () error {
	 := .c

	.hello = new(serverHelloMsg)
	.hello.vers = .vers

We only support null compression, so check that the client offered it.
	for ,  := range .clientHello.compressionMethods {
		if  == compressionNone {
			 = true
			break
		}
	}

	if ! {
		.sendAlert(alertHandshakeFailure)
		return errors.New("tls: client does not support uncompressed connections")
	}

	.hello.random = make([]byte, 32)
Downgrade protection canaries. See RFC 8446, Section 4.1.3.
	 := .config.maxSupportedVersion()
	if  >= VersionTLS12 && .vers <  || testingOnlyForceDowngradeCanary {
		if .vers == VersionTLS12 {
			copy([24:], downgradeCanaryTLS12)
		} else {
			copy([24:], downgradeCanaryTLS11)
		}
		 = [:24]
	}
	,  := io.ReadFull(.config.rand(), )
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}

	if len(.clientHello.secureRenegotiation) != 0 {
		.sendAlert(alertHandshakeFailure)
		return errors.New("tls: initial handshake had non-empty renegotiation extension")
	}

	.hello.secureRenegotiationSupported = .clientHello.secureRenegotiationSupported
	.hello.compressionMethod = compressionNone
	if len(.clientHello.serverName) > 0 {
		.serverName = .clientHello.serverName
	}

	if len(.clientHello.alpnProtocols) > 0 {
		if  := mutualProtocol(.clientHello.alpnProtocols, .config.NextProtos);  != "" {
			.hello.alpnProtocol = 
			.clientProtocol = 
		}
	}

	.cert,  = .config.getCertificate(clientHelloInfo(, .clientHello))
	if  != nil {
		if  == errNoCertificates {
			.sendAlert(alertUnrecognizedName)
		} else {
			.sendAlert(alertInternalError)
		}
		return 
	}
	if .clientHello.scts {
		.hello.scts = .cert.SignedCertificateTimestamps
	}

	.ecdheOk = supportsECDHE(.config, .clientHello.supportedCurves, .clientHello.supportedPoints)

Although omitting the ec_point_formats extension is permitted, some old OpenSSL version will refuse to handshake if not present. Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed point format. See golang.org/issue/31943.
		.hello.supportedPoints = []uint8{pointFormatUncompressed}
	}

	if ,  := .cert.PrivateKey.(crypto.Signer);  {
		switch .Public().(type) {
		case *ecdsa.PublicKey:
			.ecSignOk = true
		case ed25519.PublicKey:
			.ecSignOk = true
		case *rsa.PublicKey:
			.rsaSignOk = true
		default:
			.sendAlert(alertInternalError)
			return fmt.Errorf("tls: unsupported signing key type (%T)", .Public())
		}
	}
	if ,  := .cert.PrivateKey.(crypto.Decrypter);  {
		switch .Public().(type) {
		case *rsa.PublicKey:
			.rsaDecryptOk = true
		default:
			.sendAlert(alertInternalError)
			return fmt.Errorf("tls: unsupported decryption key type (%T)", .Public())
		}
	}

	return nil
}
supportsECDHE returns whether ECDHE key exchanges can be used with this pre-TLS 1.3 client.
func ( *Config,  []CurveID,  []uint8) bool {
	 := false
	for ,  := range  {
		if .supportsCurve() {
			 = true
			break
		}
	}

	 := false
	for ,  := range  {
		if  == pointFormatUncompressed {
			 = true
			break
		}
	}

	return  && 
}

func ( *serverHandshakeState) () error {
	 := .c

	var ,  []uint16
	if .config.PreferServerCipherSuites {
		 = .config.cipherSuites()
		 = .clientHello.cipherSuites
If the client does not seem to have hardware support for AES-GCM, and the application did not specify a cipher suite preference order, prefer other AEAD ciphers even if we prioritized AES-GCM ciphers by default.
		if .config.CipherSuites == nil && !aesgcmPreferred(.clientHello.cipherSuites) {
			 = deprioritizeAES()
		}
	} else {
		 = .clientHello.cipherSuites
		 = .config.cipherSuites()
If we don't have hardware support for AES-GCM, prefer other AEAD ciphers even if the client prioritized AES-GCM.
		if !hasAESGCMHardwareSupport {
			 = deprioritizeAES()
		}
	}

	.suite = selectCipherSuite(, , .cipherSuiteOk)
	if .suite == nil {
		.sendAlert(alertHandshakeFailure)
		return errors.New("tls: no cipher suite supported by both client and server")
	}
	.cipherSuite = .suite.id

	for ,  := range .clientHello.cipherSuites {
The client is doing a fallback connection. See RFC 7507.
			if .clientHello.vers < .config.maxSupportedVersion() {
				.sendAlert(alertInappropriateFallback)
				return errors.New("tls: client using inappropriate protocol fallback")
			}
			break
		}
	}

	return nil
}

func ( *serverHandshakeState) ( *cipherSuite) bool {
	if .flags&suiteECDHE != 0 {
		if !.ecdheOk {
			return false
		}
		if .flags&suiteECSign != 0 {
			if !.ecSignOk {
				return false
			}
		} else if !.rsaSignOk {
			return false
		}
	} else if !.rsaDecryptOk {
		return false
	}
	if .c.vers < VersionTLS12 && .flags&suiteTLS12 != 0 {
		return false
	}
	return true
}
checkForResumption reports whether we should perform resumption on this connection.
func ( *serverHandshakeState) () bool {
	 := .c

	if .config.SessionTicketsDisabled {
		return false
	}

	,  := .decryptTicket(.clientHello.sessionTicket)
	if  == nil {
		return false
	}
	.sessionState = &sessionState{usedOldKey: }
	 := .sessionState.unmarshal()
	if ! {
		return false
	}

	 := time.Unix(int64(.sessionState.createdAt), 0)
	if .config.time().Sub() > maxSessionTicketLifetime {
		return false
	}
Never resume a session for a different TLS version.
	if .vers != .sessionState.vers {
		return false
	}

Check that the client is still offering the ciphersuite in the session.
	for ,  := range .clientHello.cipherSuites {
		if  == .sessionState.cipherSuite {
			 = true
			break
		}
	}
	if ! {
		return false
	}
Check that we also support the ciphersuite from the session.
	.suite = selectCipherSuite([]uint16{.sessionState.cipherSuite},
		.config.cipherSuites(), .cipherSuiteOk)
	if .suite == nil {
		return false
	}

	 := len(.sessionState.certificates) != 0
	 := requiresClientCert(.config.ClientAuth)
	if  && ! {
		return false
	}
	if  && .config.ClientAuth == NoClientCert {
		return false
	}

	return true
}

func ( *serverHandshakeState) () error {
	 := .c

	.hello.cipherSuite = .suite.id
We echo the client's session ID in the ServerHello to let it know that we're doing a resumption.
No need to keep a full record of the handshake if client certificates won't be used.
		.finishedHash.discardHandshakeBuffer()
	}
	.finishedHash.Write(.clientHello.marshal())
	.finishedHash.Write(.hello.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .hello.marshal());  != nil {
		return 
	}

	 := new(certificateMsg)
	.certificates = .cert.Certificate
	.finishedHash.Write(.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
		return 
	}

	if .hello.ocspStapling {
		 := new(certificateStatusMsg)
		.response = .cert.OCSPStaple
		.finishedHash.Write(.marshal())
		if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
			return 
		}
	}

	 := .suite.ka(.vers)
	,  := .generateServerKeyExchange(.config, .cert, .clientHello, .hello)
	if  != nil {
		.sendAlert(alertHandshakeFailure)
		return 
	}
	if  != nil {
		.finishedHash.Write(.marshal())
		if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
			return 
		}
	}

	var  *certificateRequestMsg
An empty list of certificateAuthorities signals to the client that it may send any certificate in response 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 {
			.certificateAuthorities = .config.ClientCAs.Subjects()
		}
		.finishedHash.Write(.marshal())
		if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
			return 
		}
	}

	 := new(serverHelloDoneMsg)
	.finishedHash.Write(.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
		return 
	}

	if ,  := .flush();  != nil {
		return 
	}

	var  crypto.PublicKey // public key for client auth, if any

	,  := .readHandshake()
	if  != nil {
		return 
	}
If we requested a client certificate, then the client must send a certificate message, even if it's empty.
	if .config.ClientAuth >= RequestClientCert {
		,  := .(*certificateMsg)
		if ! {
			.sendAlert(alertUnexpectedMessage)
			return unexpectedMessageError(, )
		}
		.finishedHash.Write(.marshal())

		if  := .processCertsFromClient(Certificate{
			Certificate: .certificates,
		});  != nil {
			return 
		}
		if len(.certificates) != 0 {
			 = .peerCertificates[0].PublicKey
		}

		,  = .readHandshake()
		if  != nil {
			return 
		}
	}
	if .config.VerifyConnection != nil {
		if  := .config.VerifyConnection(.connectionStateLocked());  != nil {
			.sendAlert(alertBadCertificate)
			return 
		}
	}
Get client key exchange
	,  := .(*clientKeyExchangeMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	.finishedHash.Write(.marshal())

	,  := .processClientKeyExchange(.config, .cert, , .vers)
	if  != nil {
		.sendAlert(alertHandshakeFailure)
		return 
	}
	.masterSecret = masterFromPreMasterSecret(.vers, .suite, , .clientHello.random, .hello.random)
	if  := .config.writeKeyLog(keyLogLabelTLS12, .clientHello.random, .masterSecret);  != nil {
		.sendAlert(alertInternalError)
		return 
	}
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 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.
	if len(.peerCertificates) > 0 {
		,  = .readHandshake()
		if  != nil {
			return 
		}
		,  := .(*certificateVerifyMsg)
		if ! {
			.sendAlert(alertUnexpectedMessage)
			return unexpectedMessageError(, )
		}

		var  uint8
		var  crypto.Hash
		if .vers >= VersionTLS12 {
			if !isSupportedSignatureAlgorithm(.signatureAlgorithm, .supportedSignatureAlgorithms) {
				.sendAlert(alertIllegalParameter)
				return errors.New("tls: client certificate used with invalid signature algorithm")
			}
			, ,  = typeAndHashFromSignatureScheme(.signatureAlgorithm)
			if  != nil {
				return .sendAlert(alertInternalError)
			}
		} else {
			, ,  = legacyTypeAndHashFromPublicKey()
			if  != nil {
				.sendAlert(alertIllegalParameter)
				return 
			}
		}

		 := .finishedHash.hashForClientCertificate(, , .masterSecret)
		if  := verifyHandshakeSignature(, , , , .signature);  != nil {
			.sendAlert(alertDecryptError)
			return errors.New("tls: invalid signature by the client certificate: " + .Error())
		}

		.finishedHash.Write(.marshal())
	}

	.finishedHash.discardHandshakeBuffer()

	return nil
}

func ( *serverHandshakeState) () error {
	 := .c

	, , , , ,  :=
		keysFromMasterSecret(.vers, .suite, .masterSecret, .clientHello.random, .hello.random, .suite.macLen, .suite.keyLen, .suite.ivLen)

	var ,  interface{}
	var ,  hash.Hash

	if .suite.aead == nil {
		 = .suite.cipher(, , true /* for reading */)
		 = .suite.mac()
		 = .suite.cipher(, , false /* not for reading */)
		 = .suite.mac()
	} else {
		 = .suite.aead(, )
		 = .suite.aead(, )
	}

	.in.prepareCipherSpec(.vers, , )
	.out.prepareCipherSpec(.vers, , )

	return nil
}

func ( *serverHandshakeState) ( []byte) error {
	 := .c

	if  := .readChangeCipherSpec();  != nil {
		return 
	}

	,  := .readHandshake()
	if  != nil {
		return 
	}
	,  := .(*finishedMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}

	 := .finishedHash.clientSum(.masterSecret)
	if len() != len(.verifyData) ||
		subtle.ConstantTimeCompare(, .verifyData) != 1 {
		.sendAlert(alertHandshakeFailure)
		return errors.New("tls: client's Finished message is incorrect")
	}

	.finishedHash.Write(.marshal())
	copy(, )
	return nil
}

ticketSupported is set in a resumption handshake if the ticket from the client was encrypted with an old session ticket key and thus a refreshed ticket should be sent.
	if !.hello.ticketSupported {
		return nil
	}

	 := .c
	 := new(newSessionTicketMsg)

	 := uint64(.config.time().Unix())
If this is re-wrapping an old key, then keep the original time it was created.
		 = .sessionState.createdAt
	}

	var  [][]byte
	for ,  := range .peerCertificates {
		 = append(, .Raw)
	}
	 := sessionState{
		vers:         .vers,
		cipherSuite:  .suite.id,
		createdAt:    ,
		masterSecret: .masterSecret,
		certificates: ,
	}
	var  error
	.ticket,  = .encryptTicket(.marshal())
	if  != nil {
		return 
	}

	.finishedHash.Write(.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
		return 
	}

	return nil
}

func ( *serverHandshakeState) ( []byte) error {
	 := .c

	if ,  := .writeRecord(recordTypeChangeCipherSpec, []byte{1});  != nil {
		return 
	}

	 := new(finishedMsg)
	.verifyData = .finishedHash.serverSum(.masterSecret)
	.finishedHash.Write(.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
		return 
	}

	copy(, .verifyData)

	return nil
}
processCertsFromClient takes a chain of client certificates either from a Certificates message or from a sessionState and verifies them. It returns the public key of the leaf certificate.
func ( *Conn) ( Certificate) error {
	 := .Certificate
	 := make([]*x509.Certificate, len())
	var  error
	for ,  := range  {
		if [],  = x509.ParseCertificate();  != nil {
			.sendAlert(alertBadCertificate)
			return errors.New("tls: failed to parse client certificate: " + .Error())
		}
	}

	if len() == 0 && requiresClientCert(.config.ClientAuth) {
		.sendAlert(alertBadCertificate)
		return errors.New("tls: client didn't provide a certificate")
	}

	if .config.ClientAuth >= VerifyClientCertIfGiven && len() > 0 {
		 := x509.VerifyOptions{
			Roots:         .config.ClientCAs,
			CurrentTime:   .config.time(),
			Intermediates: x509.NewCertPool(),
			KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
		}

		for ,  := range [1:] {
			.Intermediates.AddCert()
		}

		,  := [0].Verify()
		if  != nil {
			.sendAlert(alertBadCertificate)
			return errors.New("tls: failed to verify client certificate: " + .Error())
		}

		.verifiedChains = 
	}

	.peerCertificates = 
	.ocspResponse = .OCSPStaple
	.scts = .SignedCertificateTimestamps

	if len() > 0 {
		switch [0].PublicKey.(type) {
		case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
		default:
			.sendAlert(alertUnsupportedCertificate)
			return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", [0].PublicKey)
		}
	}

	if .config.VerifyPeerCertificate != nil {
		if  := .config.VerifyPeerCertificate(, .verifiedChains);  != nil {
			.sendAlert(alertBadCertificate)
			return 
		}
	}

	return nil
}

func ( *Conn,  *clientHelloMsg) *ClientHelloInfo {
	 := .supportedVersions
	if len(.supportedVersions) == 0 {
		 = supportedVersionsFromMax(.vers)
	}

	return &ClientHelloInfo{
		CipherSuites:      .cipherSuites,
		ServerName:        .serverName,
		SupportedCurves:   .supportedCurves,
		SupportedPoints:   .supportedPoints,
		SignatureSchemes:  .supportedSignatureAlgorithms,
		SupportedProtos:   .alpnProtocols,
		SupportedVersions: ,
		Conn:              .conn,
		config:            .config,
	}