From 0d97132056ac751d2841e35466225fbff6ad727e Mon Sep 17 00:00:00 2001 From: Krasimir Angelov Date: Thu, 16 May 2019 09:48:38 +0000 Subject: Disable 3DES and other insecure cipher suites Supported cipher suites: tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 Closes https://gitlab.com/gitlab-org/gitlab-pages/issues/150. --- acceptance_test.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ app.go | 2 +- app_config.go | 1 + helpers_test.go | 12 ++++++++++ main.go | 3 +++ server.go | 15 +++++++++++- 6 files changed, 99 insertions(+), 2 deletions(-) diff --git a/acceptance_test.go b/acceptance_test.go index 55a83881..f68b31ef 100644 --- a/acceptance_test.go +++ b/acceptance_test.go @@ -1057,3 +1057,71 @@ func TestAccessControl(t *testing.T) { }) } } + +func TestAcceptsSupportedCiphers(t *testing.T) { + skipUnlessEnabled(t) + teardown := RunPagesProcess(t, *pagesBinary, listeners, "") + defer teardown() + + ciphers := []uint16{ + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + } + client, cleanup := ClientWithCiphers(ciphers) + defer cleanup() + + rsp, err := client.Get(httpsListener.URL("/")) + + if rsp != nil { + rsp.Body.Close() + } + + require.NoError(t, err) +} + +func TestRejectsUnsupportedCiphers(t *testing.T) { + skipUnlessEnabled(t) + teardown := RunPagesProcess(t, *pagesBinary, listeners, "") + defer teardown() + + ciphers := []uint16{ + tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + } + client, cleanup := ClientWithCiphers(ciphers) + defer cleanup() + + rsp, err := client.Get(httpsListener.URL("/")) + + if rsp != nil { + rsp.Body.Close() + } + + require.Error(t, err) + require.Nil(t, rsp) +} + +func TestEnableInsecureCiphers(t *testing.T) { + skipUnlessEnabled(t) + teardown := RunPagesProcess(t, *pagesBinary, listeners, "", "-insecure-ciphers") + defer teardown() + + ciphers := []uint16{ + tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + } + client, cleanup := ClientWithCiphers(ciphers) + defer cleanup() + + rsp, err := client.Get(httpsListener.URL("/")) + + if rsp != nil { + rsp.Body.Close() + } + + require.NoError(t, err) +} diff --git a/app.go b/app.go index c25bcf37..7d7ca9a2 100644 --- a/app.go +++ b/app.go @@ -258,7 +258,7 @@ func (a *theApp) Run() { wg.Add(1) go func(fd uintptr) { defer wg.Done() - err := listenAndServeTLS(fd, a.RootCertificate, a.RootKey, a.ServeHTTP, a.ServeTLS, a.HTTP2, limiter) + err := listenAndServeTLS(fd, a.RootCertificate, a.RootKey, a.ServeHTTP, a.ServeTLS, a.HTTP2, a.InsecureCiphers, limiter) if err != nil { fatal(err) } diff --git a/app_config.go b/app_config.go index 9ff26b6b..b2b885f9 100644 --- a/app_config.go +++ b/app_config.go @@ -17,6 +17,7 @@ type appConfig struct { ListenMetrics uintptr ListenAdminUnix uintptr ListenAdminHTTPS uintptr + InsecureCiphers bool HTTP2 bool RedirectHTTP bool diff --git a/helpers_test.go b/helpers_test.go index bf61b7a4..2e565300 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -329,6 +329,18 @@ func GetRedirectPageWithCookie(t *testing.T, spec ListenSpec, host, urlsuffix st return TestHTTPSClient.Transport.RoundTrip(req) } +func ClientWithCiphers(ciphers []uint16) (*http.Client, func()) { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: TestCertPool, + CipherSuites: ciphers, + }, + } + client := &http.Client{Transport: tr} + + return client, tr.CloseIdleConnections +} + func waitForRoundtrips(t *testing.T, listeners []ListenSpec, timeout time.Duration) { nListening := 0 start := time.Now() diff --git a/main.go b/main.go index 126ad69e..170e0e7e 100644 --- a/main.go +++ b/main.go @@ -51,6 +51,7 @@ var ( clientSecret = flag.String("auth-client-secret", "", "GitLab application Client Secret") redirectURI = flag.String("auth-redirect-uri", "", "GitLab application redirect URI") maxConns = flag.Uint("max-conns", 5000, "Limit on the number of concurrent connections to the HTTP, HTTPS or proxy listeners") + insecureCiphers = flag.Bool("insecure-ciphers", false, "Use default list of cipher suites, may contain insecure ones like 3DES and RC4") disableCrossOriginRequests = flag.Bool("disable-cross-origin-requests", false, "Disable cross-origin requests") @@ -82,6 +83,7 @@ func configFromFlags() appConfig { config.LogFormat = *logFormat config.LogVerbose = *logVerbose config.MaxConns = int(*maxConns) + config.InsecureCiphers = *insecureCiphers for _, file := range []struct { contents *[]byte @@ -194,6 +196,7 @@ func appMain() { "default-config-filename": flag.DefaultConfigFlagname, "disable-cross-origin-requests": *disableCrossOriginRequests, "domain": config.Domain, + "insecure-ciphers": config.InsecureCiphers, "listen-http": strings.Join(listenHTTP, ","), "listen-https": strings.Join(listenHTTPS, ","), "listen-proxy": strings.Join(listenProxy, ","), diff --git a/server.go b/server.go index 3a80e797..79268238 100644 --- a/server.go +++ b/server.go @@ -25,6 +25,15 @@ type keepAliveSetter interface { SetKeepAlivePeriod(time.Duration) error } +var preferredCipherSuites = []uint16{ + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +} + func (ln *keepAliveListener) Accept() (net.Conn, error) { conn, err := ln.Listener.Accept() if err != nil { @@ -65,7 +74,7 @@ func listenAndServe(fd uintptr, handler http.HandlerFunc, useHTTP2 bool, tlsConf return server.Serve(&keepAliveListener{l}) } -func listenAndServeTLS(fd uintptr, cert, key []byte, handler http.HandlerFunc, tlsHandler tlsHandlerFunc, useHTTP2 bool, limiter *netutil.Limiter) error { +func listenAndServeTLS(fd uintptr, cert, key []byte, handler http.HandlerFunc, tlsHandler tlsHandlerFunc, useHTTP2 bool, insecureCiphers bool, limiter *netutil.Limiter) error { certificate, err := tls.X509KeyPair(cert, key) if err != nil { return err @@ -76,5 +85,9 @@ func listenAndServeTLS(fd uintptr, cert, key []byte, handler http.HandlerFunc, t tlsConfig.Certificates = []tls.Certificate{ certificate, } + if !insecureCiphers { + tlsConfig.PreferServerCipherSuites = true + tlsConfig.CipherSuites = preferredCipherSuites + } return listenAndServe(fd, handler, useHTTP2, tlsConfig, limiter) } -- cgit v1.2.3