// Copyright 2017 Google Inc. 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 ClientHelloBuildStatus int

const NotBuilt ClientHelloBuildStatus = 0
const BuildByUtls ClientHelloBuildStatus = 1
const BuildByGoTLS ClientHelloBuildStatus = 2

type UConn struct {
	*Conn

	Extensions        []TLSExtension
	ClientHelloID     ClientHelloID
	sessionController *sessionController

	clientHelloBuildStatus ClientHelloBuildStatus
	clientHelloSpec        *ClientHelloSpec

	HandshakeState PubClientHandshakeState

	greaseSeed [ssl_grease_last_index]uint16

	omitSNIExtension bool

	// skipResumptionOnNilExtension is copied from `Config.PreferSkipResumptionOnNilExtension`.
	//
	// By default, if ClientHelloSpec is predefined or utls-generated (as opposed to HelloCustom), this flag will be updated to true.
	skipResumptionOnNilExtension bool

	// certCompressionAlgs represents the set of advertised certificate compression
	// algorithms, as specified in the ClientHello. This is only relevant client-side, for the
	// server certificate. All other forms of certificate compression are unsupported.
	certCompressionAlgs []CertCompressionAlgo

	// ech extension is a shortcut to the ECH extension in the Extensions slice if there is one.
	ech ECHExtension

	// echCtx is the echContex returned by makeClientHello()
	echCtx *echClientContext
}

// UClient returns a new uTLS client, with behavior depending on clientHelloID.
// Config CAN be nil, but make sure to eventually specify ServerName.
func ( net.Conn,  *Config,  ClientHelloID) *UConn {
	if  == nil {
		 = &Config{}
	}
	 := Conn{conn: , config: , isClient: true}
	 := PubClientHandshakeState{C: &, Hello: &PubClientHelloMsg{}}
	 := UConn{Conn: &, ClientHelloID: , HandshakeState: }
	.HandshakeState.uconn = &
	.handshakeFn = .clientHandshake
	.sessionController = newSessionController(&)
	.utls.sessionController = .sessionController
	.skipResumptionOnNilExtension = .PreferSkipResumptionOnNilExtension || .Client != helloCustom
	return &
}

// BuildHandshakeState behavior varies based on ClientHelloID and
// whether it was already called before.
// If HelloGolang:
//
//	[only once] make default ClientHello and overwrite existing state
//
// If any other mimicking ClientHelloID is used:
//
//	[only once] make ClientHello based on ID and overwrite existing state
//	[each call] apply uconn.Extensions config to internal crypto/tls structures
//	[each call] marshal ClientHello.
//
// BuildHandshakeState is automatically called before uTLS performs handshake,
// and should only be called explicitly to inspect/change fields of
// default/mimicked ClientHello.
// With the excpetion of session ticket and psk extensions, which cannot be changed
// after calling BuildHandshakeState, all other fields can be modified.
func ( *UConn) () error {
	return .buildHandshakeState(true)
}

// BuildHandshakeStateWithoutSession is the same as BuildHandshakeState, but does not
// set the session. This is only useful when you want to inspect the ClientHello before
// setting the session manually through SetSessionTicketExtension or SetPSKExtension.
// BuildHandshakeState is automatically called before uTLS performs handshake.
func ( *UConn) () error {
	return .buildHandshakeState(false)
}

func ( *UConn) ( bool) error {
	if .ClientHelloID == HelloGolang {
		if .clientHelloBuildStatus == BuildByGoTLS {
			return nil
		}
		uAssert(.clientHelloBuildStatus == NotBuilt, "BuildHandshakeState failed: invalid call, client hello has already been built by utls")

		// use default Golang ClientHello.
		, , ,  := .makeClientHello()
		if  != nil {
			return 
		}

		.HandshakeState.Hello = .getPublicPtr()
		.HandshakeState.State13.KeyShareKeys = .ToPublic()
		.HandshakeState.C = .Conn
		.echCtx = 
		.clientHelloBuildStatus = BuildByGoTLS
	} else {
		uAssert(.clientHelloBuildStatus == BuildByUtls || .clientHelloBuildStatus == NotBuilt, "BuildHandshakeState failed: invalid call, client hello has already been built by go-tls")
		if .clientHelloBuildStatus == NotBuilt {
			 := .applyPresetByID(.ClientHelloID)
			if  != nil {
				return 
			}
			if .omitSNIExtension {
				.removeSNIExtension()
			}
		}

		 := .ApplyConfig()
		if  != nil {
			return 
		}

		if  {
			 = .uLoadSession()
			if  != nil {
				return 
			}
		}

		 = .MarshalClientHello()
		if  != nil {
			return 
		}

		if  {
			.uApplyPatch()
			.sessionController.finalCheck()
			.clientHelloBuildStatus = BuildByUtls
		}

	}
	return nil
}

func ( *UConn) () error {
	if  := .config; .SessionTicketsDisabled || .ClientSessionCache == nil {
		return nil
	}
	switch .sessionController.shouldLoadSession() {
	case shouldReturn:
	case shouldSetTicket:
		.sessionController.setSessionTicketToUConn()
	case shouldSetPsk:
		.sessionController.setPskToUConn()
	case shouldLoad:
		 := .HandshakeState.Hello.getPrivatePtr()
		.sessionController.utlsAboutToLoadSession()
		, , ,  := .loadSession()
		if  == nil ||  != nil {
			return 
		}
		if .version == VersionTLS12 {
			// We use the session ticket extension for tls 1.2 session resumption
			.sessionController.initSessionTicketExt(, .sessionTicket)
			.sessionController.setSessionTicketToUConn()
		} else {
			.sessionController.initPskExt(, , , .pskIdentities)
		}
	}

	return nil
}

func ( *UConn) () {
	 := len(.HandshakeState.Hello.Raw)
	if .sessionController.shouldUpdateBinders() {
		.sessionController.updateBinders()
		.sessionController.setPskToUConn()
	}
	uAssert( == len(.HandshakeState.Hello.Raw), "tls: uApplyPatch Failed: the patch should never change the length of the marshaled clientHello")
}

func ( *UConn) () bool {
	return .didResume
}

// SetSessionState sets the session ticket, which may be preshared or fake.
// If session is nil, the body of session ticket extension will be unset,
// but the extension itself still MAY be present for mimicking purposes.
// Session tickets to be reused - use same cache on following connections.
//
// Deprecated: This method is deprecated in favor of SetSessionTicketExtension,
// as it only handles session override of TLS 1.2
func ( *UConn) ( *ClientSessionState) error {
	 := &SessionTicketExtension{Initialized: true}
	if  != nil {
		.Ticket = .session.ticket
		.Session = .session
	}
	return .SetSessionTicketExtension()
}

// SetSessionTicket sets the session ticket extension.
// If extension is nil, this will be a no-op.
func ( *UConn) ( ISessionTicketExtension) error {
	if .config.SessionTicketsDisabled || .config.ClientSessionCache == nil {
		return fmt.Errorf("tls: SetSessionTicketExtension failed: session is disabled")
	}
	if  == nil {
		return nil
	}
	return .sessionController.overrideSessionTicketExt()
}

// SetPskExtension sets the psk extension for tls 1.3 resumption. This is a no-op if the psk is nil.
func ( *UConn) ( PreSharedKeyExtension) error {
	if .config.SessionTicketsDisabled || .config.ClientSessionCache == nil {
		return fmt.Errorf("tls: SetPskExtension failed: session is disabled")
	}
	if  == nil {
		return nil
	}

	.HandshakeState.Hello.TicketSupported = true
	return .sessionController.overridePskExt()
}

// If you want session tickets to be reused - use same cache on following connections
func ( *UConn) ( ClientSessionCache) {
	.config.ClientSessionCache = 
	.HandshakeState.Hello.TicketSupported = true
}

// SetClientRandom sets client random explicitly.
// BuildHandshakeFirst() must be called before SetClientRandom.
// r must to be 32 bytes long.
func ( *UConn) ( []byte) error {
	if len() != 32 {
		return errors.New("Incorrect client random length! Expected: 32, got: " + strconv.Itoa(len()))
	} else {
		.HandshakeState.Hello.Random = make([]byte, 32)
		copy(.HandshakeState.Hello.Random, )
		return nil
	}
}

func ( *UConn) ( string) {
	 := hostnameInSNI()
	.config.ServerName = 
	for ,  := range .Extensions {
		,  := .(*SNIExtension)
		if  {
			.ServerName = 
		}
	}
}

// RemoveSNIExtension removes SNI from the list of extensions sent in ClientHello
// It returns an error when used with HelloGolang ClientHelloID
func ( *UConn) () error {
	if .ClientHelloID == HelloGolang {
		return fmt.Errorf("cannot call RemoveSNIExtension on a UConn with a HelloGolang ClientHelloID")
	}
	.omitSNIExtension = true
	return nil
}

func ( *UConn) () {
	 := make([]TLSExtension, 0, len(.Extensions))
	for ,  := range .Extensions {
		if ,  := .(*SNIExtension); ! {
			 = append(, )
		}
	}
	.Extensions = 
}

// Handshake runs the client handshake using given clientHandshakeState
// Requires hs.hello, and, optionally, hs.session to be set.
func ( *UConn) () error {
	return .HandshakeContext(context.Background())
}

// HandshakeContext runs the client or server handshake
// protocol if it has not yet been run.
//
// The provided Context must be non-nil. If the context is canceled before
// the handshake is complete, the handshake is interrupted and an error is returned.
// Once the handshake has completed, cancellation of the context will not affect the
// connection.
func ( *UConn) ( context.Context) error {
	// Delegate to unexported method for named return
	// without confusing documented signature.
	return .handshakeContext()
}

func ( *UConn) ( context.Context) ( error) {
	// Fast sync/atomic-based exit if there is no handshake in flight and the
	// last one succeeded without an error. Avoids the expensive context setup
	// and mutex for most Read and Write calls.
	if .isHandshakeComplete.Load() {
		return nil
	}

	,  := context.WithCancel()
	// Note: defer this before starting the "interrupter" goroutine
	// so that we can tell the difference between the input being canceled and
	// this cancellation. In the former case, we need to close the connection.
	defer ()

	// Start the "interrupter" goroutine, if this context might be canceled.
	// (The background context cannot).
	//
	// The interrupter goroutine waits for the input context to be done and
	// closes the connection if this happens before the function returns.
	if .quic != nil {
		.quic.cancelc = .Done()
		.quic.cancel = 
	} else if .Done() != nil {
		 := make(chan struct{})
		 := make(chan error, 1)
		defer func() {
			close()
			if  := <-;  != nil {
				// Return context error to user.
				 = 
			}
		}()
		go func() {
			select {
			case <-.Done():
				// Close the connection, discarding the error
				_ = .conn.Close()
				 <- .Err()
			case <-:
				 <- nil
			}
		}()
	}

	.handshakeMutex.Lock()
	defer .handshakeMutex.Unlock()

	if  := .handshakeErr;  != nil {
		return 
	}
	if .isHandshakeComplete.Load() {
		return nil
	}

	.in.Lock()
	defer .in.Unlock()

	// [uTLS section begins]
	if .isClient {
		 := .BuildHandshakeState()
		if  != nil {
			return 
		}
	}
	// [uTLS section ends]
	.handshakeErr = .handshakeFn()
	if .handshakeErr == nil {
		.handshakes++
	} else {
		// If an error occurred during the hadshake try to flush the
		// alert that might be left in the buffer.
		.flush()
	}

	if .handshakeErr == nil && !.isHandshakeComplete.Load() {
		.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
	}
	if .handshakeErr != nil && .isHandshakeComplete.Load() {
		panic("tls: internal error: handshake returned an error but is marked successful")
	}

	if .quic != nil {
		if .handshakeErr == nil {
			.quicHandshakeComplete()
			// Provide the 1-RTT read secret now that the handshake is complete.
			// The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
			// the handshake (RFC 9001, Section 5.7).
			.quicSetReadSecret(QUICEncryptionLevelApplication, .cipherSuite, .in.trafficSecret)
		} else {
			var  alert
			.out.Lock()
			if !errors.As(.out.err, &) {
				 = alertInternalError
			}
			.out.Unlock()
			// Return an error which wraps both the handshake error and
			// any alert error we may have sent, or alertInternalError
			// if we didn't send an alert.
			// Truncate the text of the alert to 0 characters.
			.handshakeErr = fmt.Errorf("%w%.0w", .handshakeErr, AlertError())
		}
		close(.quic.blockedc)
		close(.quic.signalc)
	}

	return .handshakeErr
}

// Copy-pasted from tls.Conn in its entirety. But c.Handshake() is now utls' one, not tls.
// Write writes data to the connection.
func ( *UConn) ( []byte) (int, error) {
	// interlock with Close below
	for {
		 := .activeCall.Load()
		if &1 != 0 {
			return 0, net.ErrClosed
		}
		if .activeCall.CompareAndSwap(, +2) {
			defer .activeCall.Add(-2)
			break
		}
	}

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

	.out.Lock()
	defer .out.Unlock()

	if  := .out.err;  != nil {
		return 0, 
	}

	if !.isHandshakeComplete.Load() {
		return 0, alertInternalError
	}

	if .closeNotifySent {
		return 0, errShutdown
	}

	// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
	// attack when using block mode ciphers due to predictable IVs.
	// This can be prevented by splitting each Application Data
	// record into two records, effectively randomizing the IV.
	//
	// https://www.openssl.org/~bodo/tls-cbc.txt
	// https://bugzilla.mozilla.org/show_bug.cgi?id=665814
	// https://www.imperialviolet.org/2012/01/15/beastfollowup.html

	var  int
	if len() > 1 && .vers <= VersionTLS10 {
		if ,  := .out.cipher.(cipher.BlockMode);  {
			,  := .writeRecordLocked(recordTypeApplicationData, [:1])
			if  != nil {
				return , .out.setErrorLocked()
			}
			,  = 1, [1:]
		}
	}

	,  := .writeRecordLocked(recordTypeApplicationData, )
	return  + , .out.setErrorLocked()
}

func ( *UConn) () error {
	for ,  := range .Extensions {
		 := .writeToUConn()
		if  != nil {
			return 
		}
	}
	return nil
}

func ( *UConn) () []uint16 {

	 := []uint16{}
	for ,  := range .Extensions {
		 := cryptobyte.String(make([]byte, 2000))
		.Read()
		var  uint16
		.ReadUint16(&)
		 = append(, )
	}
	return 
}

func ( *UConn) ( *clientHelloMsg,  *echClientContext,  bool) error {
	// This function is mostly copied from
	// https://github.com/refraction-networking/utls/blob/e430876b1d82fdf582efc57f3992d448e7ab3d8a/ech.go#L408
	var  []byte
	if  {
		 = .encapsulatedKey
	}

	,  := encodeInnerClientHelloReorderOuterExts(, int(.config.MaxNameLength), .extensionsList())
	if  != nil {
		return 
	}

	 := len() + 16
	,  := generateOuterECHExt(.config.ConfigID, .kdfID, .aeadID, , make([]byte, ))
	if  != nil {
		return 
	}

	 := slices.IndexFunc(.Extensions, func( TLSExtension) bool {
		,  := .(EncryptedClientHelloExtension)
		return 
	})
	if  < 0 {
		return fmt.Errorf("extension satisfying EncryptedClientHelloExtension not present")
	}
	 := .Extensions[]

	.Extensions[] = &GenericExtension{
		Id:   extensionEncryptedClientHello,
		Data: ,
	}

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

	 := .HandshakeState.Hello.Raw
	 = [4:]
	,  := .hpkeContext.Seal(, )
	if  != nil {
		return 
	}
	,  = generateOuterECHExt(.config.ConfigID, .kdfID, .aeadID, , )
	if  != nil {
		return 
	}
	.Extensions[] = &GenericExtension{
		Id:   extensionEncryptedClientHello,
		Data: ,
	}

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

	.Extensions[] = 
	return nil

}

func ( *UConn) () error {
	if len(.config.EncryptedClientHelloConfigList) > 0 {
		, , ,  := .makeClientHello()
		if  != nil {
			return 
		}

		// copy compressed extensions to the ClientHelloInner
		.keyShares = KeyShares(.HandshakeState.Hello.KeyShares).ToPrivate()
		.supportedSignatureAlgorithms = .HandshakeState.Hello.SupportedSignatureAlgorithms
		.sessionId = .HandshakeState.Hello.SessionId
		.supportedCurves = .HandshakeState.Hello.SupportedCurves

		.innerHello = 

		.computeAndUpdateOuterECHExtension(, , true)

		.echCtx = 
		return nil
	}

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

	return nil

}

// MarshalClientHelloNoECH marshals ClientHello as if there was no
// ECH extension present.
func ( *UConn) () error {
	 := .HandshakeState.Hello
	 := 2 + 32 + 1 + len(.SessionId) +
		2 + len(.CipherSuites)*2 +
		1 + len(.CompressionMethods)

	 := 0
	var  *UtlsPaddingExtension // reference to padding extension, if present
	for ,  := range .Extensions {
		if ,  := .(*UtlsPaddingExtension); ! {
			// If not padding - just add length of extension to total length
			 += .Len()
		} else {
			// If padding - process it later
			if  == nil {
				 = 
			} else {
				return errors.New("multiple padding extensions")
			}
		}
	}

	if  != nil {
		// determine padding extension presence and length
		.Update( + 4 +  + 2)
		 += .Len()
	}

	 := 
	if len(.Extensions) > 0 {
		 += 2 +  // 2 bytes for extensions' length
	}

	 := bytes.Buffer{}
	 := bufio.NewWriterSize(&, +4) // 1 byte for tls record type, 3 for length
	// We use buffered Writer to avoid checking write errors after every Write(): whenever first error happens
	// Write() will become noop, and error will be accessible via Flush(), which is called once in the end

	binary.Write(, binary.BigEndian, typeClientHello)
	 := []byte{byte( >> 16), byte( >> 8), byte()} // poor man's uint24
	binary.Write(, binary.BigEndian, )
	binary.Write(, binary.BigEndian, .Vers)

	binary.Write(, binary.BigEndian, .Random)

	binary.Write(, binary.BigEndian, uint8(len(.SessionId)))
	binary.Write(, binary.BigEndian, .SessionId)

	binary.Write(, binary.BigEndian, uint16(len(.CipherSuites)<<1))
	for ,  := range .CipherSuites {
		binary.Write(, binary.BigEndian, )
	}

	binary.Write(, binary.BigEndian, uint8(len(.CompressionMethods)))
	binary.Write(, binary.BigEndian, .CompressionMethods)

	if len(.Extensions) > 0 {
		binary.Write(, binary.BigEndian, uint16())
		for ,  := range .Extensions {
			if ,  := .ReadFrom();  != nil {
				return 
			}
		}
	}

	 := .Flush()
	if  != nil {
		return 
	}

	if .Len() != 4+ {
		return errors.New("utls: unexpected ClientHello length. Expected: " + strconv.Itoa(4+) +
			". Got: " + strconv.Itoa(.Len()))
	}

	.Raw = .Bytes()
	return nil
}

// get current state of cipher and encrypt zeros to get keystream
func ( *UConn) ( int) ([]byte, error) {
	 := make([]byte, )

	if ,  := .out.cipher.(cipher.AEAD);  {
		// AEAD.Seal() does not mutate internal state, other ciphers might
		return .Seal(nil, .out.seq[:], , nil), nil
	}
	return nil, errors.New("could not convert OutCipher to cipher.AEAD")
}

// SetTLSVers sets min and max TLS version in all appropriate places.
// Function will use first non-zero version parsed in following order:
//  1. Provided minTLSVers, maxTLSVers
//  2. specExtensions may have SupportedVersionsExtension
//  3. [default] min = TLS 1.0, max = TLS 1.2
//
// Error is only returned if things are in clearly undesirable state
// to help user fix them.
func ( *UConn) (,  uint16,  []TLSExtension) error {
	if  == 0 &&  == 0 {
		// if version is not set explicitly in the ClientHelloSpec, check the SupportedVersions extension
		 := 0
		for ,  := range  {
			switch ext := .(type) {
			case *SupportedVersionsExtension:
				 := func( []uint16) (uint16, uint16) {
					// returns (minVers, maxVers)
					 := uint16(0)
					 := uint16(0)
					for ,  := range  {
						if isGREASEUint16() {
							continue
						}
						if  <  ||  == 0 {
							 = 
						}
						if  >  ||  == 0 {
							 = 
						}
					}
					return , 
				}

				 += 1
				,  = (.Versions)
				if  == 0 &&  == 0 {
					return fmt.Errorf("SupportedVersions extension has invalid Versions field")
				} // else: proceed
			}
		}
		switch  {
		case 0:
			// if mandatory for TLS 1.3 extension is not present, just default to 1.2
			 = VersionTLS10
			 = VersionTLS12
		case 1:
		default:
			return fmt.Errorf("uconn.Extensions contains %v separate SupportedVersions extensions",
				)
		}
	}

	if  < VersionTLS10 ||  > VersionTLS13 {
		return fmt.Errorf("uTLS does not support 0x%X as min version", )
	}

	if  < VersionTLS10 ||  > VersionTLS13 {
		return fmt.Errorf("uTLS does not support 0x%X as max version", )
	}

	.HandshakeState.Hello.SupportedVersions = makeSupportedVersions(, )
	if .config.EncryptedClientHelloConfigList == nil {
		.config.MinVersion = 
		.config.MaxVersion = 
	}

	return nil
}

func ( *UConn) ( net.Conn) {
	.Conn.conn = 
}

func ( *UConn) () net.Conn {
	return .Conn.conn
}

// MakeConnWithCompleteHandshake allows to forge both server and client side TLS connections.
// Major Hack Alert.
func ( net.Conn,  uint16,  uint16,  []byte,  []byte,  []byte,  bool) *Conn {
	 := &Conn{conn: , config: &Config{}, isClient: }
	 := cipherSuiteByID()
	if  != nil {
		// This is mostly borrowed from establishKeys()
		, , , , ,  :=
			keysFromMasterSecret(, , , , ,
				.macLen, .keyLen, .ivLen)

		var ,  interface{}
		var ,  hash.Hash
		if .cipher != nil {
			 = .cipher(, , true /* for reading */)
			 = .mac()
			 = .cipher(, , false /* not for reading */)
			 = .mac()
		} else {
			 = .aead(, )
			 = .aead(, )
		}

		if  {
			.in.prepareCipherSpec(, , )
			.out.prepareCipherSpec(, , )
		} else {
			.in.prepareCipherSpec(, , )
			.out.prepareCipherSpec(, , )
		}

		// skip the handshake states
		.isHandshakeComplete.Store(true)
		.cipherSuite = 
		.haveVers = true
		.vers = 

		// Update to the new cipher specs
		// and consume the finished messages
		.in.changeCipherSpec()
		.out.changeCipherSpec()

		.in.incSeq()
		.out.incSeq()

		return 
	} else {
		// TODO: Support TLS 1.3 Cipher Suites
		return nil
	}
}

func (,  uint16) []uint16 {
	 := make([]uint16, -+1)
	for  := range  {
		[] =  - uint16()
	}
	return 
}

// Extending (*Conn).readHandshake() to support more customized handshake messages.
func ( *Conn) ( byte) (handshakeMessage, error) {
	switch  {
	case utlsTypeCompressedCertificate:
		return new(utlsCompressedCertificateMsg), nil
	case utlsTypeEncryptedExtensions:
		if .isClient {
			return new(encryptedExtensionsMsg), nil
		} else {
			return new(utlsClientEncryptedExtensionsMsg), nil
		}
	default:
		return nil, .in.setErrorLocked(.sendAlert(alertUnexpectedMessage))
	}
}

// Extending (*Conn).connectionStateLocked()
func ( *Conn) ( *ConnectionState) {
	.PeerApplicationSettings = .utls.peerApplicationSettings
}

type utlsConnExtraFields struct {
	// Application Settings (ALPS)
	peerApplicationSettings      []byte
	localApplicationSettings     []byte
	applicationSettingsCodepoint uint16

	sessionController *sessionController
}

// Read reads data from the connection.
//
// As Read calls [Conn.Handshake], in order to prevent indefinite blocking a deadline
// must be set for both Read and [Conn.Write] before Read is called when the handshake
// has not yet completed. See [Conn.SetDeadline], [Conn.SetReadDeadline], and
// [Conn.SetWriteDeadline].
func ( *UConn) ( []byte) (int, error) {
	if  := .Handshake();  != nil {
		return 0, 
	}
	if len() == 0 {
		// Put this after Handshake, in case people were calling
		// Read(nil) for the side effect of the Handshake.
		return 0, nil
	}

	.in.Lock()
	defer .in.Unlock()

	for .input.Len() == 0 {
		if  := .readRecord();  != nil {
			return 0, 
		}
		for .hand.Len() > 0 {
			if  := .handlePostHandshakeMessage();  != nil {
				return 0, 
			}
		}
	}

	,  := .input.Read()

	// If a close-notify alert is waiting, read it so that we can return (n,
	// EOF) instead of (n, nil), to signal to the HTTP response reading
	// goroutine that the connection is now closed. This eliminates a race
	// where the HTTP response reading goroutine would otherwise not observe
	// the EOF until its next read, by which time a client goroutine might
	// have already tried to reuse the HTTP connection for a new request.
	// See https://golang.org/cl/76400046 and https://golang.org/issue/3514
	if  != 0 && .input.Len() == 0 && .rawInput.Len() > 0 &&
		recordType(.rawInput.Bytes()[0]) == recordTypeAlert {
		if  := .readRecord();  != nil {
			return ,  // will be io.EOF on closeNotify
		}
	}

	return , nil
}

// handleRenegotiation processes a HelloRequest handshake message.
func ( *UConn) () error {
	if .vers == VersionTLS13 {
		return errors.New("tls: internal error: unexpected renegotiation")
	}

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

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

	if !.isClient {
		return .sendAlert(alertNoRenegotiation)
	}

	switch .config.Renegotiation {
	case RenegotiateNever:
		return .sendAlert(alertNoRenegotiation)
	case RenegotiateOnceAsClient:
		if .handshakes > 1 {
			return .sendAlert(alertNoRenegotiation)
		}
	case RenegotiateFreelyAsClient:
		// Ok.
	default:
		.sendAlert(alertInternalError)
		return errors.New("tls: unknown Renegotiation value")
	}

	.handshakeMutex.Lock()
	defer .handshakeMutex.Unlock()

	.isHandshakeComplete.Store(false)

	// [uTLS section begins]
	if  = .BuildHandshakeState();  != nil {
		return 
	}
	// [uTLS section ends]
	if .handshakeErr = .clientHandshake(context.Background()); .handshakeErr == nil {
		.handshakes++
	}
	return .handshakeErr
}

// handlePostHandshakeMessage processes a handshake message arrived after the
// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
func ( *UConn) () error {
	if .vers != VersionTLS13 {
		return .handleRenegotiation()
	}

	,  := .readHandshake(nil)
	if  != nil {
		return 
	}
	.retryCount++
	if .retryCount > maxUselessRecords {
		.sendAlert(alertUnexpectedMessage)
		return .in.setErrorLocked(errors.New("tls: too many non-advancing records"))
	}

	switch msg := .(type) {
	case *newSessionTicketMsgTLS13:
		return .handleNewSessionTicket()
	case *keyUpdateMsg:
		return .handleKeyUpdate()
	}
	// The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
	// as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
	// unexpected_message alert here doesn't provide it with enough information to distinguish
	// this condition from other unexpected messages. This is probably fine.
	.sendAlert(alertUnexpectedMessage)
	return fmt.Errorf("tls: received unexpected handshake message of type %T", )
}