Skip to content

Commit

Permalink
crypto/tls: disable 3-DES by default
Browse files Browse the repository at this point in the history
Fixes #66214

Change-Id: Iba8006a17fc7cd33c7485ab1a1ef8f56531c0ed1
Reviewed-on: https://go-review.googlesource.com/c/go/+/587295
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
  • Loading branch information
FiloSottile authored and gopherbot committed May 22, 2024
1 parent 5fee159 commit 0326605
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 26 deletions.
4 changes: 4 additions & 0 deletions doc/godebug.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ Go 1.23 re-enabled support in html/template for ECMAScript 6 template literals b
The [`jstmpllitinterp` setting](/pkg/html/template#hdr-Security_Model) no longer has
any effect.

Go 1.23 changed the default TLS cipher suites used by clients and servers when
not explicitly configured, removing 3DES cipher suites. The default can be reverted
using the [`tls3des` setting](/pkg/crypto/tls/#Config.CipherSuites).

### Go 1.22

Go 1.22 adds a configurable limit to control the maximum acceptable RSA key size
Expand Down
3 changes: 3 additions & 0 deletions doc/next/6-stdlib/99-minor/crypto/tls/66214.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
3DES cipher suites were removed from the default list used when
[Config.CipherSuites] is nil. The default can be reverted adding `tls3des=1` to
the GODEBUG environment variable.
33 changes: 19 additions & 14 deletions src/crypto/tls/cipher_suites.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import (
"fmt"
"hash"
"internal/cpu"
"internal/godebug"
"runtime"
"slices"

"golang.org/x/crypto/chacha20poly1305"
)
Expand Down Expand Up @@ -334,6 +336,8 @@ var disabledCipherSuites = map[uint16]bool{
TLS_RSA_WITH_RC4_128_SHA: true,
}

var tlsrsakex = godebug.New("tlsrsakex")

// rsaKexCiphers contains the ciphers which use RSA based key exchange,
// which we also disable by default unless a GODEBUG is set.
var rsaKexCiphers = map[uint16]bool{
Expand All @@ -346,21 +350,22 @@ var rsaKexCiphers = map[uint16]bool{
TLS_RSA_WITH_AES_256_GCM_SHA384: true,
}

var defaultCipherSuites []uint16
var defaultCipherSuitesWithRSAKex []uint16
var tls3des = godebug.New("tls3des")

func init() {
defaultCipherSuites = make([]uint16, 0, len(cipherSuitesPreferenceOrder))
defaultCipherSuitesWithRSAKex = make([]uint16, 0, len(cipherSuitesPreferenceOrder))
for _, c := range cipherSuitesPreferenceOrder {
if disabledCipherSuites[c] {
continue
}
if !rsaKexCiphers[c] {
defaultCipherSuites = append(defaultCipherSuites, c)
}
defaultCipherSuitesWithRSAKex = append(defaultCipherSuitesWithRSAKex, c)
}
// tdesCiphers contains 3DES ciphers,
// which we also disable by default unless a GODEBUG is set.
var tdesCiphers = map[uint16]bool{
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: true,
TLS_RSA_WITH_3DES_EDE_CBC_SHA: true,
}

func defaultCipherSuites() []uint16 {
suites := slices.Clone(cipherSuitesPreferenceOrder)
return slices.DeleteFunc(suites, func(c uint16) bool {
return disabledCipherSuites[c] ||
tlsrsakex.Value() != "1" && rsaKexCiphers[c] ||
tls3des.Value() != "1" && tdesCiphers[c]
})
}

// defaultCipherSuitesTLS13 is also the preference order, since there are no
Expand Down
11 changes: 4 additions & 7 deletions src/crypto/tls/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,9 @@ type Config struct {
// If CipherSuites is nil, a safe default list is used. The default cipher
// suites might change over time. In Go 1.22 RSA key exchange based cipher
// suites were removed from the default list, but can be re-added with the
// GODEBUG setting tlsrsakex=1.
// GODEBUG setting tlsrsakex=1. In Go 1.23 3DES cipher suites were removed
// from the default list, but can be re-added with the GODEBUG setting
// tls3des=1.
CipherSuites []uint16

// PreferServerCipherSuites is a legacy field and has no effect.
Expand Down Expand Up @@ -1025,19 +1027,14 @@ func (c *Config) time() time.Time {
return t()
}

var tlsrsakex = godebug.New("tlsrsakex")

func (c *Config) cipherSuites() []uint16 {
if needFIPS() {
return fipsCipherSuites(c)
}
if c.CipherSuites != nil {
return c.CipherSuites
}
if tlsrsakex.Value() == "1" {
return defaultCipherSuitesWithRSAKex
}
return defaultCipherSuites
return defaultCipherSuites()
}

var supportedVersions = []uint16{
Expand Down
4 changes: 4 additions & 0 deletions src/crypto/tls/handshake_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,10 @@ func (hs *clientHandshakeState) pickCipherSuite() error {
tlsrsakex.Value() // ensure godebug is initialized
tlsrsakex.IncNonDefault()
}
if hs.c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] {
tls3des.Value() // ensure godebug is initialized
tls3des.IncNonDefault()
}

hs.c.cipherSuite = hs.suite.id
return nil
Expand Down
4 changes: 4 additions & 0 deletions src/crypto/tls/handshake_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
tlsrsakex.Value() // ensure godebug is initialized
tlsrsakex.IncNonDefault()
}
if c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] {
tls3des.Value() // ensure godebug is initialized
tls3des.IncNonDefault()
}

for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
Expand Down
13 changes: 10 additions & 3 deletions src/crypto/tls/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,16 @@ func TestCipherSuites(t *testing.T) {
t.Errorf("%#04x: suite TLS 1.0-1.2, but SupportedVersions is %v", c.id, cc.SupportedVersions)
}

if cc.Insecure {
if slices.Contains(defaultCipherSuites(), c.id) {
t.Errorf("%#04x: insecure suite in default list", c.id)
}
} else {
if !slices.Contains(defaultCipherSuites(), c.id) {
t.Errorf("%#04x: secure suite not in default list", c.id)
}
}

if got := CipherSuiteName(c.id); got != cc.Name {
t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name)
}
Expand Down Expand Up @@ -1491,9 +1501,6 @@ func TestCipherSuites(t *testing.T) {
if len(cipherSuitesPreferenceOrderNoAES) != len(cipherSuitesPreferenceOrder) {
t.Errorf("cipherSuitesPreferenceOrderNoAES is not the same size as cipherSuitesPreferenceOrder")
}
if len(defaultCipherSuites) >= len(defaultCipherSuitesWithRSAKex) {
t.Errorf("defaultCipherSuitesWithRSAKex should be longer than defaultCipherSuites")
}

// Check that disabled suites are marked insecure.
for _, badSuites := range []map[uint16]bool{disabledCipherSuites, rsaKexCiphers} {
Expand Down
1 change: 1 addition & 0 deletions src/internal/godebugs/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var All = []Info{
{Name: "randautoseed", Package: "math/rand"},
{Name: "tarinsecurepath", Package: "archive/tar"},
{Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"},
{Name: "tls3des", Package: "crypto/tls", Changed: 23, Old: "1"},
{Name: "tlskyber", Package: "crypto/tls", Changed: 23, Old: "0", Opaque: true},
{Name: "tlsmaxrsasize", Package: "crypto/tls"},
{Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"},
Expand Down
4 changes: 2 additions & 2 deletions src/net/http/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ func testResponseSetsTLSConnectionState(t *testing.T, mode testMode) {

c := ts.Client()
tr := c.Transport.(*Transport)
tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}
tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
tr.TLSClientConfig.MaxVersion = tls.VersionTLS12 // to get to pick the cipher suite
tr.Dial = func(netw, addr string) (net.Conn, error) {
return net.Dial(netw, ts.Listener.Addr().String())
Expand All @@ -959,7 +959,7 @@ func testResponseSetsTLSConnectionState(t *testing.T, mode testMode) {
if res.TLS == nil {
t.Fatal("Response didn't set TLS Connection State.")
}
if got, want := res.TLS.CipherSuite, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; got != want {
if got, want := res.TLS.CipherSuite, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; got != want {
t.Errorf("TLS Cipher Suite = %d; want %d", got, want)
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/metrics/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ Below is the full list of supported metrics, ordered lexicographically.
The number of non-default behaviors executed by the crypto/tls
package due to a non-default GODEBUG=tls10server=... setting.
/godebug/non-default-behavior/tls3des:events
The number of non-default behaviors executed by the crypto/tls
package due to a non-default GODEBUG=tls3des=... setting.
/godebug/non-default-behavior/tlsmaxrsasize:events
The number of non-default behaviors executed by the crypto/tls
package due to a non-default GODEBUG=tlsmaxrsasize=... setting.
Expand Down

0 comments on commit 0326605

Please sign in to comment.