Browse Source

data providers: allow to disable SNI for TLS connections

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 3 years ago
parent
commit
3ebdfa9b2d

+ 1 - 0
docs/full-configuration.md

@@ -211,6 +211,7 @@ The configuration file contains the following sections:
   - `password`, string. Database password. Leave empty for drivers `sqlite`, `bolt` and `memory`
   - `sslmode`, integer. Used for drivers `mysql` and `postgresql`. 0 disable TLS connections, 1 require TLS, 2 set TLS mode to `verify-ca` for driver `postgresql` and `skip-verify` for driver `mysql`, 3 set TLS mode to `verify-full` for driver `postgresql` and `preferred` for driver `mysql`
   - `root_cert`, string. Path to the root certificate authority used to verify that the server certificate was signed by a trusted CA
+  - `disable_sni`, boolean. Allows to opt out Server Name Indication (SNI) for TLS connections. Default: `false`
   - `client_cert`, string. Path to the client certificate for two-way TLS authentication
   - `client_key`,string. Path to the client key for two-way TLS authentication
   - `connection_string`, string. Provide a custom database connection string. If not empty, this connection string will be used instead of building one using the previous parameters. Leave empty for drivers `bolt` and `memory`

+ 3 - 3
go.mod

@@ -37,7 +37,7 @@ require (
 	github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
 	github.com/klauspost/compress v1.15.9
 	github.com/lestrrat-go/jwx v1.2.25
-	github.com/lib/pq v1.10.6
+	github.com/lib/pq v1.10.7
 	github.com/lithammer/shortuuid/v3 v3.0.7
 	github.com/mattn/go-sqlite3 v1.14.15
 	github.com/mhale/smtpd v0.8.0
@@ -68,9 +68,9 @@ require (
 	golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
 	golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
 	golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
-	golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77
+	golang.org/x/sys v0.0.0-20220907062415-87db552b00fd
 	golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
-	google.golang.org/api v0.94.0
+	google.golang.org/api v0.95.0
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0
 )
 

+ 6 - 5
go.sum

@@ -589,8 +589,9 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
 github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
+github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
 github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
@@ -977,8 +978,8 @@ golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 h1:C1tElbkWrsSkn3IRl1GCW/gETw1TywWIPgwZtXTZbYg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U=
+golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1119,8 +1120,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
 google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
-google.golang.org/api v0.94.0 h1:KtKM9ru3nzQioV1HLlUf1cR7vMYJIpgls5VhAYQXIwA=
-google.golang.org/api v0.94.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
+google.golang.org/api v0.95.0 h1:d1c24AAS01DYqXreBeuVV7ewY/U8Mnhh47pwtsgVtYg=
+google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

+ 2 - 0
internal/config/config.go

@@ -318,6 +318,7 @@ func Init() {
 			ConnectionString: "",
 			SQLTablesPrefix:  "",
 			SSLMode:          0,
+			DisableSNI:       false,
 			RootCert:         "",
 			ClientCert:       "",
 			ClientKey:        "",
@@ -1927,6 +1928,7 @@ func setViperDefaults() {
 	viper.SetDefault("data_provider.username", globalConf.ProviderConf.Username)
 	viper.SetDefault("data_provider.password", globalConf.ProviderConf.Password)
 	viper.SetDefault("data_provider.sslmode", globalConf.ProviderConf.SSLMode)
+	viper.SetDefault("data_provider.disable_sni", globalConf.ProviderConf.DisableSNI)
 	viper.SetDefault("data_provider.root_cert", globalConf.ProviderConf.RootCert)
 	viper.SetDefault("data_provider.client_cert", globalConf.ProviderConf.ClientCert)
 	viper.SetDefault("data_provider.client_key", globalConf.ProviderConf.ClientKey)

+ 5 - 0
internal/dataprovider/dataprovider.go

@@ -330,6 +330,8 @@ type Config struct {
 	// 2 set ssl mode to verify-ca for driver postgresql and skip-verify for driver mysql.
 	// 3 set ssl mode to verify-full for driver postgresql and preferred for driver mysql.
 	SSLMode int `json:"sslmode" mapstructure:"sslmode"`
+	// Used for drivers mysql and postgresql. Set to true to disable SNI
+	DisableSNI bool `json:"disable_sni" mapstructure:"disable_sni"`
 	// Path to the root certificate authority used to verify that the server certificate was signed by a trusted CA
 	RootCert string `json:"root_cert" mapstructure:"root_cert"`
 	// Path to the client certificate for two-way TLS authentication
@@ -493,6 +495,9 @@ func (c *Config) IsDefenderSupported() bool {
 }
 
 func (c *Config) requireCustomTLSForMySQL() bool {
+	if config.DisableSNI {
+		return config.SSLMode != 0
+	}
 	if config.RootCert != "" && util.IsFileInputValid(config.RootCert) {
 		return config.SSLMode != 0
 	}

+ 42 - 31
internal/dataprovider/mysql.go

@@ -25,6 +25,7 @@ import (
 	"errors"
 	"fmt"
 	"os"
+	"path/filepath"
 	"strings"
 	"time"
 
@@ -219,37 +220,8 @@ func getMySQLConnectionString(redactedPwd bool) (string, error) {
 		}
 		sslMode := getSSLMode()
 		if sslMode == "custom" && !redactedPwd {
-			tlsConfig := &tls.Config{}
-			if config.RootCert != "" {
-				rootCAs, err := x509.SystemCertPool()
-				if err != nil {
-					rootCAs = x509.NewCertPool()
-				}
-				rootCrt, err := os.ReadFile(config.RootCert)
-				if err != nil {
-					return "", fmt.Errorf("unable to load root certificate %#v: %v", config.RootCert, err)
-				}
-				if !rootCAs.AppendCertsFromPEM(rootCrt) {
-					return "", fmt.Errorf("unable to parse root certificate %#v", config.RootCert)
-				}
-				tlsConfig.RootCAs = rootCAs
-			}
-			if config.ClientCert != "" && config.ClientKey != "" {
-				clientCert := make([]tls.Certificate, 0, 1)
-				tlsCert, err := tls.LoadX509KeyPair(config.ClientCert, config.ClientKey)
-				if err != nil {
-					return "", fmt.Errorf("unable to load key pair %#v, %#v: %v", config.ClientCert, config.ClientKey, err)
-				}
-				clientCert = append(clientCert, tlsCert)
-				tlsConfig.Certificates = clientCert
-			}
-			if config.SSLMode == 2 {
-				tlsConfig.InsecureSkipVerify = true
-			}
-			providerLog(logger.LevelInfo, "registering custom TLS config, root cert %#v, client cert %#v, client key %#v",
-				config.RootCert, config.ClientCert, config.ClientKey)
-			if err := mysql.RegisterTLSConfig("custom", tlsConfig); err != nil {
-				return "", fmt.Errorf("unable to register tls config: %v", err)
+			if err := registerMySQLCustomTLSConfig(); err != nil {
+				return "", err
 			}
 		}
 		connectionString = fmt.Sprintf("%v:%v@tcp([%v]:%v)/%v?charset=utf8mb4&interpolateParams=true&timeout=10s&parseTime=true&tls=%v&writeTimeout=60s&readTimeout=60s",
@@ -260,6 +232,45 @@ func getMySQLConnectionString(redactedPwd bool) (string, error) {
 	return connectionString, nil
 }
 
+func registerMySQLCustomTLSConfig() error {
+	tlsConfig := &tls.Config{}
+	if config.RootCert != "" {
+		rootCAs, err := x509.SystemCertPool()
+		if err != nil {
+			rootCAs = x509.NewCertPool()
+		}
+		rootCrt, err := os.ReadFile(config.RootCert)
+		if err != nil {
+			return fmt.Errorf("unable to load root certificate %#v: %v", config.RootCert, err)
+		}
+		if !rootCAs.AppendCertsFromPEM(rootCrt) {
+			return fmt.Errorf("unable to parse root certificate %#v", config.RootCert)
+		}
+		tlsConfig.RootCAs = rootCAs
+	}
+	if config.ClientCert != "" && config.ClientKey != "" {
+		clientCert := make([]tls.Certificate, 0, 1)
+		tlsCert, err := tls.LoadX509KeyPair(config.ClientCert, config.ClientKey)
+		if err != nil {
+			return fmt.Errorf("unable to load key pair %#v, %#v: %v", config.ClientCert, config.ClientKey, err)
+		}
+		clientCert = append(clientCert, tlsCert)
+		tlsConfig.Certificates = clientCert
+	}
+	if config.SSLMode == 2 || config.SSLMode == 3 {
+		tlsConfig.InsecureSkipVerify = true
+	}
+	if !filepath.IsAbs(config.Host) && !config.DisableSNI {
+		tlsConfig.ServerName = config.Host
+	}
+	providerLog(logger.LevelInfo, "registering custom TLS config, root cert %#v, client cert %#v, client key %#v, disable SNI? %v",
+		config.RootCert, config.ClientCert, config.ClientKey, config.DisableSNI)
+	if err := mysql.RegisterTLSConfig("custom", tlsConfig); err != nil {
+		return fmt.Errorf("unable to register tls config: %v", err)
+	}
+	return nil
+}
+
 func (p *MySQLProvider) checkAvailability() error {
 	return sqlCommonCheckAvailability(p.dbHandle)
 }

+ 3 - 0
internal/dataprovider/pgsql.go

@@ -231,6 +231,9 @@ func getPGSQLConnectionString(redactedPwd bool) string {
 		if config.ClientCert != "" && config.ClientKey != "" {
 			connectionString += fmt.Sprintf(" sslcert='%v' sslkey='%v'", config.ClientCert, config.ClientKey)
 		}
+		if config.DisableSNI {
+			connectionString += " sslsni=0"
+		}
 	} else {
 		connectionString = config.ConnectionString
 	}

+ 1 - 0
sftpgo.json

@@ -190,6 +190,7 @@
     "username": "",
     "password": "",
     "sslmode": 0,
+    "disable_sni": false,
     "root_cert": "",
     "client_cert": "",
     "client_key": "",