mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/tls: make cipher suite preference ordering automatic
We now have a (well, two, depending on AES hardware support) universal
cipher suite preference order, based on their security and performance.
Peer and application lists are now treated as filters (and AES hardware
support hints) that are applied to this universal order.
This removes a complex and nuanced decision from the application's
responsibilities, one which we are better equipped to make and which
applications usually don't need to have an opinion about. It also lets
us worry less about what suites we support or enable, because we can be
confident that bad ones won't be selected over good ones.
This also moves 3DES suites to InsecureCipherSuites(), even if they are
not disabled by default. Just because we can keep them as a last resort
it doesn't mean they are secure. Thankfully we had not promised that
Insecure means disabled by default.
Notable test changes:
- TestCipherSuiteCertPreferenceECDSA was testing that we'd pick the
right certificate regardless of CipherSuite ordering, which is now
completely ignored, as tested by TestCipherSuitePreference. Removed.
- The openssl command of TestHandshakeServerExportKeyingMaterial was
broken for TLS 1.0 in CL 262857, but its golden file was not
regenerated, so the test kept passing. It now broke because the
selected suite from the ones in the golden file changed.
- In TestAESCipherReordering, "server strongly prefers AES-GCM" is
removed because there is no way for a server to express a strong
preference anymore; "client prefers AES-GCM and AES-CBC over ChaCha"
switched to ChaCha20 when the server lacks AES hardware; and finally
"client supports multiple AES-GCM" changed to always prefer AES-128
per the universal preference list.
* this is going back on an explicit decision from CL 262857, and
while that client order is weird and does suggest a strong dislike
for ChaCha20, we have a strong dislike for software AES, so it
didn't feel worth making the logic more complex
- All Client-* golden files had to be regenerated because the
ClientHello cipher suites have changed.
(Even when Config.CipherSuites was limited to one suite, the TLS 1.3
default order changed.)
Fixes #45430
Fixes #41476 (as 3DES is now always the last resort)
Change-Id: If5f5d356c0f8d1f1c7542fb06644a478d6bad1e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/314609
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
parent
02ce411821
commit
9d0819b27c
68 changed files with 3753 additions and 3814 deletions
|
|
@ -397,30 +397,30 @@ func TestVersion(t *testing.T) {
|
|||
|
||||
func TestCipherSuitePreference(t *testing.T) {
|
||||
serverConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
|
||||
Certificates: testConfig.Certificates,
|
||||
MaxVersion: VersionTLS11,
|
||||
MaxVersion: VersionTLS12,
|
||||
GetConfigForClient: func(chi *ClientHelloInfo) (*Config, error) {
|
||||
if chi.CipherSuites[0] != TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {
|
||||
t.Error("the advertised order should not depend on Config.CipherSuites")
|
||||
}
|
||||
if len(chi.CipherSuites) != 2+len(defaultCipherSuitesTLS13) {
|
||||
t.Error("the advertised TLS 1.2 suites should be filtered by Config.CipherSuites")
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
clientConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA},
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
state, _, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
if state.CipherSuite != TLS_RSA_WITH_AES_128_CBC_SHA {
|
||||
// By default the server should use the client's preference.
|
||||
t.Fatalf("Client's preference was not used, got %x", state.CipherSuite)
|
||||
}
|
||||
|
||||
serverConfig.PreferServerCipherSuites = true
|
||||
state, _, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
if state.CipherSuite != TLS_RSA_WITH_RC4_128_SHA {
|
||||
t.Fatalf("Server's preference was not used, got %x", state.CipherSuite)
|
||||
if state.CipherSuite != TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {
|
||||
t.Error("the preference order should not depend on Config.CipherSuites")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1050,37 +1050,6 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
|
|||
testClientHelloFailure(t, serverConfig, clientHello, "no certificates")
|
||||
}
|
||||
|
||||
// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
|
||||
// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
|
||||
func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
|
||||
config := testConfig.Clone()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
|
||||
config.PreferServerCipherSuites = true
|
||||
|
||||
test := &serverTest{
|
||||
name: "CipherSuiteCertPreferenceRSA",
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
||||
config = testConfig.Clone()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
|
||||
config.Certificates = []Certificate{
|
||||
{
|
||||
Certificate: [][]byte{testECDSACertificate},
|
||||
PrivateKey: testECDSAPrivateKey,
|
||||
},
|
||||
}
|
||||
config.BuildNameToCertificate()
|
||||
config.PreferServerCipherSuites = true
|
||||
|
||||
test = &serverTest{
|
||||
name: "CipherSuiteCertPreferenceECDSA",
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
|
||||
func TestServerResumption(t *testing.T) {
|
||||
sessionFilePath := tempFile("")
|
||||
defer os.Remove(sessionFilePath)
|
||||
|
|
@ -1178,7 +1147,7 @@ func TestFallbackSCSV(t *testing.T) {
|
|||
func TestHandshakeServerExportKeyingMaterial(t *testing.T) {
|
||||
test := &serverTest{
|
||||
name: "ExportKeyingMaterial",
|
||||
command: []string{"openssl", "s_client", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
|
||||
command: []string{"openssl", "s_client", "-cipher", "ECDHE-RSA-AES256-SHA", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
|
||||
config: testConfig.Clone(),
|
||||
validate: func(state ConnectionState) error {
|
||||
if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil {
|
||||
|
|
@ -1699,15 +1668,14 @@ func TestMultipleCertificates(t *testing.T) {
|
|||
|
||||
func TestAESCipherReordering(t *testing.T) {
|
||||
currentAESSupport := hasAESGCMHardwareSupport
|
||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }()
|
||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport }()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clientCiphers []uint16
|
||||
serverHasAESGCM bool
|
||||
preferServerCipherSuites bool
|
||||
serverCiphers []uint16
|
||||
expectedCipher uint16
|
||||
name string
|
||||
clientCiphers []uint16
|
||||
serverHasAESGCM bool
|
||||
serverCiphers []uint16
|
||||
expectedCipher uint16
|
||||
}{
|
||||
{
|
||||
name: "server has hardware AES, client doesn't (pick ChaCha)",
|
||||
|
|
@ -1716,25 +1684,8 @@ func TestAESCipherReordering(t *testing.T) {
|
|||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
},
|
||||
serverHasAESGCM: true,
|
||||
preferServerCipherSuites: true,
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
{
|
||||
name: "server strongly prefers AES-GCM, client doesn't (pick AES-GCM)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
},
|
||||
serverHasAESGCM: true,
|
||||
preferServerCipherSuites: true,
|
||||
serverCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
},
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
serverHasAESGCM: true,
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES-GCM, server doesn't have hardware AES (pick ChaCha)",
|
||||
|
|
@ -1778,14 +1729,14 @@ func TestAESCipherReordering(t *testing.T) {
|
|||
expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES-GCM and AES-CBC over ChaCha, server doesn't have hardware AES (pick AES-GCM)",
|
||||
name: "client prefers AES-GCM and AES-CBC over ChaCha, server doesn't have hardware AES (pick ChaCha)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
serverHasAESGCM: false,
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES-GCM over ChaCha and sends GREASE, server doesn't have hardware AES (pick ChaCha)",
|
||||
|
|
@ -1799,7 +1750,7 @@ func TestAESCipherReordering(t *testing.T) {
|
|||
expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
{
|
||||
name: "client supports multiple AES-GCM, server doesn't have hardware AES and doesn't support ChaCha (pick corrent AES-GCM)",
|
||||
name: "client supports multiple AES-GCM, server doesn't have hardware AES and doesn't support ChaCha (AES-GCM)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
|
|
@ -1810,19 +1761,30 @@ func TestAESCipherReordering(t *testing.T) {
|
|||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES-GCM, server has hardware but doesn't support AES (pick ChaCha)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
},
|
||||
serverHasAESGCM: true,
|
||||
serverCiphers: []uint16{
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
hasAESGCMHardwareSupport = tc.serverHasAESGCM
|
||||
initDefaultCipherSuites()
|
||||
hs := &serverHandshakeState{
|
||||
c: &Conn{
|
||||
config: &Config{
|
||||
PreferServerCipherSuites: tc.preferServerCipherSuites,
|
||||
CipherSuites: tc.serverCiphers,
|
||||
CipherSuites: tc.serverCiphers,
|
||||
},
|
||||
vers: VersionTLS12,
|
||||
},
|
||||
|
|
@ -1847,16 +1809,15 @@ func TestAESCipherReordering(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAESCipherReordering13(t *testing.T) {
|
||||
func TestAESCipherReorderingTLS13(t *testing.T) {
|
||||
currentAESSupport := hasAESGCMHardwareSupport
|
||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }()
|
||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport }()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clientCiphers []uint16
|
||||
serverHasAESGCM bool
|
||||
preferServerCipherSuites bool
|
||||
expectedCipher uint16
|
||||
name string
|
||||
clientCiphers []uint16
|
||||
serverHasAESGCM bool
|
||||
expectedCipher uint16
|
||||
}{
|
||||
{
|
||||
name: "server has hardware AES, client doesn't (pick ChaCha)",
|
||||
|
|
@ -1864,9 +1825,8 @@ func TestAESCipherReordering13(t *testing.T) {
|
|||
TLS_CHACHA20_POLY1305_SHA256,
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
},
|
||||
serverHasAESGCM: true,
|
||||
preferServerCipherSuites: true,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
serverHasAESGCM: true,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
{
|
||||
name: "neither server nor client have hardware AES (pick ChaCha)",
|
||||
|
|
@ -1874,37 +1834,25 @@ func TestAESCipherReordering13(t *testing.T) {
|
|||
TLS_CHACHA20_POLY1305_SHA256,
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
},
|
||||
serverHasAESGCM: false,
|
||||
preferServerCipherSuites: true,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
serverHasAESGCM: false,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES, server doesn't have hardware, prefer server ciphers (pick ChaCha)",
|
||||
name: "client prefers AES, server doesn't have hardware (pick ChaCha)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
serverHasAESGCM: false,
|
||||
preferServerCipherSuites: true,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
serverHasAESGCM: false,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES and sends GREASE, server doesn't have hardware, prefer server ciphers (pick ChaCha)",
|
||||
name: "client prefers AES and sends GREASE, server doesn't have hardware (pick ChaCha)",
|
||||
clientCiphers: []uint16{
|
||||
0x0A0A, // GREASE value
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
serverHasAESGCM: false,
|
||||
preferServerCipherSuites: true,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
{
|
||||
name: "client prefers AES, server doesn't (pick ChaCha)",
|
||||
clientCiphers: []uint16{
|
||||
TLS_AES_128_GCM_SHA256,
|
||||
TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
serverHasAESGCM: false,
|
||||
expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
|
|
@ -1932,13 +1880,10 @@ func TestAESCipherReordering13(t *testing.T) {
|
|||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
hasAESGCMHardwareSupport = tc.serverHasAESGCM
|
||||
initDefaultCipherSuites()
|
||||
hs := &serverHandshakeStateTLS13{
|
||||
c: &Conn{
|
||||
config: &Config{
|
||||
PreferServerCipherSuites: tc.preferServerCipherSuites,
|
||||
},
|
||||
vers: VersionTLS13,
|
||||
config: &Config{},
|
||||
vers: VersionTLS13,
|
||||
},
|
||||
clientHello: &clientHelloMsg{
|
||||
cipherSuites: tc.clientCiphers,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue