Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/tlsconfig/tlsconfig.go105
-rw-r--r--internal/tlsconfig/tlsconfig_go1_12.go17
-rw-r--r--internal/tlsconfig/tlsconfig_go1_12_test.go42
-rw-r--r--internal/tlsconfig/tlsconfig_test.go71
4 files changed, 235 insertions, 0 deletions
diff --git a/internal/tlsconfig/tlsconfig.go b/internal/tlsconfig/tlsconfig.go
new file mode 100644
index 00000000..1c9db71e
--- /dev/null
+++ b/internal/tlsconfig/tlsconfig.go
@@ -0,0 +1,105 @@
+package tlsconfig
+
+import (
+ "crypto/tls"
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+)
+
+// GetCertificateFunc returns the certificate to be used for given domain
+type GetCertificateFunc func(*tls.ClientHelloInfo) (*tls.Certificate, 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,
+ }
+
+ // AllTLSVersions has all supported flag values
+ AllTLSVersions = map[string]uint16{
+ "": 0, // Default value in tls.Config
+ "ssl3": tls.VersionSSL30,
+ "tls1.0": tls.VersionTLS10,
+ "tls1.1": tls.VersionTLS11,
+ "tls1.2": tls.VersionTLS12,
+ }
+)
+
+// FlagUsage returns string with explanation how to use the CLI flag
+func FlagUsage(minOrMax string) string {
+ versions := []string{}
+
+ for version := range AllTLSVersions {
+ if version != "" {
+ versions = append(versions, fmt.Sprintf("%q", version))
+ }
+ }
+ sort.Strings(versions)
+
+ return fmt.Sprintf("Specifies the "+minOrMax+"imum SSL/TLS version, supported values are %s", strings.Join(versions, ", "))
+}
+
+// Create returns tls.Config for given app configuration
+func Create(cert, key []byte, getCertificate GetCertificateFunc, insecureCiphers bool, tlsMinVersion uint16, tlsMaxVersion uint16) (*tls.Config, error) {
+ tlsConfig := &tls.Config{GetCertificate: getCertificate}
+
+ err := configureCertificate(tlsConfig, cert, key)
+ if err != nil {
+ return nil, err
+ }
+
+ if !insecureCiphers {
+ configureTLSCiphers(tlsConfig)
+ }
+
+ tlsConfig.MinVersion = tlsMinVersion
+ tlsConfig.MaxVersion = tlsMaxVersion
+
+ return tlsConfig, nil
+}
+
+// ValidateTLSVersions returns error if the provided TLS versions config values are not valid
+func ValidateTLSVersions(min, max string) error {
+ tlsMin, tlsMinOk := AllTLSVersions[min]
+ tlsMax, tlsMaxOk := AllTLSVersions[max]
+
+ if !tlsMinOk {
+ return fmt.Errorf("Invalid minimum TLS version: %s", min)
+ }
+ if !tlsMaxOk {
+ return fmt.Errorf("Invalid maximum TLS version: %s", max)
+ }
+ if tlsMin > tlsMax && tlsMax > 0 {
+ return fmt.Errorf("Invalid maximum TLS version: %s; Should be at least %s", max, min)
+ }
+
+ // At this point values are validated so if we have tls1.3
+ // accepted we are on Go 1.12+ so let's enable it too.
+ if min == "tls1.3" || max == "tls1.3" {
+ os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
+ }
+
+ return nil
+}
+
+func configureCertificate(tlsConfig *tls.Config, cert, key []byte) error {
+ certificate, err := tls.X509KeyPair(cert, key)
+ if err != nil {
+ return err
+ }
+
+ tlsConfig.Certificates = []tls.Certificate{certificate}
+
+ return nil
+}
+
+func configureTLSCiphers(tlsConfig *tls.Config) {
+ tlsConfig.PreferServerCipherSuites = true
+ tlsConfig.CipherSuites = preferredCipherSuites
+}
diff --git a/internal/tlsconfig/tlsconfig_go1_12.go b/internal/tlsconfig/tlsconfig_go1_12.go
new file mode 100644
index 00000000..f92bdf09
--- /dev/null
+++ b/internal/tlsconfig/tlsconfig_go1_12.go
@@ -0,0 +1,17 @@
+// +build go1.12
+
+package tlsconfig
+
+import (
+ "crypto/tls"
+)
+
+func init() {
+ AllTLSVersions["tls1.3"] = tls.VersionTLS13
+
+ preferredCipherSuites = append(preferredCipherSuites,
+ tls.TLS_AES_128_GCM_SHA256,
+ tls.TLS_AES_256_GCM_SHA384,
+ tls.TLS_CHACHA20_POLY1305_SHA256,
+ )
+}
diff --git a/internal/tlsconfig/tlsconfig_go1_12_test.go b/internal/tlsconfig/tlsconfig_go1_12_test.go
new file mode 100644
index 00000000..56b58c9d
--- /dev/null
+++ b/internal/tlsconfig/tlsconfig_go1_12_test.go
@@ -0,0 +1,42 @@
+// +build go1.12
+
+package tlsconfig
+
+import (
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestEnableTLS13(t *testing.T) {
+ tests := map[string]struct {
+ tlsMin string
+ tlsMax string
+ enableTLS13 bool
+ }{
+ "ask for minimum TLS 1.3": {tlsMin: "tls1.3", tlsMax: "", enableTLS13: true},
+ "ask for maximim TLS 1.3": {tlsMin: "", tlsMax: "tls1.3", enableTLS13: true},
+ "do not ask for TLS 1.3": {tlsMin: "tls1.2", tlsMax: "tls1.2", enableTLS13: false},
+ }
+
+ // Store original GODEBUG value
+ godebug := os.Getenv("GODEBUG")
+
+ for name, tc := range tests {
+ t.Run(name, func(t *testing.T) {
+ err := ValidateTLSVersions(tc.tlsMin, tc.tlsMax)
+ require.NoError(t, err)
+
+ if tc.enableTLS13 {
+ assert.Regexp(t, "tls13=1", os.Getenv("GODEBUG"))
+ } else {
+ assert.NotRegexp(t, "tls13=1", godebug)
+ }
+ })
+
+ // Restore original GODEBUG value
+ os.Setenv("GODEBUG", godebug)
+ }
+}
diff --git a/internal/tlsconfig/tlsconfig_test.go b/internal/tlsconfig/tlsconfig_test.go
new file mode 100644
index 00000000..b4cf87ad
--- /dev/null
+++ b/internal/tlsconfig/tlsconfig_test.go
@@ -0,0 +1,71 @@
+package tlsconfig
+
+import (
+ "crypto/tls"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+var cert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
+DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
+EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
+7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
+5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
+NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
+Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
+6MF9+Yw1Yy0t
+-----END CERTIFICATE-----`)
+
+var key = []byte(`-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
+AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
+EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
+-----END EC PRIVATE KEY-----`)
+
+var getCertificate = func(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ return nil, nil
+}
+
+func TestValidateTLSVersions(t *testing.T) {
+ tests := map[string]struct {
+ tlsMin string
+ tlsMax string
+ err string
+ }{
+ "invalid minimum TLS version": {tlsMin: "tls123", tlsMax: "", err: "Invalid minimum TLS version: tls123"},
+ "invalid maximum TLS version": {tlsMin: "", tlsMax: "tls123", err: "Invalid maximum TLS version: tls123"},
+ "TLS versions conflict": {tlsMin: "tls1.2", tlsMax: "tls1.1", err: "Invalid maximum TLS version: tls1.1; Should be at least tls1.2"},
+ }
+
+ for name, tc := range tests {
+ t.Run(name, func(t *testing.T) {
+ err := ValidateTLSVersions(tc.tlsMin, tc.tlsMax)
+ require.EqualError(t, err, tc.err)
+ })
+ }
+}
+
+func TestInvalidKeyPair(t *testing.T) {
+ _, err := Create([]byte(``), []byte(``), getCertificate, false, tls.VersionTLS11, tls.VersionTLS12)
+ require.EqualError(t, err, "tls: failed to find any PEM data in certificate input")
+}
+
+func TestInsecureCihers(t *testing.T) {
+ tlsConfig, err := Create(cert, key, getCertificate, true, tls.VersionTLS11, tls.VersionTLS12)
+ require.NoError(t, err)
+ require.False(t, tlsConfig.PreferServerCipherSuites)
+ require.Empty(t, tlsConfig.CipherSuites)
+}
+
+func TestCreate(t *testing.T) {
+ tlsConfig, err := Create(cert, key, getCertificate, false, tls.VersionTLS11, tls.VersionTLS12)
+ require.NoError(t, err)
+ require.IsType(t, getCertificate, tlsConfig.GetCertificate)
+ require.True(t, tlsConfig.PreferServerCipherSuites)
+ require.Equal(t, preferredCipherSuites, tlsConfig.CipherSuites)
+ require.Equal(t, tls.VersionTLS11, tlsConfig.MinVersion)
+ require.Equal(t, tls.VersionTLS12, tlsConfig.MaxVersion)
+}