diff --git a/state_impl.go b/state_impl.go index 1dff295..bad27df 100644 --- a/state_impl.go +++ b/state_impl.go @@ -476,6 +476,20 @@ func applyTLSCiphers(tlsConfig *tls.Config, ciphers string) { if tlsConfig == nil || strings.TrimSpace(ciphers) == "" { return } + parts := splitTLSConfigList(ciphers) + for _, part := range parts { + if id, ok := lookupTLSCipherSuite(part); ok { + tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, id) + } + } +} + +func lookupTLSCipherSuite(value string) (uint16, bool) { + name := strings.ToLower(strings.TrimSpace(value)) + if name == "" { + return 0, false + } + allowed := map[string]uint16{} for _, suite := range tls.CipherSuites() { allowed[strings.ToLower(suite.Name)] = suite.ID @@ -483,12 +497,36 @@ func applyTLSCiphers(tlsConfig *tls.Config, ciphers string) { for _, suite := range tls.InsecureCipherSuites() { allowed[strings.ToLower(suite.Name)] = suite.ID } - parts := splitTLSConfigList(ciphers) - for _, part := range parts { - if id, ok := allowed[strings.ToLower(part)]; ok { - tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, id) + if id, ok := allowed[name]; ok { + return id, true + } + + if alias, ok := tlsCipherSuiteAliases[name]; ok { + if id, ok := allowed[strings.ToLower(alias)]; ok { + return id, true } } + + return 0, false +} + +var tlsCipherSuiteAliases = map[string]string{ + "ecdhe-ecdsa-aes128-gcm-sha256": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "ecdhe-rsa-aes128-gcm-sha256": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "ecdhe-ecdsa-aes256-gcm-sha384": "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "ecdhe-rsa-aes256-gcm-sha384": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "ecdhe-ecdsa-chacha20-poly1305": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "ecdhe-rsa-chacha20-poly1305": "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "dhe-rsa-aes128-gcm-sha256": "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "dhe-rsa-aes256-gcm-sha384": "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "aes128-gcm-sha256": "TLS_RSA_WITH_AES_128_GCM_SHA256", + "aes256-gcm-sha384": "TLS_RSA_WITH_AES_256_GCM_SHA384", + "aes128-sha": "TLS_RSA_WITH_AES_128_CBC_SHA", + "aes256-sha": "TLS_RSA_WITH_AES_256_CBC_SHA", + "ecdhe-ecdsa-aes128-sha256": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "ecdhe-rsa-aes128-sha256": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "ecdhe-ecdsa-aes256-sha384": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "ecdhe-rsa-aes256-sha384": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", } func splitTLSConfigList(value string) []string { diff --git a/tls_test.go b/tls_test.go new file mode 100644 index 0000000..8488563 --- /dev/null +++ b/tls_test.go @@ -0,0 +1,36 @@ +package proxy + +import ( + "crypto/tls" + "testing" +) + +func TestTLS_applyTLSCiphers_Good(t *testing.T) { + cfg := &tls.Config{} + + applyTLSCiphers(cfg, "ECDHE-RSA-AES128-GCM-SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256") + + if len(cfg.CipherSuites) != 2 { + t.Fatalf("expected two recognised cipher suites, got %d", len(cfg.CipherSuites)) + } +} + +func TestTLS_applyTLSCiphers_Bad(t *testing.T) { + cfg := &tls.Config{} + + applyTLSCiphers(cfg, "made-up-cipher-one:made-up-cipher-two") + + if len(cfg.CipherSuites) != 0 { + t.Fatalf("expected unknown cipher names to be ignored, got %#v", cfg.CipherSuites) + } +} + +func TestTLS_applyTLSCiphers_Ugly(t *testing.T) { + cfg := &tls.Config{} + + applyTLSCiphers(cfg, " aes128-sha | ECDHE-RSA-AES256-GCM-SHA384 ; tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 ") + + if len(cfg.CipherSuites) != 3 { + t.Fatalf("expected mixed separators and casing to be accepted, got %d", len(cfg.CipherSuites)) + } +}