// 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.
type serverHandshakeState struct {
	c            *Conn
	ctx          context.Context
	clientHello  *clientHelloMsg
	hello        *serverHelloMsg
	suite        *cipherSuite
	ecdheOk      bool
	ecSignOk     bool
	rsaDecryptOk bool
	rsaSignOk    bool
	sessionState *sessionState
	finishedHash finishedHash
	masterSecret []byte
	cert         *Certificate
}

// serverHandshake performs a TLS handshake as a server.
func ( *Conn) ( context.Context) error {
	,  := .readClientHello()
	if  != nil {
		return 
	}

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

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

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

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

	// For an overview of TLS handshaking, see RFC 5246, Section 7.3.
	.buffering = true
	if .checkForResumption() {
		// 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 
		}
	} else {
		// 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) ( context.Context) (*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

	 := false
	// 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)
	 := .hello.random
	// 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
	}

	,  := negotiateALPN(.config.NextProtos, .clientHello.alpnProtocols)
	if  != nil {
		.sendAlert(alertNoApplicationProtocol)
		return 
	}
	.hello.alpnProtocol = 
	.clientProtocol = 

	.cert,  = .config.getCertificate(clientHelloInfo(.ctx, , .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)

	if .ecdheOk {
		// 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
}

// negotiateALPN picks a shared ALPN protocol that both sides support in server
// preference order. If ALPN is not configured or the peer doesn't support it,
// it returns "" and no error.
func negotiateALPN(,  []string) (string, error) {
	if len() == 0 || len() == 0 {
		return "", nil
	}
	var  bool
	for ,  := range  {
		for ,  := range  {
			if  ==  {
				return , nil
			}
			if  == "h2" &&  == "http/1.1" {
				 = true
			}
		}
	}
	// As a special case, let http/1.1 clients connect to h2 servers as if they
	// didn't support ALPN. We used not to enforce protocol overlap, so over
	// time a number of HTTP servers were configured with only "h2", but
	// expected to accept connections from "http/1.1" clients. See Issue 46310.
	if  {
		return "", nil
	}
	return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", )
}

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

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

	return  && 
}

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

	 := cipherSuitesPreferenceOrder
	if !hasAESGCMHardwareSupport || !aesgcmPreferred(.clientHello.cipherSuites) {
		 = cipherSuitesPreferenceOrderNoAES
	}

	 := .config.cipherSuites()
	 := make([]uint16, 0, len())
	for ,  := range  {
		for ,  := range  {
			if  ==  {
				 = append(, )
				break
			}
		}
	}

	.suite = selectCipherSuite(, .clientHello.cipherSuites, .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 {
		if  == TLS_FALLBACK_SCSV {
			// 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
	}

	 := 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
	.cipherSuite = .suite.id
	// We echo the client's session ID in the ServerHello to let it know
	// that we're doing a resumption.
	.hello.sessionId = .clientHello.sessionId
	.hello.ticketSupported = .sessionState.usedOldKey
	.finishedHash = newFinishedHash(.vers, .suite)
	.finishedHash.discardHandshakeBuffer()
	.finishedHash.Write(.clientHello.marshal())
	.finishedHash.Write(.hello.marshal())
	if ,  := .writeRecord(recordTypeHandshake, .hello.marshal());  != nil {
		return 
	}

	if  := .processCertsFromClient(Certificate{
		Certificate: .sessionState.certificates,
	});  != nil {
		return 
	}

	if .config.VerifyConnection != nil {
		if  := .config.VerifyConnection(.connectionStateLocked());  != nil {
			.sendAlert(alertBadCertificate)
			return 
		}
	}

	.masterSecret = .sessionState.masterSecret

	return nil
}

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

	if .clientHello.ocspStapling && len(.cert.OCSPStaple) > 0 {
		.hello.ocspStapling = true
	}

	.hello.ticketSupported = .clientHello.ticketSupported && !.config.SessionTicketsDisabled
	.hello.cipherSuite = .suite.id

	.finishedHash = newFinishedHash(.c.vers, .suite)
	if .config.ClientAuth == NoClientCert {
		// 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
	if .config.ClientAuth >= RequestClientCert {
		// Request a client certificate
		 = new(certificateRequestMsg)
		.certificateTypes = []byte{
			byte(certTypeRSASign),
			byte(certTypeECDSASign),
		}
		if .vers >= VersionTLS12 {
			.hasSignatureAlgorithm = true
			.supportedSignatureAlgorithms = supportedSignatureAlgorithms
		}

		// 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
}

func ( *serverHandshakeState) () error {
	// 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 .sessionState != nil {
		// 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 clientHelloInfo( context.Context,  *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,
		ctx:               ,
	}
}