浏览代码

Implement support of Optional TLS (#900)

Issue: #899

Add `preferred` config value to the `tls` config variable on the DSN.

This results in a TLS connection when the server advertises this by the flag
send in the initial packet.
Daniël van Eeden 7 年之前
父节点
当前提交
60d456a402
共有 4 个文件被更改,包括 21 次插入9 次删除
  1. 2 2
      README.md
  2. 13 5
      driver_test.go
  3. 1 1
      dsn.go
  4. 5 1
      packets.go

+ 2 - 2
README.md

@@ -328,11 +328,11 @@ Timeout for establishing connections, aka dial timeout. The value must be a deci
 
 ```
 Type:           bool / string
-Valid Values:   true, false, skip-verify, <name>
+Valid Values:   true, false, skip-verify, preferred, <name>
 Default:        false
 ```
 
-`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
+`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use `preferred` to use TLS only when advertised by the server, this is similar to `skip-verify`, but additionally allows a fallback to a connection which is not encrypted. Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
 
 
 ##### `writeTimeout`

+ 13 - 5
driver_test.go

@@ -1304,7 +1304,7 @@ func TestFoundRows(t *testing.T) {
 }
 
 func TestTLS(t *testing.T) {
-	tlsTest := func(dbt *DBTest) {
+	tlsTestReq := func(dbt *DBTest) {
 		if err := dbt.db.Ping(); err != nil {
 			if err == ErrNoTLS {
 				dbt.Skip("server does not support TLS")
@@ -1321,19 +1321,27 @@ func TestTLS(t *testing.T) {
 				dbt.Fatal(err.Error())
 			}
 
-			if value == nil {
-				dbt.Fatal("no Cipher")
+			if (*value == nil) || (len(*value) == 0) {
+				dbt.Fatalf("no Cipher")
+			} else {
+				dbt.Logf("Cipher: %s", *value)
 			}
 		}
 	}
+	tlsTestOpt := func(dbt *DBTest) {
+		if err := dbt.db.Ping(); err != nil {
+			dbt.Fatalf("error on Ping: %s", err.Error())
+		}
+	}
 
-	runTests(t, dsn+"&tls=skip-verify", tlsTest)
+	runTests(t, dsn+"&tls=preferred", tlsTestOpt)
+	runTests(t, dsn+"&tls=skip-verify", tlsTestReq)
 
 	// Verify that registering / using a custom cfg works
 	RegisterTLSConfig("custom-skip-verify", &tls.Config{
 		InsecureSkipVerify: true,
 	})
-	runTests(t, dsn+"&tls=custom-skip-verify", tlsTest)
+	runTests(t, dsn+"&tls=custom-skip-verify", tlsTestReq)
 }
 
 func TestReuseClosedConnection(t *testing.T) {

+ 1 - 1
dsn.go

@@ -560,7 +560,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 				} else {
 					cfg.TLSConfig = "false"
 				}
-			} else if vl := strings.ToLower(value); vl == "skip-verify" {
+			} else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" {
 				cfg.TLSConfig = vl
 				cfg.tls = &tls.Config{InsecureSkipVerify: true}
 			} else {

+ 5 - 1
packets.go

@@ -194,7 +194,11 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro
 		return nil, "", ErrOldProtocol
 	}
 	if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
-		return nil, "", ErrNoTLS
+		if mc.cfg.TLSConfig == "preferred" {
+			mc.cfg.tls = nil
+		} else {
+			return nil, "", ErrNoTLS
+		}
 	}
 	pos += 2