// 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: ,
			echContext:  ,
		}
		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();  != nil {
		return 
	}
	if .sessionState != nil {
		// The client has included a session ticket and so we do an abbreviated handshake.
		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)
	.isHandshakeComplete.Store(true)

	return nil
}

// readClientHello reads a ClientHello message and selects the protocol version.
func ( *Conn) ( context.Context) (*clientHelloMsg, *echServerContext, error) {
	// clientHelloMsg is included in the transcript, but we haven't initialized
	// it yet. The respective handshake functions will record it themselves.
	,  := .readHandshake(nil)
	if  != nil {
		return nil, nil, 
	}
	,  := .(*clientHelloMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return nil, nil, unexpectedMessageError(, )
	}

	// ECH processing has to be done before we do any other negotiation based on
	// the contents of the client hello, since we may swap it out completely.
	var  *echServerContext
	if len(.encryptedClientHello) != 0 {
		, ,  = .processECHClientHello()
		if  != nil {
			return nil, nil, 
		}
	}

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

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

	// This check reflects some odd specification implied behavior. Client-facing servers
	// are supposed to reject hellos with outer ECH and inner ECH that offers 1.2, but
	// backend servers are allowed to accept hellos with inner ECH that offer 1.2, since
	// they cannot expect client-facing servers to behave properly. Since we act as both
	// a client-facing and backend server, we only enforce 1.3 being negotiated if we
	// saw a hello with outer ECH first. The spec probably should've made this an error,
	// but it didn't, and this matches the boringssl behavior.
	if .vers != VersionTLS13 && ( != nil && !.inner) {
		.sendAlert(alertIllegalParameter)
		return nil, nil, errors.New("tls: Encrypted Client Hello cannot be used pre-TLS 1.3")
	}

	if .config.MinVersion == 0 && .vers < VersionTLS12 {
		tls10server.Value() // ensure godebug is initialized
		tls10server.IncNonDefault()
	}

	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(roleServer)
	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.extendedMasterSecret = .clientHello.extendedMasterSecret
	.hello.secureRenegotiationSupported = .clientHello.secureRenegotiationSupported
	.hello.compressionMethod = compressionNone
	if len(.clientHello.serverName) > 0 {
		.serverName = .clientHello.serverName
	}

	,  := negotiateALPN(.config.NextProtos, .clientHello.alpnProtocols, false)
	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, .vers, .clientHello.supportedCurves, .clientHello.supportedPoints)

	if .ecdheOk && len(.clientHello.supportedPoints) > 0 {
		// 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,  bool) (string, error) {
	if len() == 0 || len() == 0 {
		if  && len() != 0 {
			// RFC 9001, Section 8.1
			return "", fmt.Errorf("tls: client did not request an application protocol")
		}
		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,  uint16,  []CurveID,  []uint8) bool {
	 := false
	for ,  := range  {
		if .supportsCurve(, ) {
			 = true
			break
		}
	}

	 := false
	for ,  := range  {
		if  == pointFormatUncompressed {
			 = true
			break
		}
	}
	// Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is
	// missing, uncompressed points are supported. If supportedPoints is empty,
	// the extension must be missing, as an empty extension body is rejected by
	// the parser. See https://go.dev/issue/49126.
	if len() == 0 {
		 = true
	}

	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

	if .config.CipherSuites == nil && !fips140tls.Required() && rsaKexCiphers[.suite.id] {
		tlsrsakex.Value() // ensure godebug is initialized
		tlsrsakex.IncNonDefault()
	}
	if .config.CipherSuites == nil && !fips140tls.Required() && tdesCiphers[.suite.id] {
		tls3des.Value() // ensure godebug is initialized
		tls3des.IncNonDefault()
	}

	for ,  := range .clientHello.cipherSuites {
		if  == TLS_FALLBACK_SCSV {
			// The client is doing a fallback connection. See RFC 7507.
			if .clientHello.vers < .config.maxSupportedVersion(roleServer) {
				.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) () error {
	 := .c

	if .config.SessionTicketsDisabled {
		return nil
	}

	var  *SessionState
	if .config.UnwrapSession != nil {
		,  := .config.UnwrapSession(.clientHello.sessionTicket, .connectionStateLocked())
		if  != nil {
			return 
		}
		if  == nil {
			return nil
		}
		 = 
	} else {
		 := .config.decryptTicket(.clientHello.sessionTicket, .ticketKeys)
		if  == nil {
			return nil
		}
		,  := ParseSessionState()
		if  != nil {
			return nil
		}
		 = 
	}

	// TLS 1.2 tickets don't natively have a lifetime, but we want to avoid
	// re-wrapping the same master secret in different tickets over and over for
	// too long, weakening forward secrecy.
	 := time.Unix(int64(.createdAt), 0)
	if .config.time().Sub() > maxSessionTicketLifetime {
		return nil
	}

	// Never resume a session for a different TLS version.
	if .vers != .version {
		return nil
	}

	 := false
	// Check that the client is still offering the ciphersuite in the session.
	for ,  := range .clientHello.cipherSuites {
		if  == .cipherSuite {
			 = true
			break
		}
	}
	if ! {
		return nil
	}

	// Check that we also support the ciphersuite from the session.
	 := selectCipherSuite([]uint16{.cipherSuite},
		.config.cipherSuites(), .cipherSuiteOk)
	if  == nil {
		return nil
	}

	 := len(.peerCertificates) != 0
	 := requiresClientCert(.config.ClientAuth)
	if  && ! {
		return nil
	}
	if  && .config.ClientAuth == NoClientCert {
		return nil
	}
	if  && .config.time().After(.peerCertificates[0].NotAfter) {
		return nil
	}
	if  && .config.ClientAuth >= VerifyClientCertIfGiven &&
		len(.verifiedChains) == 0 {
		return nil
	}

	// RFC 7627, Section 5.3
	if !.extMasterSecret && .clientHello.extendedMasterSecret {
		return nil
	}
	if .extMasterSecret && !.clientHello.extendedMasterSecret {
		// Aborting is somewhat harsh, but it's a MUST and it would indicate a
		// weird downgrade in client capabilities.
		return errors.New("tls: session supported extended_master_secret but client does not")
	}

	.peerCertificates = .peerCertificates
	.ocspResponse = .ocspResponse
	.scts = .scts
	.verifiedChains = .verifiedChains
	.extMasterSecret = .extMasterSecret
	.sessionState = 
	.suite = 
	.didResume = true
	return nil
}

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
	// We always send a new session ticket, even if it wraps the same master
	// secret and it's potentially encrypted with the same key, to help the
	// client avoid cross-connection tracking from a network observer.
	.hello.ticketSupported = true
	.finishedHash = newFinishedHash(.vers, .suite)
	.finishedHash.discardHandshakeBuffer()
	if  := transcriptMsg(.clientHello, &.finishedHash);  != nil {
		return 
	}
	if ,  := .c.writeHandshakeRecord(.hello, &.finishedHash);  != nil {
		return 
	}

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

	.masterSecret = .sessionState.secret

	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()
	}
	if  := transcriptMsg(.clientHello, &.finishedHash);  != nil {
		return 
	}
	if ,  := .c.writeHandshakeRecord(.hello, &.finishedHash);  != nil {
		return 
	}

	 := new(certificateMsg)
	.certificates = .cert.Certificate
	if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
		return 
	}

	if .hello.ocspStapling {
		 := new(certificateStatusMsg)
		.response = .cert.OCSPStaple
		if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
			return 
		}
	}

	 := .suite.ka(.vers)
	,  := .generateServerKeyExchange(.config, .cert, .clientHello, .hello)
	if  != nil {
		.sendAlert(alertHandshakeFailure)
		return 
	}
	if  != nil {
		if len(.key) >= 3 && .key[0] == 3 /* named curve */ {
			.curveID = CurveID(byteorder.BEUint16(.key[1:]))
		}
		if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != 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()
		}
		if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
			return 
		}
	}

	 := new(serverHelloDoneMsg)
	if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
		return 
	}

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

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

	,  := .readHandshake(&.finishedHash)
	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(, )
		}

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

		,  = .readHandshake(&.finishedHash)
		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(, )
	}

	,  := .processClientKeyExchange(.config, .cert, , .vers)
	if  != nil {
		.sendAlert(alertIllegalParameter)
		return 
	}
	if .hello.extendedMasterSecret {
		.extMasterSecret = true
		.masterSecret = extMasterFromPreMasterSecret(.vers, .suite, ,
			.finishedHash.Sum())
	} else {
		.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 {
		// certificateVerifyMsg is included in the transcript, but not until
		// after we verify the handshake signature, since the state before
		// this message was sent is used.
		,  = .readHandshake(nil)
		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(, )
		if  := verifyHandshakeSignature(, , , , .signature);  != nil {
			.sendAlert(alertDecryptError)
			return errors.New("tls: invalid signature by the client certificate: " + .Error())
		}

		if  := transcriptMsg(, &.finishedHash);  != nil {
			return 
		}
	}

	.finishedHash.discardHandshakeBuffer()

	return nil
}

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

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

	var ,  any
	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 
	}

	// finishedMsg is included in the transcript, but not until after we
	// check the client version, since the state before this message was
	// sent is used during verification.
	,  := .readHandshake(nil)
	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")
	}

	if  := transcriptMsg(, &.finishedHash);  != nil {
		return 
	}

	copy(, )
	return nil
}

func ( *serverHandshakeState) () error {
	if !.hello.ticketSupported {
		return nil
	}

	 := .c
	 := new(newSessionTicketMsg)

	 := .sessionState()
	.secret = .masterSecret
	if .sessionState != nil {
		// If this is re-wrapping an old key, then keep
		// the original time it was created.
		.createdAt = .sessionState.createdAt
	}
	if .config.WrapSession != nil {
		var  error
		.ticket,  = .config.WrapSession(.connectionStateLocked(), )
		if  != nil {
			return 
		}
	} else {
		,  := .Bytes()
		if  != nil {
			return 
		}
		.ticket,  = .config.encryptTicket(, .ticketKeys)
		if  != nil {
			return 
		}
	}

	if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
		return 
	}

	return nil
}

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

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

	 := new(finishedMsg)
	.verifyData = .finishedHash.serverSum(.masterSecret)
	if ,  := .c.writeHandshakeRecord(, &.finishedHash);  != nil {
		return 
	}

	copy(, .verifyData)

	return nil
}

// processCertsFromClient takes a chain of client certificates either from a
// Certificates message and verifies them.
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 [].PublicKeyAlgorithm == x509.RSA {
			 := [].PublicKey.(*rsa.PublicKey).N.BitLen()
			if ,  := checkKeySize(); ! {
				.sendAlert(alertBadCertificate)
				return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", )
			}
		}
	}

	if len() == 0 && requiresClientCert(.config.ClientAuth) {
		if .vers == VersionTLS13 {
			.sendAlert(alertCertificateRequired)
		} else {
			.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 {
			var  x509.CertificateInvalidError
			if errors.As(, &x509.UnknownAuthorityError{}) {
				.sendAlert(alertUnknownCA)
			} else if errors.As(, &) && .Reason == x509.Expired {
				.sendAlert(alertCertificateExpired)
			} else {
				.sendAlert(alertBadCertificate)
			}
			return &CertificateVerificationError{UnverifiedCertificates: , Err: }
		}

		.verifiedChains,  = fipsAllowedChains()
		if  != nil {
			.sendAlert(alertBadCertificate)
			return &CertificateVerificationError{UnverifiedCertificates: , Err: }
		}
	}

	.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: ,
		Extensions:        .extensions,
		Conn:              .conn,
		config:            .config,
		ctx:               ,
	}
}