diff options
Diffstat (limited to 'src/crypto/tls/common.go')
| -rw-r--r-- | src/crypto/tls/common.go | 123 |
1 files changed, 106 insertions, 17 deletions
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index e8d009137a..5b68742975 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -7,6 +7,7 @@ package tls import ( "bytes" "container/list" + "context" "crypto" "crypto/ecdsa" "crypto/ed25519" @@ -20,6 +21,8 @@ import ( "internal/cpu" "io" "net" + "runtime" + "sort" "strings" "sync" "time" @@ -228,9 +231,6 @@ type ConnectionState struct { CipherSuite uint16 // NegotiatedProtocol is the application protocol negotiated with ALPN. - // - // Note that on the client side, this is currently not guaranteed to be from - // Config.NextProtos. NegotiatedProtocol string // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation. @@ -294,10 +294,26 @@ func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, le type ClientAuthType int const ( + // NoClientCert indicates that no client certificate should be requested + // during the handshake, and if any certificates are sent they will not + // be verified. NoClientCert ClientAuthType = iota + // RequestClientCert indicates that a client certificate should be requested + // during the handshake, but does not require that the client send any + // certificates. RequestClientCert + // RequireAnyClientCert indicates that a client certificate should be requested + // during the handshake, and that at least one certificate is required to be + // sent by the client, but that certificate is not required to be valid. RequireAnyClientCert + // VerifyClientCertIfGiven indicates that a client certificate should be requested + // during the handshake, but does not require that the client sends a + // certificate. If the client does send a certificate it is required to be + // valid. VerifyClientCertIfGiven + // RequireAndVerifyClientCert indicates that a client certificate should be requested + // during the handshake, and that at least one valid certificate is required + // to be sent by the client. RequireAndVerifyClientCert ) @@ -428,6 +444,16 @@ type ClientHelloInfo struct { // config is embedded by the GetCertificate or GetConfigForClient caller, // for use with SupportsCertificate. config *Config + + // ctx is the context of the handshake that is in progress. + ctx context.Context +} + +// Context returns the context of the handshake that is in progress. +// This context is a child of the context passed to HandshakeContext, +// if any, and is canceled when the handshake concludes. +func (c *ClientHelloInfo) Context() context.Context { + return c.ctx } // CertificateRequestInfo contains information from a server's @@ -446,6 +472,16 @@ type CertificateRequestInfo struct { // Version is the TLS version that was negotiated for this connection. Version uint16 + + // ctx is the context of the handshake that is in progress. + ctx context.Context +} + +// Context returns the context of the handshake that is in progress. +// This context is a child of the context passed to HandshakeContext, +// if any, and is canceled when the handshake concludes. +func (c *CertificateRequestInfo) Context() context.Context { + return c.ctx } // RenegotiationSupport enumerates the different levels of support for TLS @@ -727,9 +763,12 @@ func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) { // ticket, and the lifetime we set for tickets we send. const maxSessionTicketLifetime = 7 * 24 * time.Hour -// Clone returns a shallow clone of c. It is safe to clone a Config that is +// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is // being used concurrently by a TLS client or server. func (c *Config) Clone() *Config { + if c == nil { + return nil + } c.mutex.RLock() defer c.mutex.RUnlock() return &Config{ @@ -1244,7 +1283,9 @@ func (c *Config) BuildNameToCertificate() { if err != nil { continue } - if len(x509Cert.Subject.CommonName) > 0 { + // If SANs are *not* present, some clients will consider the certificate + // valid for the name in the Common Name. + if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 { c.NameToCertificate[x509Cert.Subject.CommonName] = cert } for _, san := range x509Cert.DNSNames { @@ -1415,21 +1456,21 @@ func defaultCipherSuitesTLS13() []uint16 { return varDefaultCipherSuitesTLS13 } -func initDefaultCipherSuites() { - var topCipherSuites []uint16 +var ( + hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ + hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL + // Keep in sync with crypto/aes/cipher_s390x.go. + hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) - // Check the cpu flags for each platform that has optimized GCM implementations. - // Worst case, these variables will just all be false. - var ( - hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ - hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - // Keep in sync with crypto/aes/cipher_s390x.go. - 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 +) - hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X - ) +func initDefaultCipherSuites() { + var topCipherSuites []uint16 - if hasGCMAsm { + if hasAESGCMHardwareSupport { // If AES-GCM hardware is provided then prioritise AES-GCM // cipher suites. topCipherSuites = []uint16{ @@ -1492,3 +1533,51 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg } return false } + +var aesgcmCiphers = map[uint16]bool{ + // 1.2 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true, + // 1.3 + TLS_AES_128_GCM_SHA256: true, + TLS_AES_256_GCM_SHA384: true, +} + +var nonAESGCMAEADCiphers = map[uint16]bool{ + // 1.2 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: true, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true, + // 1.3 + TLS_CHACHA20_POLY1305_SHA256: true, +} + +// aesgcmPreferred returns whether the first valid cipher in the preference list +// is an AES-GCM cipher, implying the peer has hardware support for it. +func aesgcmPreferred(ciphers []uint16) bool { + for _, cID := range ciphers { + c := cipherSuiteByID(cID) + if c == nil { + c13 := cipherSuiteTLS13ByID(cID) + if c13 == nil { + continue + } + return aesgcmCiphers[cID] + } + return aesgcmCiphers[cID] + } + return false +} + +// deprioritizeAES reorders cipher preference lists by rearranging +// adjacent AEAD ciphers such that AES-GCM based ciphers are moved +// after other AEAD ciphers. It returns a fresh slice. +func deprioritizeAES(ciphers []uint16) []uint16 { + reordered := make([]uint16, len(ciphers)) + copy(reordered, ciphers) + sort.SliceStable(reordered, func(i, j int) bool { + return nonAESGCMAEADCiphers[reordered[i]] && aesgcmCiphers[reordered[j]] + }) + return reordered +} |
