summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorDaniel Schalla <daniel@schalla.me>2018-10-16 16:51:46 +0200
committerChristopher Speller <crspeller@gmail.com>2018-10-16 07:51:46 -0700
commit557fd9ea187b1279b43ff63b94fedf2320aa3351 (patch)
tree463fdbd5aefba8f94a61fb1338bf5e7bd123a5f6 /app
parentcedf6488e4d4d66c186facb4253513b1f7e775c6 (diff)
downloadchat-557fd9ea187b1279b43ff63b94fedf2320aa3351.tar.gz
chat-557fd9ea187b1279b43ff63b94fedf2320aa3351.tar.bz2
chat-557fd9ea187b1279b43ff63b94fedf2320aa3351.zip
Set default ciphers, set tls 1.2 via config, set curve prefs (#9315)
Config Checks at StartUp Part1 Config Checks; Tests for TLS Server HSTS header implementation + tests make gofmt happy with new go version... make gofmt happy with new go version #2... fix logic bug fix typo Fix unnecessary code block
Diffstat (limited to 'app')
-rw-r--r--app/server.go65
-rw-r--r--app/server_test.go147
2 files changed, 204 insertions, 8 deletions
diff --git a/app/server.go b/app/server.go
index debb6764f..b95059c84 100644
--- a/app/server.go
+++ b/app/server.go
@@ -46,7 +46,7 @@ type Server struct {
didFinishListen chan struct{}
}
-var corsAllowedMethods []string = []string{
+var corsAllowedMethods = []string{
"POST",
"GET",
"OPTIONS",
@@ -199,26 +199,75 @@ func (a *App) StartServer() error {
go func() {
var err error
if *a.Config().ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
- if *a.Config().ServiceSettings.UseLetsEncrypt {
- tlsConfig := &tls.Config{
- GetCertificate: m.GetCertificate,
+ tlsConfig := &tls.Config{
+ PreferServerCipherSuites: true,
+ CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
+ }
+
+ switch *a.Config().ServiceSettings.TLSMinVer {
+ case "1.0":
+ tlsConfig.MinVersion = tls.VersionTLS10
+ case "1.1":
+ tlsConfig.MinVersion = tls.VersionTLS11
+ default:
+ tlsConfig.MinVersion = tls.VersionTLS12
+ }
+
+ defaultCiphers := []uint16{
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ }
+
+ if len(a.Config().ServiceSettings.TLSOverwriteCiphers) == 0 {
+ tlsConfig.CipherSuites = defaultCiphers
+ } else {
+ var cipherSuites []uint16
+ for _, cipher := range a.Config().ServiceSettings.TLSOverwriteCiphers {
+ value, ok := model.ServerTLSSupportedCiphers[cipher]
+
+ if !ok {
+ mlog.Warn("Unsupported cipher passed", mlog.String("cipher", cipher))
+ continue
+ }
+
+ cipherSuites = append(cipherSuites, value)
}
- tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
+ if len(cipherSuites) == 0 {
+ mlog.Warn("No supported ciphers passed, fallback to default cipher suite")
+ cipherSuites = defaultCiphers
+ }
+
+ tlsConfig.CipherSuites = cipherSuites
+ }
+
+ certFile := ""
+ keyFile := ""
- a.Srv.Server.TLSConfig = tlsConfig
- err = a.Srv.Server.ServeTLS(listener, "", "")
+ if *a.Config().ServiceSettings.UseLetsEncrypt {
+ tlsConfig.GetCertificate = m.GetCertificate
+ tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
} else {
- err = a.Srv.Server.ServeTLS(listener, *a.Config().ServiceSettings.TLSCertFile, *a.Config().ServiceSettings.TLSKeyFile)
+ certFile = *a.Config().ServiceSettings.TLSCertFile
+ keyFile = *a.Config().ServiceSettings.TLSKeyFile
}
+
+ a.Srv.Server.TLSConfig = tlsConfig
+ err = a.Srv.Server.ServeTLS(listener, certFile, keyFile)
} else {
err = a.Srv.Server.Serve(listener)
}
+
if err != nil && err != http.ErrServerClosed {
mlog.Critical(fmt.Sprintf("Error starting server, err:%v", err))
time.Sleep(time.Second)
}
+
close(a.Srv.didFinishListen)
}()
diff --git a/app/server_test.go b/app/server_test.go
index 94771a44e..4a355e113 100644
--- a/app/server_test.go
+++ b/app/server_test.go
@@ -4,6 +4,12 @@
package app
import (
+ "crypto/tls"
+ "github.com/mattermost/mattermost-server/utils"
+ "net/http"
+ "path"
+ "strconv"
+ "strings"
"testing"
"github.com/mattermost/mattermost-server/model"
@@ -16,6 +22,10 @@ func TestStartServerSuccess(t *testing.T) {
a.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ListenAddress = ":0" })
serverErr := a.StartServer()
+
+ client := &http.Client{}
+ checkEndpoint(t, client, "http://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
a.Shutdown()
require.NoError(t, serverErr)
}
@@ -48,3 +58,140 @@ func TestStartServerPortUnavailable(t *testing.T) {
a.Shutdown()
require.Error(t, serverErr)
}
+
+func TestStartServerTLSSuccess(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ testDir, _ := utils.FindDir("tests")
+ a.UpdateConfig(func(cfg *model.Config) {
+ *cfg.ServiceSettings.ListenAddress = ":0"
+ *cfg.ServiceSettings.ConnectionSecurity = "TLS"
+ *cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
+ *cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
+ })
+ serverErr := a.StartServer()
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ }
+
+ client := &http.Client{Transport: tr}
+ checkEndpoint(t, client, "https://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
+ a.Shutdown()
+ require.NoError(t, serverErr)
+}
+
+func TestStartServerTLSVersion(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ testDir, _ := utils.FindDir("tests")
+ a.UpdateConfig(func(cfg *model.Config) {
+ *cfg.ServiceSettings.ListenAddress = ":0"
+ *cfg.ServiceSettings.ConnectionSecurity = "TLS"
+ *cfg.ServiceSettings.TLSMinVer = "1.2"
+ *cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
+ *cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
+ })
+ serverErr := a.StartServer()
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ MaxVersion: tls.VersionTLS11,
+ },
+ }
+
+ client := &http.Client{Transport: tr}
+ err = checkEndpoint(t, client, "https://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
+ if !strings.Contains(err.Error(), "remote error: tls: protocol version not supported") {
+ t.Errorf("Expected protocol version error, got %s", err)
+ }
+
+ client.Transport = &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+
+ err = checkEndpoint(t, client, "https://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
+ if err != nil {
+ t.Errorf("Expected nil, got %s", err)
+ }
+
+ a.Shutdown()
+ require.NoError(t, serverErr)
+}
+
+func TestStartServerTLSOverwriteCipher(t *testing.T) {
+ a, err := New()
+ require.NoError(t, err)
+
+ testDir, _ := utils.FindDir("tests")
+ a.UpdateConfig(func(cfg *model.Config) {
+ *cfg.ServiceSettings.ListenAddress = ":0"
+ *cfg.ServiceSettings.ConnectionSecurity = "TLS"
+ cfg.ServiceSettings.TLSOverwriteCiphers = []string{
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ }
+ *cfg.ServiceSettings.TLSKeyFile = path.Join(testDir, "tls_test_key.pem")
+ *cfg.ServiceSettings.TLSCertFile = path.Join(testDir, "tls_test_cert.pem")
+ })
+ serverErr := a.StartServer()
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ CipherSuites: []uint16{
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ },
+ },
+ }
+
+ client := &http.Client{Transport: tr}
+ err = checkEndpoint(t, client, "https://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
+ if !strings.Contains(err.Error(), "remote error: tls: handshake failure") {
+ t.Errorf("Expected protocol version error, got %s", err)
+ }
+
+ client.Transport = &http.Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ CipherSuites: []uint16{
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ }
+
+ err = checkEndpoint(t, client, "https://localhost:" + strconv.Itoa(a.Srv.ListenAddr.Port) + "/", http.StatusNotFound)
+
+ if err != nil {
+ t.Errorf("Expected nil, got %s", err)
+ }
+
+ a.Shutdown()
+ require.NoError(t, serverErr)
+}
+
+func checkEndpoint(t *testing.T, client *http.Client, url string, expectedStatus int) error {
+ res, err := client.Get(url)
+
+ if err != nil {
+ return err
+ }
+
+ defer res.Body.Close()
+
+ if res.StatusCode != expectedStatus {
+ t.Errorf("Response code was %d; want %d", res.StatusCode, expectedStatus)
+ }
+
+ return nil
+}