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
	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")
	}

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[:]
	}

	 := .cipherSuites()
	.cipherSuites = make([]uint16, 0, len())

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

	,  := 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 {
		.cipherSuites = append(.cipherSuites, defaultCipherSuitesTLS13()...)

		 := .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) () ( 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 {
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:           ,
			serverHello: ,
			hello:       ,
			ecdheParams: ,
			session:     ,
			earlySecret: ,
			binderKey:   ,
		}
In TLS 1.3, session tickets are delivered after the handshake.
		return .handshake()
	}

	 := &clientHandshakeState{
		c:           ,
		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

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.
The original connection had InsecureSkipVerify, while this doesn't.
			return , nil, nil, nil
		}
		 := .serverCertificates[0]
Expired certificate, delete the entry.
			.config.ClientSessionCache.Put(, nil)
			return , nil, nil, nil
		}
		if  := .VerifyHostname(.config.ServerName);  != nil {
			return , nil, nil, nil
		}
	}

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 
		}
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)
RFC4366 on Certificate Status Request: The server MAY return a "certificate_status" message.

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 this is the first handshake on a connection, process and (optionally) verify the server's certificates.
		if  := .verifyServerCertificate(.certificates);  != nil {
			return 
		}
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(.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
}

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 .serverHello.alpnProtocol != "" {
		if len(.hello.alpnProtocols) == 0 {
			.sendAlert(alertUnsupportedExtension)
			return false, errors.New("tls: server advertised unrequested ALPN extension")
		}
		if mutualProtocol([]string{.serverHello.alpnProtocol}, .hello.alpnProtocols) == "" {
			.sendAlert(alertUnsupportedExtension)
			return false, errors.New("tls: server selected unadvertised ALPN protocol")
		}
		.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
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
}

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 ( uint16,  *certificateRequestMsg) *CertificateRequestInfo {
	 := &CertificateRequestInfo{
		AcceptableCAs: .certificateAuthorities,
		Version:       ,
	}

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

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.
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 ( net.Addr,  *Config) string {
	if len(.ServerName) > 0 {
		return .ServerName
	}
	return .String()
}
mutualProtocol finds the mutual ALPN protocol given list of possible protocols and a list of the preference order.
func (,  []string) string {
	for ,  := range  {
		for ,  := range  {
			if  ==  {
				return 
			}
		}
	}
	return ""
}
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 ( 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