0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-23 22:27:38 -05:00

tls: Prefer ChaCha20 if AES-NI instruction set is unavailable (#1675)

Fixes #1674
This commit is contained in:
Andrew Steinborn 2017-05-17 12:45:17 -04:00 committed by Matt Holt
parent 8d3f336971
commit b0cf3f0d2d
3 changed files with 52 additions and 18 deletions

View file

@ -9,6 +9,7 @@ import (
"net/url" "net/url"
"strings" "strings"
"github.com/codahale/aesnicheck"
"github.com/mholt/caddy" "github.com/mholt/caddy"
"github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme"
) )
@ -294,7 +295,7 @@ func (c *Config) buildStandardTLSConfig() error {
// default cipher suites // default cipher suites
if len(config.CipherSuites) == 0 { if len(config.CipherSuites) == 0 {
config.CipherSuites = defaultCiphers config.CipherSuites = getPreferredDefaultCiphers()
} }
// for security, ensure TLS_FALLBACK_SCSV is always included first // for security, ensure TLS_FALLBACK_SCSV is always included first
@ -380,7 +381,7 @@ func RegisterConfigGetter(serverType string, fn ConfigGetter) {
func SetDefaultTLSParams(config *Config) { func SetDefaultTLSParams(config *Config) {
// If no ciphers provided, use default list // If no ciphers provided, use default list
if len(config.Ciphers) == 0 { if len(config.Ciphers) == 0 {
config.Ciphers = defaultCiphers config.Ciphers = getPreferredDefaultCiphers()
} }
// Not a cipher suite, but still important for mitigating protocol downgrade attacks // Not a cipher suite, but still important for mitigating protocol downgrade attacks
@ -464,6 +465,35 @@ var defaultCiphers = []uint16{
tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA,
} }
// List of ciphers we should prefer if native AESNI support is missing
var defaultCiphersNonAESNI = []uint16{
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
}
// getPreferredDefaultCiphers returns an appropriate cipher suite to use, depending on
// the hardware support available for AES-NI.
//
// See https://github.com/mholt/caddy/issues/1674
func getPreferredDefaultCiphers() []uint16 {
if aesnicheck.HasAESNI() {
return defaultCiphers
}
// Return a cipher suite that prefers ChaCha20
return defaultCiphersNonAESNI
}
// Map of supported curves // Map of supported curves
// https://golang.org/pkg/crypto/tls/#CurveID // https://golang.org/pkg/crypto/tls/#CurveID
var supportedCurvesMap = map[string]tls.CurveID{ var supportedCurvesMap = map[string]tls.CurveID{

View file

@ -6,6 +6,8 @@ import (
"net/url" "net/url"
"reflect" "reflect"
"testing" "testing"
"github.com/codahale/aesnicheck"
) )
func TestConvertTLSConfigProtocolVersions(t *testing.T) { func TestConvertTLSConfigProtocolVersions(t *testing.T) {
@ -60,10 +62,11 @@ func TestConvertTLSConfigCipherSuites(t *testing.T) {
{Enabled: true, Ciphers: nil}, {Enabled: true, Ciphers: nil},
} }
defaultCiphersExpected := getPreferredDefaultCiphers()
expectedCiphers := [][]uint16{ expectedCiphers := [][]uint16{
{tls.TLS_FALLBACK_SCSV, 0xc02c, 0xc030}, {tls.TLS_FALLBACK_SCSV, 0xc02c, 0xc030},
{tls.TLS_FALLBACK_SCSV, 0xc012, 0xc030, 0xc00a}, {tls.TLS_FALLBACK_SCSV, 0xc012, 0xc030, 0xc00a},
append([]uint16{tls.TLS_FALLBACK_SCSV}, defaultCiphers...), append([]uint16{tls.TLS_FALLBACK_SCSV}, defaultCiphersExpected...),
} }
for i, config := range configs { for i, config := range configs {
@ -79,6 +82,21 @@ func TestConvertTLSConfigCipherSuites(t *testing.T) {
} }
} }
func TestGetPreferredDefaultCiphers(t *testing.T) {
expectedCiphers := defaultCiphers
if !aesnicheck.HasAESNI() {
expectedCiphers = defaultCiphersNonAESNI
}
// Ensure ordering is correct and ciphers are what we expected.
result := getPreferredDefaultCiphers()
for i, actual := range result {
if actual != expectedCiphers[i] {
t.Errorf("Expected cipher in position %d to be %0x, got %0x", i, expectedCiphers[i], actual)
}
}
}
func TestStorageForNoURL(t *testing.T) { func TestStorageForNoURL(t *testing.T) {
c := &Config{} c := &Config{}
if _, err := c.StorageFor(""); err == nil { if _, err := c.StorageFor(""); err == nil {

View file

@ -58,21 +58,7 @@ func TestSetupParseBasic(t *testing.T) {
} }
// Cipher checks // Cipher checks
expectedCiphers := []uint16{ expectedCiphers := append([]uint16{tls.TLS_FALLBACK_SCSV}, getPreferredDefaultCiphers()...)
tls.TLS_FALLBACK_SCSV,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
}
// Ensure count is correct (plus one for TLS_FALLBACK_SCSV) // Ensure count is correct (plus one for TLS_FALLBACK_SCSV)
if len(cfg.Ciphers) != len(expectedCiphers) { if len(cfg.Ciphers) != len(expectedCiphers) {