// Copyright 2018 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 (
	
	
	
	
	
	
	
	
	
	
	
)

type clientHandshakeStateTLS13 struct {
	c            *Conn
	ctx          context.Context
	serverHello  *serverHelloMsg
	hello        *clientHelloMsg
	keyShareKeys *keySharePrivateKeys

	session     *SessionState
	earlySecret []byte
	binderKey   []byte

	certReq       *certificateRequestMsgTLS13
	usingPSK      bool
	sentDummyCCS  bool
	suite         *cipherSuiteTLS13
	transcript    hash.Hash
	masterSecret  []byte
	trafficSecret []byte // client_application_traffic_secret_0

	echContext *echContext
}

// handshake requires hs.c, hs.hello, hs.serverHello, hs.keyShareKeys, and,
// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
func ( *clientHandshakeStateTLS13) () error {
	 := .c

	if needFIPS() {
		return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
	}

	// The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
	// sections 4.1.2 and 4.1.3.
	if .handshakes > 0 {
		.sendAlert(alertProtocolVersion)
		return errors.New("tls: server selected TLS 1.3 in a renegotiation")
	}

	// Consistency check on the presence of a keyShare and its parameters.
	if .keyShareKeys == nil || .keyShareKeys.ecdhe == nil || len(.hello.keyShares) == 0 {
		return .sendAlert(alertInternalError)
	}

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

	.transcript = .suite.hash.New()

	if  := transcriptMsg(.hello, .transcript);  != nil {
		return 
	}

	if .echContext != nil {
		.echContext.innerTranscript = .suite.hash.New()
		if  := transcriptMsg(.echContext.innerHello, .echContext.innerTranscript);  != nil {
			return 
		}
	}

	if bytes.Equal(.serverHello.random, helloRetryRequestRandom) {
		if  := .sendDummyChangeCipherSpec();  != nil {
			return 
		}
		if  := .processHelloRetryRequest();  != nil {
			return 
		}
	}

	var  []byte
	if .echContext != nil {
		 := cloneHash(.echContext.innerTranscript, .suite.hash)
		.Write(.serverHello.original[:30])
		.Write(make([]byte, 8))
		.Write(.serverHello.original[38:])
		 := .suite.expandLabel(
			.suite.extract(.echContext.innerHello.random, nil),
			"ech accept confirmation",
			.Sum(nil),
			8,
		)
		if subtle.ConstantTimeCompare(, .serverHello.random[len(.serverHello.random)-8:]) == 1 {
			.hello = .echContext.innerHello
			.serverName = .config.ServerName
			.transcript = .echContext.innerTranscript
			.echAccepted = true

			if .serverHello.encryptedClientHello != nil {
				.sendAlert(alertUnsupportedExtension)
				return errors.New("tls: unexpected encrypted_client_hello extension in server hello despite ECH being accepted")
			}

			if .hello.serverName == "" && .serverHello.serverNameAck {
				.sendAlert(alertUnsupportedExtension)
				return errors.New("tls: unexpected server_name extension in server hello")
			}
		} else {
			.echContext.echRejected = true
			// If the server sent us retry configs, we'll return these to
			// the user so they can update their Config.
			 = .serverHello.encryptedClientHello
		}
	}

	if  := transcriptMsg(.serverHello, .transcript);  != nil {
		return 
	}

	.buffering = true
	if  := .processServerHello();  != nil {
		return 
	}
	if  := .sendDummyChangeCipherSpec();  != nil {
		return 
	}
	if  := .establishHandshakeKeys();  != nil {
		return 
	}
	if  := .readServerParameters();  != nil {
		return 
	}
	if  := .readServerCertificate();  != nil {
		return 
	}
	if  := .readServerFinished();  != nil {
		return 
	}
	if  := .sendClientCertificate();  != nil {
		return 
	}
	if  := .sendClientFinished();  != nil {
		return 
	}
	if ,  := .flush();  != nil {
		return 
	}

	if .echContext != nil && .echContext.echRejected {
		.sendAlert(alertECHRequired)
		return &ECHRejectionError{}
	}

	.isHandshakeComplete.Store(true)

	return nil
}

// checkServerHelloOrHRR does validity checks that apply to both ServerHello and
// HelloRetryRequest messages. It sets hs.suite.
func ( *clientHandshakeStateTLS13) () error {
	 := .c

	if .serverHello.supportedVersion == 0 {
		.sendAlert(alertMissingExtension)
		return errors.New("tls: server selected TLS 1.3 using the legacy version field")
	}

	if .serverHello.supportedVersion != VersionTLS13 {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
	}

	if .serverHello.vers != VersionTLS12 {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server sent an incorrect legacy version")
	}

	if .serverHello.ocspStapling ||
		.serverHello.ticketSupported ||
		.serverHello.extendedMasterSecret ||
		.serverHello.secureRenegotiationSupported ||
		len(.serverHello.secureRenegotiation) != 0 ||
		len(.serverHello.alpnProtocol) != 0 ||
		len(.serverHello.scts) != 0 {
		.sendAlert(alertUnsupportedExtension)
		return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
	}

	if !bytes.Equal(.hello.sessionId, .serverHello.sessionId) {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server did not echo the legacy session ID")
	}

	if .serverHello.compressionMethod != compressionNone {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server selected unsupported compression format")
	}

	 := mutualCipherSuiteTLS13(.hello.cipherSuites, .serverHello.cipherSuite)
	if .suite != nil &&  != .suite {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
	}
	if  == nil {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server chose an unconfigured cipher suite")
	}
	.suite = 
	.cipherSuite = .suite.id

	return nil
}

// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
func ( *clientHandshakeStateTLS13) () error {
	if .c.quic != nil {
		return nil
	}
	if .sentDummyCCS {
		return nil
	}
	.sentDummyCCS = true

	return .c.writeChangeCipherRecord()
}

// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
// resends hs.hello, and reads the new ServerHello into hs.serverHello.
func ( *clientHandshakeStateTLS13) () error {
	 := .c

	// The first ClientHello gets double-hashed into the transcript upon a
	// HelloRetryRequest. (The idea is that the server might offload transcript
	// storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
	 := .transcript.Sum(nil)
	.transcript.Reset()
	.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
	.transcript.Write()
	if  := transcriptMsg(.serverHello, .transcript);  != nil {
		return 
	}

	var  bool
	 := .hello
	if .echContext != nil {
		 = .echContext.innerTranscript.Sum(nil)
		.echContext.innerTranscript.Reset()
		.echContext.innerTranscript.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
		.echContext.innerTranscript.Write()

		if .serverHello.encryptedClientHello != nil {
			if len(.serverHello.encryptedClientHello) != 8 {
				.c.sendAlert(alertDecodeError)
				return errors.New("tls: malformed encrypted client hello extension")
			}

			 := cloneHash(.echContext.innerTranscript, .suite.hash)
			 := make([]byte, len(.serverHello.original))
			copy(, .serverHello.original)
			 = bytes.Replace(, .serverHello.encryptedClientHello, make([]byte, 8), 1)
			.Write()
			 := .suite.expandLabel(
				.suite.extract(.echContext.innerHello.random, nil),
				"hrr ech accept confirmation",
				.Sum(nil),
				8,
			)
			if subtle.ConstantTimeCompare(, .serverHello.encryptedClientHello) == 1 {
				 = .echContext.innerHello
				.serverName = .config.ServerName
				 = true
				.echAccepted = true
			}
		}

		if  := transcriptMsg(.serverHello, .echContext.innerTranscript);  != nil {
			return 
		}
	} else if .serverHello.encryptedClientHello != nil {
		// Unsolicited ECH extension should be rejected
		.sendAlert(alertUnsupportedExtension)
		return errors.New("tls: unexpected ECH extension in serverHello")
	}

	// The only HelloRetryRequest extensions we support are key_share and
	// cookie, and clients must abort the handshake if the HRR would not result
	// in any change in the ClientHello.
	if .serverHello.selectedGroup == 0 && .serverHello.cookie == nil {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
	}

	if .serverHello.cookie != nil {
		.cookie = .serverHello.cookie
	}

	if .serverHello.serverShare.group != 0 {
		.sendAlert(alertDecodeError)
		return errors.New("tls: received malformed key_share extension")
	}

	// If the server sent a key_share extension selecting a group, ensure it's
	// a group we advertised but did not send a key share for, and send a key
	// share for it this time.
	if  := .serverHello.selectedGroup;  != 0 {
		if !slices.Contains(.supportedCurves, ) {
			.sendAlert(alertIllegalParameter)
			return errors.New("tls: server selected unsupported group")
		}
		if slices.ContainsFunc(.hello.keyShares, func( keyShare) bool {
			return .group == 
		}) {
			.sendAlert(alertIllegalParameter)
			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
		}
		// Note: we don't support selecting X25519Kyber768Draft00 in a HRR,
		// because we currently only support it at all when CurvePreferences is
		// empty, which will cause us to also send a key share for it.
		//
		// This will have to change once we support selecting hybrid KEMs
		// without sending key shares for them.
		if ,  := curveForCurveID(); ! {
			.sendAlert(alertInternalError)
			return errors.New("tls: CurvePreferences includes unsupported curve")
		}
		,  := generateECDHEKey(.config.rand(), )
		if  != nil {
			.sendAlert(alertInternalError)
			return 
		}
		.keyShareKeys = &keySharePrivateKeys{curveID: , ecdhe: }
		.keyShares = []keyShare{{group: , data: .PublicKey().Bytes()}}
	}

	if len(.pskIdentities) > 0 {
		 := cipherSuiteTLS13ByID(.session.cipherSuite)
		if  == nil {
			return .sendAlert(alertInternalError)
		}
		if .hash == .suite.hash {
			// Update binders and obfuscated_ticket_age.
			 := .config.time().Sub(time.Unix(int64(.session.createdAt), 0))
			.pskIdentities[0].obfuscatedTicketAge = uint32(/time.Millisecond) + .session.ageAdd

			 := .suite.hash.New()
			.Write([]byte{typeMessageHash, 0, 0, uint8(len())})
			.Write()
			if  := transcriptMsg(.serverHello, );  != nil {
				return 
			}

			if  := computeAndUpdatePSK(, .binderKey, , .suite.finishedHash);  != nil {
				return 
			}
		} else {
			// Server selected a cipher suite incompatible with the PSK.
			.pskIdentities = nil
			.pskBinders = nil
		}
	}

	if .earlyData {
		.earlyData = false
		.quicRejectedEarlyData()
	}

	if  {
		// Any extensions which have changed in hello, but are mirrored in the
		// outer hello and compressed, need to be copied to the outer hello, so
		// they can be properly decompressed by the server. For now, the only
		// extension which may have changed is keyShares.
		.hello.keyShares = .keyShares
		.echContext.innerHello = 
		if  := transcriptMsg(.echContext.innerHello, .echContext.innerTranscript);  != nil {
			return 
		}

		if  := computeAndUpdateOuterECHExtension(.hello, .echContext.innerHello, .echContext, false);  != nil {
			return 
		}
	} else {
		.hello = 
	}

	if ,  := .c.writeHandshakeRecord(.hello, .transcript);  != nil {
		return 
	}

	// serverHelloMsg is not included in the transcript
	,  := .readHandshake(nil)
	if  != nil {
		return 
	}

	,  := .(*serverHelloMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	.serverHello = 

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

	.didHRR = true
	return nil
}

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

	if bytes.Equal(.serverHello.random, helloRetryRequestRandom) {
		.sendAlert(alertUnexpectedMessage)
		return errors.New("tls: server sent two HelloRetryRequest messages")
	}

	if len(.serverHello.cookie) != 0 {
		.sendAlert(alertUnsupportedExtension)
		return errors.New("tls: server sent a cookie in a normal ServerHello")
	}

	if .serverHello.selectedGroup != 0 {
		.sendAlert(alertDecodeError)
		return errors.New("tls: malformed key_share extension")
	}

	if .serverHello.serverShare.group == 0 {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server did not send a key share")
	}
	if !slices.ContainsFunc(.hello.keyShares, func( keyShare) bool {
		return .group == .serverHello.serverShare.group
	}) {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server selected unsupported group")
	}

	if !.serverHello.selectedIdentityPresent {
		return nil
	}

	if int(.serverHello.selectedIdentity) >= len(.hello.pskIdentities) {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server selected an invalid PSK")
	}

	if len(.hello.pskIdentities) != 1 || .session == nil {
		return .sendAlert(alertInternalError)
	}
	 := cipherSuiteTLS13ByID(.session.cipherSuite)
	if  == nil {
		return .sendAlert(alertInternalError)
	}
	if .hash != .suite.hash {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: server selected an invalid PSK and cipher suite pair")
	}

	.usingPSK = true
	.didResume = true
	.peerCertificates = .session.peerCertificates
	.activeCertHandles = .session.activeCertHandles
	.verifiedChains = .session.verifiedChains
	.ocspResponse = .session.ocspResponse
	.scts = .session.scts
	return nil
}

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

	 := .serverHello.serverShare.data
	if .serverHello.serverShare.group == x25519Kyber768Draft00 {
		if len() != x25519PublicKeySize+mlkem768.CiphertextSize {
			.sendAlert(alertIllegalParameter)
			return errors.New("tls: invalid server key share")
		}
		 = .serverHello.serverShare.data[:x25519PublicKeySize]
	}
	,  := .keyShareKeys.ecdhe.Curve().NewPublicKey()
	if  != nil {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: invalid server key share")
	}
	,  := .keyShareKeys.ecdhe.ECDH()
	if  != nil {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: invalid server key share")
	}
	if .serverHello.serverShare.group == x25519Kyber768Draft00 {
		if .keyShareKeys.kyber == nil {
			return .sendAlert(alertInternalError)
		}
		 := .serverHello.serverShare.data[x25519PublicKeySize:]
		,  := kyberDecapsulate(.keyShareKeys.kyber, )
		if  != nil {
			.sendAlert(alertIllegalParameter)
			return errors.New("tls: invalid Kyber server key share")
		}
		 = append(, ...)
	}
	.curveID = .serverHello.serverShare.group

	 := .earlySecret
	if !.usingPSK {
		 = .suite.extract(nil, nil)
	}

	 := .suite.extract(,
		.suite.deriveSecret(, "derived", nil))

	 := .suite.deriveSecret(,
		clientHandshakeTrafficLabel, .transcript)
	.out.setTrafficSecret(.suite, QUICEncryptionLevelHandshake, )
	 := .suite.deriveSecret(,
		serverHandshakeTrafficLabel, .transcript)
	.in.setTrafficSecret(.suite, QUICEncryptionLevelHandshake, )

	if .quic != nil {
		if .hand.Len() != 0 {
			.sendAlert(alertUnexpectedMessage)
		}
		.quicSetWriteSecret(QUICEncryptionLevelHandshake, .suite.id, )
		.quicSetReadSecret(QUICEncryptionLevelHandshake, .suite.id, )
	}

	 = .config.writeKeyLog(keyLogLabelClientHandshake, .hello.random, )
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}
	 = .config.writeKeyLog(keyLogLabelServerHandshake, .hello.random, )
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}

	.masterSecret = .suite.extract(nil,
		.suite.deriveSecret(, "derived", nil))

	return nil
}

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

	,  := .readHandshake(.transcript)
	if  != nil {
		return 
	}

	,  := .(*encryptedExtensionsMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}

	if  := checkALPN(.hello.alpnProtocols, .alpnProtocol, .quic != nil);  != nil {
		// RFC 8446 specifies that no_application_protocol is sent by servers, but
		// does not specify how clients handle the selection of an incompatible protocol.
		// RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
		// in this case. Always sending no_application_protocol seems reasonable.
		.sendAlert(alertNoApplicationProtocol)
		return 
	}
	.clientProtocol = .alpnProtocol

	if .quic != nil {
		if .quicTransportParameters == nil {
			// RFC 9001 Section 8.2.
			.sendAlert(alertMissingExtension)
			return errors.New("tls: server did not send a quic_transport_parameters extension")
		}
		.quicSetTransportParameters(.quicTransportParameters)
	} else {
		if .quicTransportParameters != nil {
			.sendAlert(alertUnsupportedExtension)
			return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
		}
	}

	if !.hello.earlyData && .earlyData {
		.sendAlert(alertUnsupportedExtension)
		return errors.New("tls: server sent an unexpected early_data extension")
	}
	if .hello.earlyData && !.earlyData {
		.quicRejectedEarlyData()
	}
	if .earlyData {
		if .session.cipherSuite != .cipherSuite {
			.sendAlert(alertHandshakeFailure)
			return errors.New("tls: server accepted 0-RTT with the wrong cipher suite")
		}
		if .session.alpnProtocol != .clientProtocol {
			.sendAlert(alertHandshakeFailure)
			return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
		}
	}
	if .echContext != nil && !.echContext.echRejected && .echRetryConfigs != nil {
		.sendAlert(alertUnsupportedExtension)
		return errors.New("tls: server sent ECH retry configs after accepting ECH")
	}

	return nil
}

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

	// Either a PSK or a certificate is always used, but not both.
	// See RFC 8446, Section 4.1.1.
	if .usingPSK {
		// Make sure the connection is still being verified whether or not this
		// is a resumption. Resumptions currently don't reverify certificates so
		// they don't call verifyServerCertificate. See Issue 31641.
		if .config.VerifyConnection != nil {
			if  := .config.VerifyConnection(.connectionStateLocked());  != nil {
				.sendAlert(alertBadCertificate)
				return 
			}
		}
		return nil
	}

	,  := .readHandshake(.transcript)
	if  != nil {
		return 
	}

	,  := .(*certificateRequestMsgTLS13)
	if  {
		.certReq = 

		,  = .readHandshake(.transcript)
		if  != nil {
			return 
		}
	}

	,  := .(*certificateMsgTLS13)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	if len(.certificate.Certificate) == 0 {
		.sendAlert(alertDecodeError)
		return errors.New("tls: received empty certificates message")
	}

	.scts = .certificate.SignedCertificateTimestamps
	.ocspResponse = .certificate.OCSPStaple

	if  := .verifyServerCertificate(.certificate.Certificate);  != nil {
		return 
	}

	// 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(, )
	}

	// See RFC 8446, Section 4.4.3.
	if !isSupportedSignatureAlgorithm(.signatureAlgorithm, supportedSignatureAlgorithms()) {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: certificate used with invalid signature algorithm")
	}
	, ,  := typeAndHashFromSignatureScheme(.signatureAlgorithm)
	if  != nil {
		return .sendAlert(alertInternalError)
	}
	if  == signaturePKCS1v15 ||  == crypto.SHA1 {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: certificate used with invalid signature algorithm")
	}
	 := signedMessage(, serverSignatureContext, .transcript)
	if  := verifyHandshakeSignature(, .peerCertificates[0].PublicKey,
		, , .signature);  != nil {
		.sendAlert(alertDecryptError)
		return errors.New("tls: invalid signature by the server certificate: " + .Error())
	}

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

	return nil
}

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

	// 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(, )
	}

	 := .suite.finishedHash(.in.trafficSecret, .transcript)
	if !hmac.Equal(, .verifyData) {
		.sendAlert(alertDecryptError)
		return errors.New("tls: invalid server finished hash")
	}

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

	// Derive secrets that take context through the server Finished.

	.trafficSecret = .suite.deriveSecret(.masterSecret,
		clientApplicationTrafficLabel, .transcript)
	 := .suite.deriveSecret(.masterSecret,
		serverApplicationTrafficLabel, .transcript)
	.in.setTrafficSecret(.suite, QUICEncryptionLevelApplication, )

	 = .config.writeKeyLog(keyLogLabelClientTraffic, .hello.random, .trafficSecret)
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}
	 = .config.writeKeyLog(keyLogLabelServerTraffic, .hello.random, )
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}

	.ekm = .suite.exportKeyingMaterial(.masterSecret, .transcript)

	return nil
}

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

	if .certReq == nil {
		return nil
	}

	if .echContext != nil && .echContext.echRejected {
		if ,  := .c.writeHandshakeRecord(&certificateMsgTLS13{}, .transcript);  != nil {
			return 
		}
		return nil
	}

	,  := .getClientCertificate(&CertificateRequestInfo{
		AcceptableCAs:    .certReq.certificateAuthorities,
		SignatureSchemes: .certReq.supportedSignatureAlgorithms,
		Version:          .vers,
		ctx:              .ctx,
	})
	if  != nil {
		return 
	}

	 := new(certificateMsgTLS13)

	.certificate = *
	.scts = .certReq.scts && len(.SignedCertificateTimestamps) > 0
	.ocspStapling = .certReq.ocspStapling && len(.OCSPStaple) > 0

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

	// If we sent an empty certificate message, skip the CertificateVerify.
	if len(.Certificate) == 0 {
		return nil
	}

	 := new(certificateVerifyMsg)
	.hasSignatureAlgorithm = true

	.signatureAlgorithm,  = selectSignatureScheme(.vers, , .certReq.supportedSignatureAlgorithms)
	if  != nil {
		// getClientCertificate returned a certificate incompatible with the
		// CertificateRequestInfo supported signature algorithms.
		.sendAlert(alertHandshakeFailure)
		return 
	}

	, ,  := typeAndHashFromSignatureScheme(.signatureAlgorithm)
	if  != nil {
		return .sendAlert(alertInternalError)
	}

	 := signedMessage(, clientSignatureContext, .transcript)
	 := crypto.SignerOpts()
	if  == signatureRSAPSS {
		 = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: }
	}
	,  := .PrivateKey.(crypto.Signer).Sign(.config.rand(), , )
	if  != nil {
		.sendAlert(alertInternalError)
		return errors.New("tls: failed to sign handshake: " + .Error())
	}
	.signature = 

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

	return nil
}

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

	 := &finishedMsg{
		verifyData: .suite.finishedHash(.out.trafficSecret, .transcript),
	}

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

	.out.setTrafficSecret(.suite, QUICEncryptionLevelApplication, .trafficSecret)

	if !.config.SessionTicketsDisabled && .config.ClientSessionCache != nil {
		.resumptionSecret = .suite.deriveSecret(.masterSecret,
			resumptionLabel, .transcript)
	}

	if .quic != nil {
		if .hand.Len() != 0 {
			.sendAlert(alertUnexpectedMessage)
		}
		.quicSetWriteSecret(QUICEncryptionLevelApplication, .suite.id, .trafficSecret)
	}

	return nil
}

func ( *Conn) ( *newSessionTicketMsgTLS13) error {
	if !.isClient {
		.sendAlert(alertUnexpectedMessage)
		return errors.New("tls: received new session ticket from a client")
	}

	if .config.SessionTicketsDisabled || .config.ClientSessionCache == nil {
		return nil
	}

	// See RFC 8446, Section 4.6.1.
	if .lifetime == 0 {
		return nil
	}
	 := time.Duration(.lifetime) * time.Second
	if  > maxSessionTicketLifetime {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: received a session ticket with invalid lifetime")
	}

	// RFC 9001, Section 4.6.1
	if .quic != nil && .maxEarlyData != 0 && .maxEarlyData != 0xffffffff {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: invalid early data for QUIC connection")
	}

	 := cipherSuiteTLS13ByID(.cipherSuite)
	if  == nil || .resumptionSecret == nil {
		return .sendAlert(alertInternalError)
	}

	 := .expandLabel(.resumptionSecret, "resumption",
		.nonce, .hash.Size())

	 := .sessionState()
	.secret = 
	.useBy = uint64(.config.time().Add().Unix())
	.ageAdd = .ageAdd
	.EarlyData = .quic != nil && .maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1
	.ticket = .label
	if .quic != nil && .quic.enableSessionEvents {
		.quicStoreSession()
		return nil
	}
	 := &ClientSessionState{session: }
	if  := .clientSessionCacheKey();  != "" {
		.config.ClientSessionCache.Put(, )
	}

	return nil
}