diff --git a/caddytls/config.go b/caddytls/config.go index f73cbde39..e30d2a1d3 100644 --- a/caddytls/config.go +++ b/caddytls/config.go @@ -379,8 +379,8 @@ func MakeTLSConfig(configs []*Config) (*tls.Config, error) { config.CipherSuites = defaultCiphers } - // For security, ensure TLS_FALLBACK_SCSV is always included - if config.CipherSuites[0] != tls.TLS_FALLBACK_SCSV { + // For security, ensure TLS_FALLBACK_SCSV is always included first + if len(config.CipherSuites) == 0 || config.CipherSuites[0] != tls.TLS_FALLBACK_SCSV { config.CipherSuites = append([]uint16{tls.TLS_FALLBACK_SCSV}, config.CipherSuites...) } diff --git a/caddytls/config_test.go b/caddytls/config_test.go index be7c204a2..2cdadce5d 100644 --- a/caddytls/config_test.go +++ b/caddytls/config_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestMakeTLSConfig(t *testing.T) { +func TestMakeTLSConfigProtocolVersions(t *testing.T) { // same min and max protocol versions configs := []*Config{ { @@ -29,6 +29,68 @@ func TestMakeTLSConfig(t *testing.T) { } } +func TestMakeTLSConfigPreferServerCipherSuites(t *testing.T) { + // prefer server cipher suites + configs := []*Config{{Enabled: true, PreferServerCipherSuites: true}} + result, err := MakeTLSConfig(configs) + if err != nil { + t.Fatalf("Did not expect an error, but got %v", err) + } + if got, want := result.PreferServerCipherSuites, true; got != want { + t.Errorf("Expected PreferServerCipherSuites==%v but got %v", want, got) + } +} + +func TestMakeTLSConfigTLSEnabledDisabled(t *testing.T) { + // verify handling when Enabled is true and false + configs := []*Config{ + {Enabled: true}, + {Enabled: false}, + } + _, err := MakeTLSConfig(configs) + if err == nil { + t.Fatalf("Expected an error, but got %v", err) + } + + // verify that when disabled, a nil pair is returned + configs = []*Config{{}, {}} + result, err := MakeTLSConfig(configs) + if err != nil { + t.Errorf("Did not expect an error, but got %v", err) + } + if result != nil { + t.Errorf("Expected a nil *tls.Config result, got %+v", result) + } +} + +func TestMakeTLSConfigCipherSuites(t *testing.T) { + // ensure cipher suites are unioned and + // that TLS_FALLBACK_SCSV is prepended + configs := []*Config{ + {Enabled: true, Ciphers: []uint16{0xc02c, 0xc030}}, + {Enabled: true, Ciphers: []uint16{0xc012, 0xc030, 0xc00a}}, + } + result, err := MakeTLSConfig(configs) + if err != nil { + t.Fatalf("Did not expect an error, but got %v", err) + } + expected := []uint16{tls.TLS_FALLBACK_SCSV, 0xc02c, 0xc030, 0xc012, 0xc00a} + if !reflect.DeepEqual(result.CipherSuites, expected) { + t.Errorf("Expected ciphers %v but got %v", expected, result.CipherSuites) + } + + // use default suites if none specified + configs = []*Config{{Enabled: true}} + result, err = MakeTLSConfig(configs) + if err != nil { + t.Fatalf("Did not expect an error, but got %v", err) + } + expected = append([]uint16{tls.TLS_FALLBACK_SCSV}, defaultCiphers...) + if !reflect.DeepEqual(result.CipherSuites, expected) { + t.Errorf("Expected default ciphers %v but got %v", expected, result.CipherSuites) + } +} + func TestStorageForNoURL(t *testing.T) { c := &Config{} if _, err := c.StorageFor(""); err == nil {