Source File
common.go
Belonging Package
crypto/tls
package tls
import (
)
const (
VersionTLS10 = 0x0301
VersionTLS11 = 0x0302
VersionTLS12 = 0x0303
VersionTLS13 = 0x0304
VersionSSL30 = 0x0300
)
const (
maxPlaintext = 16384 // maximum plaintext payload length
maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3
recordHeaderLen = 5 // record header length
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
maxUselessRecords = 16 // maximum number of consecutive non-advancing records
)
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 // Not IANA assigned
typeMessageHash uint8 = 254 // synthetic message
)
const (
compressionNone uint8 = 0
)
const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
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
extensionRenegotiationInfo uint16 = 0xff01
)
const (
scsvRenegotiation uint16 = 0x00ff
)
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 // ECDSA or EdDSA keys, see RFC 8422, Section 3.
)
const (
signaturePKCS1v15 uint8 = iota + 225
signatureRSAPSS
signatureECDSA
signatureEd25519
)
var directSigning crypto.Hash = 0
var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
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,
}
downgradeCanaryTLS12 = "DOWNGRD\x01"
downgradeCanaryTLS11 = "DOWNGRD\x00"
)
type ClientAuthType int
func ( ClientAuthType) bool {
switch {
case RequireAnyClientCert, RequireAndVerifyClientCert:
return true
default:
return false
}
}
type ClientSessionState struct {
sessionTicket []uint8 // Encrypted ticket used for session resumption with server
vers uint16 // TLS version negotiated for the session
cipherSuite uint16 // Ciphersuite negotiated for the session
masterSecret []byte // Full handshake MasterSecret, or TLS 1.3 resumption_master_secret
serverCertificates []*x509.Certificate // Certificate chain presented by the server
verifiedChains [][]*x509.Certificate // Certificate chains we built for verification
receivedAt time.Time // When the session ticket was received from the server
ocspResponse []byte // Stapled OCSP response presented by the server
scts [][]byte // SCTs presented by the server
Get(sessionKey string) (session *ClientSessionState, ok bool)
Put(sessionKey string, cs *ClientSessionState)
}
type SignatureScheme uint16
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
Ed25519 SignatureScheme = 0x0807
PKCS1WithSHA1 SignatureScheme = 0x0201
ECDSAWithSHA1 SignatureScheme = 0x0203
)
AcceptableCAs [][]byte
type RenegotiationSupport int
GetCertificate func(*ClientHelloInfo) (*Certificate, error)
GetConfigForClient func(*ClientHelloInfo) (*Config, error)
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
SessionTicketKey [32]byte
ticketKeyNameLen = 16
ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
ticketKeyRotation = 24 * time.Hour
)
func ( *Config) ( [32]byte) ( ticketKey) {
:= sha512.Sum512([:])
copy(.keyName[:], [:ticketKeyNameLen])
copy(.aesKey[:], [ticketKeyNameLen:ticketKeyNameLen+16])
copy(.hmacKey[:], [ticketKeyNameLen+16:ticketKeyNameLen+32])
.created = .time()
return
}
const maxSessionTicketLifetime = 7 * 24 * time.Hour
func ( *Config) () *Config {
if == nil {
return nil
}
.mutex.RLock()
defer .mutex.RUnlock()
return &Config{
Rand: .Rand,
Time: .Time,
Certificates: .Certificates,
NameToCertificate: .NameToCertificate,
GetCertificate: .GetCertificate,
GetClientCertificate: .GetClientCertificate,
GetConfigForClient: .GetConfigForClient,
VerifyPeerCertificate: .VerifyPeerCertificate,
VerifyConnection: .VerifyConnection,
RootCAs: .RootCAs,
NextProtos: .NextProtos,
ServerName: .ServerName,
ClientAuth: .ClientAuth,
ClientCAs: .ClientCAs,
InsecureSkipVerify: .InsecureSkipVerify,
CipherSuites: .CipherSuites,
PreferServerCipherSuites: .PreferServerCipherSuites,
SessionTicketsDisabled: .SessionTicketsDisabled,
SessionTicketKey: .SessionTicketKey,
ClientSessionCache: .ClientSessionCache,
MinVersion: .MinVersion,
MaxVersion: .MaxVersion,
CurvePreferences: .CurvePreferences,
DynamicRecordSizingDisabled: .DynamicRecordSizingDisabled,
Renegotiation: .Renegotiation,
KeyLogWriter: .KeyLogWriter,
sessionTicketKeys: .sessionTicketKeys,
autoSessionTicketKeys: .autoSessionTicketKeys,
}
}
var deprecatedSessionTicketKey = []byte("DEPRECATED")
if .SessionTicketKey != [32]byte{} &&
(bytes.HasPrefix(.SessionTicketKey[:], deprecatedSessionTicketKey) || len(.sessionTicketKeys) > 0) {
return
}
copy(.SessionTicketKey[:], deprecatedSessionTicketKey)
} else if !bytes.HasPrefix(.SessionTicketKey[:], deprecatedSessionTicketKey) && len(.sessionTicketKeys) == 0 {
.sessionTicketKeys = []ticketKey{.ticketKeyFromBytes(.SessionTicketKey)}
}
}
if != nil {
.mutex.RLock()
if .SessionTicketsDisabled {
return nil
}
.initLegacySessionTicketKeyRLocked()
if len(.sessionTicketKeys) != 0 {
:= .sessionTicketKeys
.mutex.RUnlock()
return
}
.mutex.RUnlock()
}
.mutex.RLock()
defer .mutex.RUnlock()
if .SessionTicketsDisabled {
return nil
}
.initLegacySessionTicketKeyRLocked()
if len(.sessionTicketKeys) != 0 {
return .sessionTicketKeys
if len(.autoSessionTicketKeys) > 0 && .time().Sub(.autoSessionTicketKeys[0].created) < ticketKeyRotation {
return .autoSessionTicketKeys
}
if len(.autoSessionTicketKeys) == 0 || .time().Sub(.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
var [32]byte
if , := io.ReadFull(.rand(), [:]); != nil {
panic(fmt.Sprintf("unable to generate random session ticket key: %v", ))
}
:= make([]ticketKey, 0, len(.autoSessionTicketKeys)+1)
= append(, .ticketKeyFromBytes())
if .time().Sub(.created) < ticketKeyLifetime {
= append(, )
}
}
.autoSessionTicketKeys =
}
return .autoSessionTicketKeys
}
func ( *Config) ( [][32]byte) {
if len() == 0 {
panic("tls: keys must have at least one key")
}
:= make([]ticketKey, len())
for , := range {
[] = .ticketKeyFromBytes()
}
.mutex.Lock()
.sessionTicketKeys =
.mutex.Unlock()
}
func ( *Config) () io.Reader {
:= .Rand
if == nil {
return rand.Reader
}
return
}
func ( *Config) () time.Time {
:= .Time
if == nil {
= time.Now
}
return ()
}
func ( *Config) () []uint16 {
:= .CipherSuites
if == nil {
= defaultCipherSuites()
}
return
}
var supportedVersions = []uint16{
VersionTLS13,
VersionTLS12,
VersionTLS11,
VersionTLS10,
}
func ( *Config) () []uint16 {
:= make([]uint16, 0, len(supportedVersions))
for , := range supportedVersions {
if != nil && .MinVersion != 0 && < .MinVersion {
continue
}
if != nil && .MaxVersion != 0 && > .MaxVersion {
continue
}
= append(, )
}
return
}
func ( *Config) () uint16 {
:= .supportedVersions()
if len() == 0 {
return 0
}
return [0]
}
func ( uint16) []uint16 {
:= make([]uint16, 0, len(supportedVersions))
for , := range supportedVersions {
if > {
continue
}
= append(, )
}
return
}
var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
func ( *Config) () []CurveID {
if == nil || len(.CurvePreferences) == 0 {
return defaultCurvePreferences
}
return .CurvePreferences
}
func ( *Config) ( CurveID) bool {
for , := range .curvePreferences() {
if == {
return true
}
}
return false
}
func ( *Config) ( []uint16) (uint16, bool) {
:= .supportedVersions()
for , := range {
for , := range {
if == {
return , true
}
}
}
return 0, false
}
var errNoCertificates = errors.New("tls: no certificates configured")
func ( *Config) ( *ClientHelloInfo) (*Certificate, error) {
if .GetCertificate != nil &&
(len(.Certificates) == 0 || len(.ServerName) > 0) {
, := .GetCertificate()
if != nil || != nil {
return ,
}
}
if len(.Certificates) == 0 {
return nil, errNoCertificates
}
return &.Certificates[0], nil
}
if .NameToCertificate != nil {
:= strings.ToLower(.ServerName)
if , := .NameToCertificate[]; {
return , nil
}
if len() > 0 {
:= strings.Split(, ".")
[0] = "*"
:= strings.Join(, ".")
if , := .NameToCertificate[]; {
return , nil
}
}
}
for , := range .Certificates {
if := .SupportsCertificate(&); == nil {
return &, nil
}
}
return &.Certificates[0], nil
}
:= .config
if == nil {
= &Config{}
}
, := .mutualVersion(.SupportedVersions)
if ! {
return errors.New("no mutually supported protocol versions")
}
if .ServerName != "" {
, := .leaf()
if != nil {
return fmt.Errorf("failed to parse certificate: %w", )
}
if := .VerifyHostname(.ServerName); != nil {
return fmt.Errorf("certificate is not valid for requested server name: %w", )
}
}
if == VersionTLS13 {
return
:= selectCipherSuite(.CipherSuites, .cipherSuites(), func( *cipherSuite) bool {
if .flags&suiteECDHE != 0 {
return false
}
if < VersionTLS12 && .flags&suiteTLS12 != 0 {
return false
}
return true
})
if == nil {
return
}
return nil
}
if len(.SignatureSchemes) > 0 {
if , := selectSignatureScheme(, , .SignatureSchemes); != nil {
return ()
}
}
if == VersionTLS13 {
return nil
}
if !supportsECDHE(, .SupportedCurves, .SupportedPoints) {
return (errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
}
var bool
if , := .PrivateKey.(crypto.Signer); {
switch pub := .Public().(type) {
case *ecdsa.PublicKey:
var CurveID
switch .Curve {
case elliptic.P256():
= CurveP256
case elliptic.P384():
= CurveP384
case elliptic.P521():
= CurveP521
default:
return (unsupportedCertificateError())
}
var bool
for , := range .SupportedCurves {
if == && .supportsCurve() {
= true
break
}
}
if ! {
return errors.New("client doesn't support certificate curve")
}
= true
case ed25519.PublicKey:
if < VersionTLS12 || len(.SignatureSchemes) == 0 {
return errors.New("connection doesn't support Ed25519")
}
= true
case *rsa.PublicKey:
default:
return (unsupportedCertificateError())
}
} else {
return (unsupportedCertificateError())
}
:= selectCipherSuite(.CipherSuites, .cipherSuites(), func( *cipherSuite) bool {
if .flags&suiteECDHE == 0 {
return false
}
if .flags&suiteECSign != 0 {
if ! {
return false
}
} else {
if {
return false
}
}
if < VersionTLS12 && .flags&suiteTLS12 != 0 {
return false
}
return true
})
if == nil {
return (errors.New("client doesn't support any cipher suites compatible with the certificate"))
}
return nil
}
func ( *CertificateRequestInfo) ( *Certificate) error {
if , := selectSignatureScheme(.Version, , .SignatureSchemes); != nil {
return
}
if len(.AcceptableCAs) == 0 {
return nil
}
for , := range .Certificate {
func ( *Config) () {
.NameToCertificate = make(map[string]*Certificate)
for := range .Certificates {
:= &.Certificates[]
, := .leaf()
if != nil {
continue
if .Subject.CommonName != "" && len(.DNSNames) == 0 {
.NameToCertificate[.Subject.CommonName] =
}
for , := range .DNSNames {
.NameToCertificate[] =
}
}
}
const (
keyLogLabelTLS12 = "CLIENT_RANDOM"
keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0"
)
func ( *Config) ( string, , []byte) error {
if .KeyLogWriter == nil {
return nil
}
:= []byte(fmt.Sprintf("%s %x %x\n", , , ))
writerMutex.Lock()
, := .KeyLogWriter.Write()
writerMutex.Unlock()
return
}
var writerMutex sync.Mutex
type Certificate struct {
Leaf *x509.Certificate
}
func ( *Certificate) () (*x509.Certificate, error) {
if .Leaf != nil {
return .Leaf, nil
}
return x509.ParseCertificate(.Certificate[0])
}
type handshakeMessage interface {
marshal() []byte
unmarshal([]byte) bool
}
type lruSessionCache struct {
sync.Mutex
m map[string]*list.Element
q *list.List
capacity int
}
type lruSessionCacheEntry struct {
sessionKey string
state *ClientSessionState
}
func ( *lruSessionCache) ( string, *ClientSessionState) {
.Lock()
defer .Unlock()
if , := .m[]; {
if == nil {
.q.Remove()
delete(.m, )
} else {
:= .Value.(*lruSessionCacheEntry)
.state =
.q.MoveToFront()
}
return
}
if .q.Len() < .capacity {
:= &lruSessionCacheEntry{, }
.m[] = .q.PushFront()
return
}
:= .q.Back()
:= .Value.(*lruSessionCacheEntry)
delete(.m, .sessionKey)
.sessionKey =
.state =
.q.MoveToFront()
.m[] =
}
func ( *lruSessionCache) ( string) (*ClientSessionState, bool) {
.Lock()
defer .Unlock()
if , := .m[]; {
.q.MoveToFront()
return .Value.(*lruSessionCacheEntry).state, true
}
return nil, false
}
var emptyConfig Config
func () *Config {
return &emptyConfig
}
var (
once sync.Once
varDefaultCipherSuites []uint16
varDefaultCipherSuitesTLS13 []uint16
)
func () []uint16 {
once.Do(initDefaultCipherSuites)
return varDefaultCipherSuites
}
func () []uint16 {
once.Do(initDefaultCipherSuites)
return varDefaultCipherSuitesTLS13
}
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
runtime.GOARCH == "s390x" && hasGCMAsmS390X
)
func () {
var []uint16
= []uint16{
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
}
varDefaultCipherSuitesTLS13 = []uint16{
TLS_AES_128_GCM_SHA256,
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_256_GCM_SHA384,
}
= []uint16{
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
varDefaultCipherSuitesTLS13 = []uint16{
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
}
}
varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
varDefaultCipherSuites = append(varDefaultCipherSuites, ...)
:
for , := range cipherSuites {
if .flags&suiteDefaultOff != 0 {
continue
}
for , := range varDefaultCipherSuites {
if == .id {
continue
}
}
varDefaultCipherSuites = append(varDefaultCipherSuites, .id)
}
}
func (, interface{}) error {
return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", , )
}
func ( SignatureScheme, []SignatureScheme) bool {
for , := range {
if == {
return true
}
}
return false
}
func ( []uint16) bool {
for , := range {
:= cipherSuiteByID()
if == nil {
:= cipherSuiteTLS13ByID()
if == nil {
continue
}
return aesgcmCiphers[]
}
return aesgcmCiphers[]
}
return false
}
func ( []uint16) []uint16 {
:= make([]uint16, len())
copy(, )
sort.SliceStable(, func(, int) bool {
return nonAESGCMAEADCiphers[[]] && aesgcmCiphers[[]]
})
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |