go-sql-driver / mysql

Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package
https://pkg.go.dev/github.com/go-sql-driver/mysql
Mozilla Public License 2.0
14.49k stars 2.31k forks source link

Error `tls: handshake failure` on try to connect to mysql 5.7 with SSL client certs #1635

Open randreev1321 opened 1 week ago

randreev1321 commented 1 week ago

Issue description

Failed to connect to mysql server version 5.7.44 using SSL client certificates. An error is returned. Everything works correctly with mysql server version 8.4.2.

Example code

    rootCertPool := x509.NewCertPool()
    pem, err := os.ReadFile("certs/ca-cert.pem")
    if err != nil {
        log.Fatal(err)
    }
    if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
        log.Fatal("Failed to append PEM.")
    }
    clientCert := make([]tls.Certificate, 0, 1)
    certs, err := tls.LoadX509KeyPair("certs/client-cert.pem", "certs/client-key.pem")
    if err != nil {
        log.Fatal(err)
    }
    clientCert = append(clientCert, certs)
    mysql.RegisterTLSConfig("custom", &tls.Config{
        RootCAs:      rootCertPool,
        Certificates: clientCert,
        InsecureSkipVerify: true,
    })
    db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
    if err != nil {
        log.Fatal(err)
    }

Error log

MySQL connect error: remote error: tls: handshake failure

Configuration

v1.8.1

Go version: go version go1.22.6 darwin/arm64

Server version: MySQL 5.7.44

Server OS: oraclelinux7

methane commented 1 week ago

https://dev.mysql.com/blog-archive/ssltls-improvements-in-mysql-5-7-10/

MySQL 5.7 may not support TLS v1.2. You should check your MySQL configuration and tweak MinVersion if TLS v1.2 is not supported.

randreev1321 commented 1 week ago

Support of TLS v1.2 in mysql 5.7.44 enabled by default.

I tried specifying MinVersion TLS v1.2, it didn't do anything.

methane commented 1 week ago

How did you confirm it on your MySQL server? Supported TLS version is depends on how the server binary is built. See the link I wrote above.

randreev1321 commented 1 week ago

Here is my connection from console

mysql -u root -p -h 192.168.8.53 --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.44 MySQL Community Server (GPL)

Here is server settings and my connection status:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 5.7.44                       |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| tls_version             | TLSv1,TLSv1.1,TLSv1.2        |
| version                 | 5.7.44                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
8 rows in set (0.03 sec)

mysql> SELECT 
    -> variable_value AS tls_version,
    -> processlist_user AS user,
    -> processlist_host AS host
    -> FROM performance_schema.status_by_thread sbt
    -> JOIN performance_schema.threads t
    -> ON (t.thread_id = sbt.thread_id)
    -> WHERE variable_name = 'Ssl_version'
    ->  ORDER BY tls_version;
+-------------+------+------------+
| tls_version | user | host       |
+-------------+------+------------+
| TLSv1.2     | root | 172.18.0.1 |
+-------------+------+------------+
1 row in set (0.02 sec)
methane commented 1 week ago

The next suspect is the cipher suite. Compare MySQL's ssl_cipher_list with Go's default cipher suites.