func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
	supportedVersions := c.supportedVersions(isClient)
	for _, peerVersion := range peerVersions {
		for _, v := range supportedVersions {
			if v == peerVersion {
				return v, true
			}
		}
	}
	return 0, false
}
mutualVersion returns the protocol version to use given the advertised
versions of the peer. Priority is given to the peer preference order.
package qtls
import (
	"container/list"
	"crypto/rand"
	"crypto/sha512"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io"
	"math/big"
	"os"
	"strings"
	"sync"
	"time"
	"golang.org/x/sys/cpu"
)
const (
	VersionSSL30 = 0x0300
	VersionTLS10 = 0x0301
	VersionTLS11 = 0x0302
	VersionTLS12 = 0x0303
	VersionTLS13 = 0x0304
)
const (
	maxPlaintext       = 16384         
	maxCiphertext      = 16384 + 2048  
	maxCiphertextTLS13 = 16384 + 256   
	recordHeaderLen    = 5             
	maxHandshake       = 65536         
	maxUselessRecords  = 16            
)
type recordType uint8
const (
	recordTypeChangeCipherSpec recordType = 20
	recordTypeAlert            recordType = 21
	recordTypeHandshake        recordType = 22
	recordTypeApplicationData  recordType = 23
)
const (
	typeHelloRequest        uint8 = 0
	typeClientHello         uint8 = 1
	typeServerHello         uint8 = 2
	typeNewSessionTicket    uint8 = 4
	typeEndOfEarlyData      uint8 = 5
	typeEncryptedExtensions uint8 = 8
	typeCertificate         uint8 = 11
	typeServerKeyExchange   uint8 = 12
	typeCertificateRequest  uint8 = 13
	typeServerHelloDone     uint8 = 14
	typeCertificateVerify   uint8 = 15
	typeClientKeyExchange   uint8 = 16
	typeFinished            uint8 = 20
	typeCertificateStatus   uint8 = 22
	typeKeyUpdate           uint8 = 24
	typeNextProtocol        uint8 = 67   
	typeMessageHash         uint8 = 254  
)
const (
	compressionNone uint8 = 0
)
type Extension struct {
	Type uint16
	Data []byte
}
const (
	extensionServerName              uint16 = 0
	extensionStatusRequest           uint16 = 5
	extensionSupportedCurves         uint16 = 10  
	extensionSupportedPoints         uint16 = 11
	extensionSignatureAlgorithms     uint16 = 13
	extensionALPN                    uint16 = 16
	extensionSCT                     uint16 = 18
	extensionSessionTicket           uint16 = 35
	extensionPreSharedKey            uint16 = 41
	extensionEarlyData               uint16 = 42
	extensionSupportedVersions       uint16 = 43
	extensionCookie                  uint16 = 44
	extensionPSKModes                uint16 = 45
	extensionCertificateAuthorities  uint16 = 47
	extensionSignatureAlgorithmsCert uint16 = 50
	extensionKeyShare                uint16 = 51
	extensionNextProtoNeg            uint16 = 13172  
	extensionRenegotiationInfo       uint16 = 0xff01
)
const (
	scsvRenegotiation uint16 = 0x00ff
)
type CurveID = tls.CurveID
const (
	CurveP256 CurveID = 23
	CurveP384 CurveID = 24
	CurveP521 CurveID = 25
	X25519    CurveID = 29
)
type keyShare struct {
	group CurveID
	data  []byte
}
const (
	pskModePlain uint8 = 0
	pskModeDHE   uint8 = 1
)
type pskIdentity struct {
	label               []byte
	obfuscatedTicketAge uint32
}
const (
	pointFormatUncompressed uint8 = 0
)
const (
	statusTypeOCSP uint8 = 1
)
const (
	certTypeRSASign   = 1
	certTypeECDSASign = 64  
)
const (
	signaturePKCS1v15 uint8 = iota + 16
	signatureECDSA
	signatureRSAPSS
)
var supportedSignatureAlgorithms = []SignatureScheme{
	PSSWithSHA256,
	PSSWithSHA384,
	PSSWithSHA512,
	PKCS1WithSHA256,
	ECDSAWithP256AndSHA256,
	PKCS1WithSHA384,
	ECDSAWithP384AndSHA384,
	PKCS1WithSHA512,
	ECDSAWithP521AndSHA512,
	PKCS1WithSHA1,
	ECDSAWithSHA1,
}
var supportedSignatureAlgorithmsTLS12 = supportedSignatureAlgorithms[3:]
var helloRetryRequestRandom = []byte{  
	0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
	0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
	0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
	0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
}
const (
	downgradeCanaryTLS12 = "DOWNGRD\x01"
	downgradeCanaryTLS11 = "DOWNGRD\x00"
)
type ConnectionState struct {
	Version                     uint16                 
	HandshakeComplete           bool                   
	DidResume                   bool                   
	CipherSuite                 uint16                 
	NegotiatedProtocol          string                 
	NegotiatedProtocolIsMutual  bool                   
	ServerName                  string                 
	PeerCertificates            []*x509.Certificate    
	VerifiedChains              [][]*x509.Certificate  
	SignedCertificateTimestamps [][]byte               
	OCSPResponse                []byte                 
	ekm func(label string, context []byte, length int) ([]byte, error)
	TLSUnique []byte
}
func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
	return cs.ekm(label, context, length)
}
type ClientAuthType = tls.ClientAuthType
const (
	NoClientCert ClientAuthType = iota
	RequestClientCert
	RequireAnyClientCert
	VerifyClientCertIfGiven
	RequireAndVerifyClientCert
)
func requiresClientCert(c ClientAuthType) bool {
	switch c {
	case RequireAnyClientCert, RequireAndVerifyClientCert:
		return true
	default:
		return false
	}
}
type ClientSessionState struct {
	sessionTicket      []uint8                
	vers               uint16                 
	cipherSuite        uint16                 
	masterSecret       []byte                 
	serverCertificates []*x509.Certificate    
	verifiedChains     [][]*x509.Certificate  
	receivedAt         time.Time              
	nonce  []byte     
	useBy  time.Time  
	ageAdd uint32     
}
type ClientSessionCache interface {
	Get(sessionKey string) (session *ClientSessionState, ok bool)
	Put(sessionKey string, cs *ClientSessionState)
}
type SignatureScheme = tls.SignatureScheme
const (
	PKCS1WithSHA256 SignatureScheme = 0x0401
	PKCS1WithSHA384 SignatureScheme = 0x0501
	PKCS1WithSHA512 SignatureScheme = 0x0601
	PSSWithSHA256 SignatureScheme = 0x0804
	PSSWithSHA384 SignatureScheme = 0x0805
	PSSWithSHA512 SignatureScheme = 0x0806
	ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
	ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
	ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
	PKCS1WithSHA1 SignatureScheme = 0x0201
	ECDSAWithSHA1 SignatureScheme = 0x0203
)
type ClientHelloInfo = tls.ClientHelloInfo
type CertificateRequestInfo = tls.CertificateRequestInfo
type RenegotiationSupport int
const (
	RenegotiateNever RenegotiationSupport = iota
	RenegotiateOnceAsClient
	RenegotiateFreelyAsClient
)
type Config struct {
	Rand io.Reader
	Time func() time.Time
	Certificates []Certificate
	NameToCertificate map[string]*Certificate
	GetCertificate func(*ClientHelloInfo) (*Certificate, error)
	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
	GetConfigForClient func(*ClientHelloInfo) (*Config, error)
	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
	RootCAs *x509.CertPool
	NextProtos []string
	ServerName string
	ClientAuth ClientAuthType
	ClientCAs *x509.CertPool
	InsecureSkipVerify bool
	CipherSuites []uint16
	PreferServerCipherSuites bool
	SessionTicketsDisabled bool
	SessionTicketKey [32]byte
	ClientSessionCache ClientSessionCache
	MinVersion uint16
	MaxVersion uint16
	CurvePreferences []CurveID
	DynamicRecordSizingDisabled bool
	Renegotiation RenegotiationSupport
	KeyLogWriter io.Writer
	GetExtensions func(handshakeMessageType uint8) []Extension
	ReceivedExtensions func(handshakeMessageType uint8, exts []Extension)
	serverInitOnce sync.Once  
	mutex sync.RWMutex
	sessionTicketKeys []ticketKey
	AlternativeRecordLayer RecordLayer
}
type RecordLayer interface {
	SetReadKey(suite *CipherSuite, trafficSecret []byte)
	SetWriteKey(suite *CipherSuite, trafficSecret []byte)
	ReadHandshakeMessage() ([]byte, error)
	WriteRecord([]byte) (int, error)
	SendAlert(uint8)
}
const ticketKeyNameLen = 16
type ticketKey struct {
	keyName [ticketKeyNameLen]byte
	aesKey  [16]byte
	hmacKey [16]byte
}
func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
	hashed := sha512.Sum512(b[:])
	copy(key.keyName[:], hashed[:ticketKeyNameLen])
	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
	return key
}
const maxSessionTicketLifetime = 7 * 24 * time.Hour
func (c *Config) Clone() *Config {
	c.serverInitOnce.Do(func() { c.serverInit(nil) })
	var sessionTicketKeys []ticketKey
	c.mutex.RLock()
	sessionTicketKeys = c.sessionTicketKeys
	c.mutex.RUnlock()
	return &Config{
		Rand:                        c.Rand,
		Time:                        c.Time,
		Certificates:                c.Certificates,
		NameToCertificate:           c.NameToCertificate,
		GetCertificate:              c.GetCertificate,
		GetClientCertificate:        c.GetClientCertificate,
		GetConfigForClient:          c.GetConfigForClient,
		VerifyPeerCertificate:       c.VerifyPeerCertificate,
		RootCAs:                     c.RootCAs,
		NextProtos:                  c.NextProtos,
		ServerName:                  c.ServerName,
		ClientAuth:                  c.ClientAuth,
		ClientCAs:                   c.ClientCAs,
		InsecureSkipVerify:          c.InsecureSkipVerify,
		CipherSuites:                c.CipherSuites,
		PreferServerCipherSuites:    c.PreferServerCipherSuites,
		SessionTicketsDisabled:      c.SessionTicketsDisabled,
		SessionTicketKey:            c.SessionTicketKey,
		ClientSessionCache:          c.ClientSessionCache,
		MinVersion:                  c.MinVersion,
		MaxVersion:                  c.MaxVersion,
		CurvePreferences:            c.CurvePreferences,
		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
		Renegotiation:               c.Renegotiation,
		KeyLogWriter:                c.KeyLogWriter,
		GetExtensions:               c.GetExtensions,
		ReceivedExtensions:          c.ReceivedExtensions,
		sessionTicketKeys:           sessionTicketKeys,
	}
}
func (c *Config) serverInit(originalConfig *Config) {
	if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
		return
	}
	alreadySet := false
	for _, b := range c.SessionTicketKey {
		if b != 0 {
			alreadySet = true
			break
		}
	}
	if !alreadySet {
		if originalConfig != nil {
			copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
		} else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
			c.SessionTicketsDisabled = true
			return
		}
	}
	if originalConfig != nil {
		originalConfig.mutex.RLock()
		c.sessionTicketKeys = originalConfig.sessionTicketKeys
		originalConfig.mutex.RUnlock()
	} else {
		c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
	}
}
func (c *Config) ticketKeys() []ticketKey {
	c.mutex.RLock()
	ret := c.sessionTicketKeys
	c.mutex.RUnlock()
	return ret
}
func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
	if len(keys) == 0 {
		panic("tls: keys must have at least one key")
	}
	newKeys := make([]ticketKey, len(keys))
	for i, bytes := range keys {
		newKeys[i] = ticketKeyFromBytes(bytes)
	}
	c.mutex.Lock()
	c.sessionTicketKeys = newKeys
	c.mutex.Unlock()
}
func (c *Config) rand() io.Reader {
	r := c.Rand
	if r == nil {
		return rand.Reader
	}
	return r
}
func (c *Config) time() time.Time {
	t := c.Time
	if t == nil {
		t = time.Now
	}
	return t()
}
func (c *Config) cipherSuites() []uint16 {
	s := c.CipherSuites
	if s == nil {
		s = defaultCipherSuites()
	}
	return s
}
var supportedVersions = []uint16{
	VersionTLS13,
	VersionTLS12,
	VersionTLS11,
	VersionTLS10,
	VersionSSL30,
}
func (c *Config) supportedVersions(isClient bool) []uint16 {
	versions := make([]uint16, 0, len(supportedVersions))
	for _, v := range supportedVersions {
		if c != nil && c.MinVersion != 0 && v < c.MinVersion {
			continue
		}
		if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
			continue
		}
		if isClient && v < VersionTLS10 {
			continue
		}
		if v == VersionTLS13 && !isTLS13Supported() {
			continue
		}
		versions = append(versions, v)
	}
	return versions
}
var tls13Support struct {
	sync.Once
	cached bool
}
func isTLS13Supported() bool {
	return true
	tls13Support.Do(func() {
		tls13Support.cached = goDebugString("tls13") == "1"
	})
	return tls13Support.cached
}
func goDebugString(key string) string {
	s := os.Getenv("GODEBUG")
	for i := 0; i < len(s)-len(key)-1; i++ {
		if i > 0 && s[i-1] != ',' {
			continue
		}
		afterKey := s[i+len(key):]
		if afterKey[0] != '=' || s[i:i+len(key)] != key {
			continue
		}
		val := afterKey[1:]
		for i, b := range val {
			if b == ',' {
				return val[:i]
			}
		}
		return val
	}
	return ""
}
func (c *Config) maxSupportedVersion(isClient bool) uint16 {
	supportedVersions := c.supportedVersions(isClient)
	if len(supportedVersions) == 0 {
		return 0
	}
	return supportedVersions[0]
}
func supportedVersionsFromMax(maxVersion uint16) []uint16 {
	versions := make([]uint16, 0, len(supportedVersions))
	for _, v := range supportedVersions {
		if v > maxVersion {
			continue
		}
		versions = append(versions, v)
	}
	return versions
}
var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
	if c == nil || len(c.CurvePreferences) == 0 {
		return defaultCurvePreferences
	}
	return c.CurvePreferences
}