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

type clientHandshakeState struct {
	c            *Conn
	ctx          context.Context
	serverHello  *serverHelloMsg
	hello        *clientHelloMsg
	suite        *cipherSuite
	finishedHash finishedHash
	masterSecret []byte
	session      *ClientSessionState
}

func ( *Conn) () (*clientHelloMsg, ecdheParameters, error) {
	 := .config
	if len(.ServerName) == 0 && !.InsecureSkipVerify {
		return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
	}

	 := 0
	for ,  := range .NextProtos {
		if  := len();  == 0 ||  > 255 {
			return nil, nil, errors.New("tls: invalid NextProtos value")
		} else {
			 += 1 + 
		}
	}
	if  > 0xffff {
		return nil, nil, errors.New("tls: NextProtos values too large")
	}

	 := .supportedVersions()
	if len() == 0 {
		return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
	}

	 := .maxSupportedVersion()
	// The version at the beginning of the ClientHello was capped at TLS 1.2
	// for compatibility reasons. The supported_versions extension is used
	// to negotiate versions now. See RFC 8446, Section 4.2.1.
	if  > VersionTLS12 {
		 = VersionTLS12
	}

	 := &clientHelloMsg{
		vers:                         ,
		compressionMethods:           []uint8{compressionNone},
		random:                       make([]byte, 32),
		sessionId:                    make([]byte, 32),
		ocspStapling:                 true,
		scts:                         true,
		serverName:                   hostnameInSNI(.ServerName),
		supportedCurves:              .curvePreferences(),
		supportedPoints:              []uint8{pointFormatUncompressed},
		secureRenegotiationSupported: true,
		alpnProtocols:                .NextProtos,
		supportedVersions:            ,
	}

	if .handshakes > 0 {
		.secureRenegotiation = .clientFinished[:]
	}

	 := cipherSuitesPreferenceOrder
	if !hasAESGCMHardwareSupport {
		 = cipherSuitesPreferenceOrderNoAES
	}
	 := .cipherSuites()
	.cipherSuites = make([]uint16, 0, len())

	for ,  := range  {
		 := mutualCipherSuite(, )
		if  == nil {
			continue
		}
		// Don't advertise TLS 1.2-only cipher suites unless
		// we're attempting TLS 1.2.
		if .vers < VersionTLS12 && .flags&suiteTLS12 != 0 {
			continue
		}
		.cipherSuites = append(.cipherSuites, )
	}

	,  := io.ReadFull(.rand(), .random)
	if  != nil {
		return nil, nil, errors.New("tls: short read from Rand: " + .Error())
	}

	// A random session ID is used to detect when the server accepted a ticket
	// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
	// a compatibility measure (see RFC 8446, Section 4.1.2).
	if ,  := io.ReadFull(.rand(), .sessionId);  != nil {
		return nil, nil, errors.New("tls: short read from Rand: " + .Error())
	}

	if .vers >= VersionTLS12 {
		.supportedSignatureAlgorithms = supportedSignatureAlgorithms
	}

	var  ecdheParameters
	if .supportedVersions[0] == VersionTLS13 {
		if hasAESGCMHardwareSupport {
			.cipherSuites = append(.cipherSuites, defaultCipherSuitesTLS13...)
		} else {
			.cipherSuites = append(.cipherSuites, defaultCipherSuitesTLS13NoAES...)
		}

		 := .curvePreferences()[0]
		if ,  := curveForCurveID();  != X25519 && ! {
			return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
		}
		,  = generateECDHEParameters(.rand(), )
		if  != nil {
			return nil, nil, 
		}
		.keyShares = []keyShare{{group: , data: .PublicKey()}}
	}

	return , , nil
}

func ( *Conn) ( context.Context) ( error) {
	if .config == nil {
		.config = defaultConfig()
	}

	// This may be a renegotiation handshake, in which case some fields
	// need to be reset.
	.didResume = false

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

	, , ,  := .loadSession()
	if  != "" &&  != nil {
		defer func() {
			// If we got a handshake failure when resuming a session, throw away
			// the session ticket. See RFC 5077, Section 3.2.
			//
			// RFC 8446 makes no mention of dropping tickets on failure, but it
			// does require servers to abort on invalid binders, so we need to
			// delete tickets to recover from a corrupted PSK.
			if  != nil {
				.config.ClientSessionCache.Put(, nil)
			}
		}()
	}

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

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

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

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

	// If we are negotiating a protocol version that's lower than what we
	// support, check for the server downgrade canaries.
	// See RFC 8446, Section 4.1.3.
	 := .config.maxSupportedVersion()
	 := string(.random[24:]) == downgradeCanaryTLS12
	 := string(.random[24:]) == downgradeCanaryTLS11
	if  == VersionTLS13 && .vers <= VersionTLS12 && ( || ) ||
		 == VersionTLS12 && .vers <= VersionTLS11 &&  {
		.sendAlert(alertIllegalParameter)
		return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
	}

	if .vers == VersionTLS13 {
		 := &clientHandshakeStateTLS13{
			c:           ,
			ctx:         ,
			serverHello: ,
			hello:       ,
			ecdheParams: ,
			session:     ,
			earlySecret: ,
			binderKey:   ,
		}

		// In TLS 1.3, session tickets are delivered after the handshake.
		return .handshake()
	}

	 := &clientHandshakeState{
		c:           ,
		ctx:         ,
		serverHello: ,
		hello:       ,
		session:     ,
	}

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

	// If we had a successful handshake and hs.session is different from
	// the one already cached - cache a new one.
	if  != "" && .session != nil &&  != .session {
		.config.ClientSessionCache.Put(, .session)
	}

	return nil
}

func ( *Conn) ( *clientHelloMsg) ( string,
	 *ClientSessionState, ,  []byte) {
	if .config.SessionTicketsDisabled || .config.ClientSessionCache == nil {
		return "", nil, nil, nil
	}

	.ticketSupported = true

	if .supportedVersions[0] == VersionTLS13 {
		// Require DHE on resumption as it guarantees forward secrecy against
		// compromise of the session ticket key. See RFC 8446, Section 4.2.9.
		.pskModes = []uint8{pskModeDHE}
	}

	// Session resumption is not allowed if renegotiating because
	// renegotiation is primarily used to allow a client to send a client
	// certificate, which would be skipped if session resumption occurred.
	if .handshakes != 0 {
		return "", nil, nil, nil
	}

	// Try to resume a previously negotiated TLS session, if available.
	 = clientSessionCacheKey(.conn.RemoteAddr(), .config)
	,  := .config.ClientSessionCache.Get()
	if ! ||  == nil {
		return , nil, nil, nil
	}

	// Check that version used for the previous session is still valid.
	 := false
	for ,  := range .supportedVersions {
		if  == .vers {
			 = true
			break
		}
	}
	if ! {
		return , nil, nil, nil
	}

	// Check that the cached server certificate is not expired, and that it's
	// valid for the ServerName. This should be ensured by the cache key, but
	// protect the application from a faulty ClientSessionCache implementation.
	if !.config.InsecureSkipVerify {
		if len(.verifiedChains) == 0 {
			// The original connection had InsecureSkipVerify, while this doesn't.
			return , nil, nil, nil
		}
		 := .serverCertificates[0]
		if .config.time().After(.NotAfter) {
			// Expired certificate, delete the entry.
			.config.ClientSessionCache.Put(, nil)
			return , nil, nil, nil
		}
		if  := .VerifyHostname(.config.ServerName);  != nil {
			return , nil, nil, nil
		}
	}

	if .vers != VersionTLS13 {
		// In TLS 1.2 the cipher suite must match the resumed session. Ensure we
		// are still offering it.
		if mutualCipherSuite(.cipherSuites, .cipherSuite) == nil {
			return , nil, nil, nil
		}

		.sessionTicket = .sessionTicket
		return
	}

	// Check that the session ticket is not expired.
	if .config.time().After(.useBy) {
		.config.ClientSessionCache.Put(, nil)
		return , nil, nil, nil
	}

	// In TLS 1.3 the KDF hash must match the resumed session. Ensure we
	// offer at least one cipher suite with that hash.
	 := cipherSuiteTLS13ByID(.cipherSuite)
	if  == nil {
		return , nil, nil, nil
	}
	 := false
	for ,  := range .cipherSuites {
		 := cipherSuiteTLS13ByID()
		if  != nil && .hash == .hash {
			 = true
			break
		}
	}
	if ! {
		return , nil, nil, nil
	}

	// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
	 := uint32(.config.time().Sub(.receivedAt) / time.Millisecond)
	 := pskIdentity{
		label:               .sessionTicket,
		obfuscatedTicketAge:  + .ageAdd,
	}
	.pskIdentities = []pskIdentity{}
	.pskBinders = [][]byte{make([]byte, .hash.Size())}

	// Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
	 := .expandLabel(.masterSecret, "resumption",
		.nonce, .hash.Size())
	 = .extract(, nil)
	 = .deriveSecret(, resumptionBinderLabel, nil)
	 := .hash.New()
	.Write(.marshalWithoutBinders())
	 := [][]byte{.finishedHash(, )}
	.updateBinders()

	return
}

func ( *Conn) ( *serverHelloMsg) error {
	 := .vers
	if .supportedVersion != 0 {
		 = .supportedVersion
	}

	,  := .config.mutualVersion([]uint16{})
	if ! {
		.sendAlert(alertProtocolVersion)
		return fmt.Errorf("tls: server selected unsupported protocol version %x", )
	}

	.vers = 
	.haveVers = true
	.in.version = 
	.out.version = 

	return nil
}

// Does the handshake, either a full one or resumes old session. Requires hs.c,
// hs.hello, hs.serverHello, and, optionally, hs.session to be set.
func ( *clientHandshakeState) () error {
	 := .c

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

	.finishedHash = newFinishedHash(.vers, .suite)

	// No signatures of the handshake are needed in a resumption.
	// Otherwise, in a full handshake, if we don't have any certificates
	// configured then we will never send a CertificateVerify message and
	// thus no signatures are needed in that case either.
	if  || (len(.config.Certificates) == 0 && .config.GetClientCertificate == nil) {
		.finishedHash.discardHandshakeBuffer()
	}

	.finishedHash.Write(.hello.marshal())
	.finishedHash.Write(.serverHello.marshal())

	.buffering = true
	.didResume = 
	if  {
		if  := .establishKeys();  != nil {
			return 
		}
		if  := .readSessionTicket();  != nil {
			return 
		}
		if  := .readFinished(.serverFinished[:]);  != nil {
			return 
		}
		.clientFinishedIsFirst = false
		// 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 
			}
		}
		if  := .sendFinished(.clientFinished[:]);  != nil {
			return 
		}
		if ,  := .flush();  != nil {
			return 
		}
	} else {
		if  := .doFullHandshake();  != nil {
			return 
		}
		if  := .establishKeys();  != nil {
			return 
		}
		if  := .sendFinished(.clientFinished[:]);  != nil {
			return 
		}
		if ,  := .flush();  != nil {
			return 
		}
		.clientFinishedIsFirst = true
		if  := .readSessionTicket();  != nil {
			return 
		}
		if  := .readFinished(.serverFinished[:]);  != nil {
			return 
		}
	}

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

	return nil
}

func ( *clientHandshakeState) () error {
	if .suite = mutualCipherSuite(.hello.cipherSuites, .serverHello.cipherSuite); .suite == nil {
		.c.sendAlert(alertHandshakeFailure)
		return errors.New("tls: server chose an unconfigured cipher suite")
	}

	.c.cipherSuite = .suite.id
	return nil
}

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

	,  := .readHandshake()
	if  != nil {
		return 
	}
	,  := .(*certificateMsg)
	if ! || len(.certificates) == 0 {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	.finishedHash.Write(.marshal())

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

	,  := .(*certificateStatusMsg)
	if  {
		// RFC4366 on Certificate Status Request:
		// The server MAY return a "certificate_status" message.

		if !.serverHello.ocspStapling {
			// If a server returns a "CertificateStatus" message, then the
			// server MUST have included an extension of type "status_request"
			// with empty "extension_data" in the extended server hello.

			.sendAlert(alertUnexpectedMessage)
			return errors.New("tls: received unexpected CertificateStatus message")
		}
		.finishedHash.Write(.marshal())

		.ocspResponse = .response

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

	if .handshakes == 0 {
		// If this is the first handshake on a connection, process and
		// (optionally) verify the server's certificates.
		if  := .verifyServerCertificate(.certificates);  != nil {
			return 
		}
	} else {
		// This is a renegotiation handshake. We require that the
		// server's identity (i.e. leaf certificate) is unchanged and
		// thus any previous trust decision is still valid.
		//
		// See https://mitls.org/pages/attacks/3SHAKE for the
		// motivation behind this requirement.
		if !bytes.Equal(.peerCertificates[0].Raw, .certificates[0]) {
			.sendAlert(alertBadCertificate)
			return errors.New("tls: server's identity changed during renegotiation")
		}
	}

	 := .suite.ka(.vers)

	,  := .(*serverKeyExchangeMsg)
	if  {
		.finishedHash.Write(.marshal())
		 = .processServerKeyExchange(.config, .hello, .serverHello, .peerCertificates[0], )
		if  != nil {
			.sendAlert(alertUnexpectedMessage)
			return 
		}

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

	var  *Certificate
	var  bool
	,  := .(*certificateRequestMsg)
	if  {
		 = true
		.finishedHash.Write(.marshal())

		 := certificateRequestInfoFromMsg(.ctx, .vers, )
		if ,  = .getClientCertificate();  != nil {
			.sendAlert(alertInternalError)
			return 
		}

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

	,  := .(*serverHelloDoneMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	.finishedHash.Write(.marshal())

	// If the server requested a certificate then we have to send a
	// Certificate message, even if it's empty because we don't have a
	// certificate to send.
	if  {
		 = new(certificateMsg)
		.certificates = .Certificate
		.finishedHash.Write(.marshal())
		if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
			return 
		}
	}

	, ,  := .generateClientKeyExchange(.config, .hello, .peerCertificates[0])
	if  != nil {
		.sendAlert(alertInternalError)
		return 
	}
	if  != nil {
		.finishedHash.Write(.marshal())
		if ,  := .writeRecord(recordTypeHandshake, .marshal());  != nil {
			return 
		}
	}

	if  != nil && len(.Certificate) > 0 {
		 := &certificateVerifyMsg{}

		,  := .PrivateKey.(crypto.Signer)
		if ! {
			.sendAlert(alertInternalError)
			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", .PrivateKey)
		}

		var  uint8
		var  crypto.Hash
		if .vers >= VersionTLS12 {
			,  := selectSignatureScheme(.vers, , .supportedSignatureAlgorithms)
			if  != nil {
				.sendAlert(alertIllegalParameter)
				return 
			}
			, ,  = typeAndHashFromSignatureScheme()
			if  != nil {
				return .sendAlert(alertInternalError)
			}
			.hasSignatureAlgorithm = true
			.signatureAlgorithm = 
		} else {
			, ,  = legacyTypeAndHashFromPublicKey(.Public())
			if  != nil {
				.sendAlert(alertIllegalParameter)
				return 
			}
		}

		 := .finishedHash.hashForClientCertificate(, , .masterSecret)
		 := crypto.SignerOpts()
		if  == signatureRSAPSS {
			 = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: }
		}
		.signature,  = .Sign(.config.rand(), , )
		if  != nil {
			.sendAlert(alertInternalError)
			return 
		}

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

	.masterSecret = masterFromPreMasterSecret(.vers, .suite, , .hello.random, .serverHello.random)
	if  := .config.writeKeyLog(keyLogLabelTLS12, .hello.random, .masterSecret);  != nil {
		.sendAlert(alertInternalError)
		return errors.New("tls: failed to write to key log: " + .Error())
	}

	.finishedHash.discardHandshakeBuffer()

	return nil
}

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

	, , , , ,  :=
		keysFromMasterSecret(.vers, .suite, .masterSecret, .hello.random, .serverHello.random, .suite.macLen, .suite.keyLen, .suite.ivLen)
	var ,  interface{}
	var ,  hash.Hash
	if .suite.cipher != nil {
		 = .suite.cipher(, , false /* not for reading */)
		 = .suite.mac()
		 = .suite.cipher(, , true /* for reading */)
		 = .suite.mac()
	} else {
		 = .suite.aead(, )
		 = .suite.aead(, )
	}

	.in.prepareCipherSpec(.vers, , )
	.out.prepareCipherSpec(.vers, , )
	return nil
}

func ( *clientHandshakeState) () bool {
	// If the server responded with the same sessionId then it means the
	// sessionTicket is being used to resume a TLS session.
	return .session != nil && .hello.sessionId != nil &&
		bytes.Equal(.serverHello.sessionId, .hello.sessionId)
}

func ( *clientHandshakeState) () (bool, error) {
	 := .c

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

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

	if .handshakes == 0 && .serverHello.secureRenegotiationSupported {
		.secureRenegotiation = true
		if len(.serverHello.secureRenegotiation) != 0 {
			.sendAlert(alertHandshakeFailure)
			return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
		}
	}

	if .handshakes > 0 && .secureRenegotiation {
		var  [24]byte
		copy([:], .clientFinished[:])
		copy([12:], .serverFinished[:])
		if !bytes.Equal(.serverHello.secureRenegotiation, [:]) {
			.sendAlert(alertHandshakeFailure)
			return false, errors.New("tls: incorrect renegotiation extension contents")
		}
	}

	if  := checkALPN(.hello.alpnProtocols, .serverHello.alpnProtocol);  != nil {
		.sendAlert(alertUnsupportedExtension)
		return false, 
	}
	.clientProtocol = .serverHello.alpnProtocol

	.scts = .serverHello.scts

	if !.serverResumedSession() {
		return false, nil
	}

	if .session.vers != .vers {
		.sendAlert(alertHandshakeFailure)
		return false, errors.New("tls: server resumed a session with a different version")
	}

	if .session.cipherSuite != .suite.id {
		.sendAlert(alertHandshakeFailure)
		return false, errors.New("tls: server resumed a session with a different cipher suite")
	}

	// Restore masterSecret, peerCerts, and ocspResponse from previous state
	.masterSecret = .session.masterSecret
	.peerCertificates = .session.serverCertificates
	.verifiedChains = .session.verifiedChains
	.ocspResponse = .session.ocspResponse
	// Let the ServerHello SCTs override the session SCTs from the original
	// connection, if any are provided
	if len(.scts) == 0 && len(.session.scts) != 0 {
		.scts = .session.scts
	}

	return true, nil
}

// checkALPN ensure that the server's choice of ALPN protocol is compatible with
// the protocols that we advertised in the Client Hello.
func checkALPN( []string,  string) error {
	if  == "" {
		return nil
	}
	if len() == 0 {
		return errors.New("tls: server advertised unrequested ALPN extension")
	}
	for ,  := range  {
		if  ==  {
			return nil
		}
	}
	return errors.New("tls: server selected unadvertised ALPN protocol")
}

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

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

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

	 := .finishedHash.serverSum(.masterSecret)
	if len() != len(.verifyData) ||
		subtle.ConstantTimeCompare(, .verifyData) != 1 {
		.sendAlert(alertHandshakeFailure)
		return errors.New("tls: server's Finished message was incorrect")
	}
	.finishedHash.Write(.marshal())
	copy(, )
	return nil
}

func ( *clientHandshakeState) () error {
	if !.serverHello.ticketSupported {
		return nil
	}

	 := .c
	,  := .readHandshake()
	if  != nil {
		return 
	}
	,  := .(*newSessionTicketMsg)
	if ! {
		.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(, )
	}
	.finishedHash.Write(.marshal())

	.session = &ClientSessionState{
		sessionTicket:      .ticket,
		vers:               .vers,
		cipherSuite:        .suite.id,
		masterSecret:       .masterSecret,
		serverCertificates: .peerCertificates,
		verifiedChains:     .verifiedChains,
		receivedAt:         .config.time(),
		ocspResponse:       .ocspResponse,
		scts:               .scts,
	}

	return nil
}

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

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

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

// verifyServerCertificate parses and verifies the provided chain, setting
// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
func ( *Conn) ( [][]byte) error {
	 := make([]*x509.Certificate, len())
	for ,  := range  {
		,  := x509.ParseCertificate()
		if  != nil {
			.sendAlert(alertBadCertificate)
			return errors.New("tls: failed to parse certificate from server: " + .Error())
		}
		[] = 
	}

	if !.config.InsecureSkipVerify {
		 := x509.VerifyOptions{
			Roots:         .config.RootCAs,
			CurrentTime:   .config.time(),
			DNSName:       .config.ServerName,
			Intermediates: x509.NewCertPool(),
		}
		for ,  := range [1:] {
			.Intermediates.AddCert()
		}
		var  error
		.verifiedChains,  = [0].Verify()
		if  != nil {
			.sendAlert(alertBadCertificate)
			return 
		}
	}

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

	.peerCertificates = 

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

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

	return nil
}

// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
func certificateRequestInfoFromMsg( context.Context,  uint16,  *certificateRequestMsg) *CertificateRequestInfo {
	 := &CertificateRequestInfo{
		AcceptableCAs: .certificateAuthorities,
		Version:       ,
		ctx:           ,
	}

	var ,  bool
	for ,  := range .certificateTypes {
		switch  {
		case certTypeRSASign:
			 = true
		case certTypeECDSASign:
			 = true
		}
	}

	if !.hasSignatureAlgorithm {
		// Prior to TLS 1.2, signature schemes did not exist. In this case we
		// make up a list based on the acceptable certificate types, to help
		// GetClientCertificate and SupportsCertificate select the right certificate.
		// The hash part of the SignatureScheme is a lie here, because
		// TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA.
		switch {
		case  && :
			.SignatureSchemes = []SignatureScheme{
				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
			}
		case :
			.SignatureSchemes = []SignatureScheme{
				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
			}
		case :
			.SignatureSchemes = []SignatureScheme{
				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
			}
		}
		return 
	}

	// Filter the signature schemes based on the certificate types.
	// See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
	.SignatureSchemes = make([]SignatureScheme, 0, len(.supportedSignatureAlgorithms))
	for ,  := range .supportedSignatureAlgorithms {
		, ,  := typeAndHashFromSignatureScheme()
		if  != nil {
			continue
		}
		switch  {
		case signatureECDSA, signatureEd25519:
			if  {
				.SignatureSchemes = append(.SignatureSchemes, )
			}
		case signatureRSAPSS, signaturePKCS1v15:
			if  {
				.SignatureSchemes = append(.SignatureSchemes, )
			}
		}
	}

	return 
}

func ( *Conn) ( *CertificateRequestInfo) (*Certificate, error) {
	if .config.GetClientCertificate != nil {
		return .config.GetClientCertificate()
	}

	for ,  := range .config.Certificates {
		if  := .SupportsCertificate(&);  != nil {
			continue
		}
		return &, nil
	}

	// No acceptable certificate found. Don't send a certificate.
	return new(Certificate), nil
}

// clientSessionCacheKey returns a key used to cache sessionTickets that could
// be used to resume previously negotiated TLS sessions with a server.
func clientSessionCacheKey( net.Addr,  *Config) string {
	if len(.ServerName) > 0 {
		return .ServerName
	}
	return .String()
}

// hostnameInSNI converts name into an appropriate hostname for SNI.
// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
// See RFC 6066, Section 3.
func hostnameInSNI( string) string {
	 := 
	if len() > 0 && [0] == '[' && [len()-1] == ']' {
		 = [1 : len()-1]
	}
	if  := strings.LastIndex(, "%");  > 0 {
		 = [:]
	}
	if net.ParseIP() != nil {
		return ""
	}
	for len() > 0 && [len()-1] == '.' {
		 = [:len()-1]
	}
	return 
}