Bug #85323 The PHP (mysqli) driver only connects with TLS 1.0 and never TLS 1.2
Submitted: 6 Mar 2017 12:27 Modified: 3 Jul 2017 15:35
Reporter: Jason Miele Email Updates:
Status: Unsupported Impact on me:
None 
Category:Connector / C Severity:S3 (Non-critical)
Version: OS:CentOS
Assigned to: CPU Architecture:Any
Tags: openssl, php, tls

[6 Mar 2017 12:27] Jason Miele
Description:
In regards to: MySQL native driver for PHP - mysqlnd (ext/mysqli)

The PHP/mysqli connector fails to create an SSL connection with the TLSv1.2 protocol to a MySQL server.

For example, in the following PHP script, we create a connection to a MySQL database. Our MySQL database is setup with SSL=On and generates its own certificates. Additionally, MySQL users are created/altered with "REQUIRE SSL". The PHP script always connects to MySQL with the TLSv1.0 protocol no matter which CIPHER is selected in the php scripts's ssl_set method. If we set tls_version=v1.2 or tls_version=v1.1,v1.2 in our MySQL’s my.cnf file (in tandem with REQUIRE SSL for the user), then our PHP script will not connect at all to our MySQL database. 

How to repeat:
1) Compile and install MySQL server with OpenSSL 1.0.1 or greater
2) Edit the configuration of the MySQL server, set "tls_version=TLSv1.2"
3) Create a user in MySQL with "REQUIRE SSL"
4) Compile PHP 7.1.1, 7.0.15, or 5.6.30 with the same version of OpenSSL as MySQL
5) Run the following script on PHP (try the script with the MySQL server variable set to (tls_version=TLSv1.2 and tls_version=TLSv1,TLSv1.1,TLSv1.2):

Note, in the script below, "TRY-ANY-CIPHER" means we tried all of the available ciphers and none of them would connect with anything higher than TLS 1.0.  

<?php
echo 'hello';

$mysqli = new mysqli();
$mysqli->init();

# replace TRY-ANY-CIPER with the CIPHER of your choice, or NULL
$mysqli->ssl_set('/etc/ssl/mysql/client-key.pem', '/etc/ssl/mysql/client-cert.pem', '/etc/ssl/mysql/ca-cert.pem', NULL, TRY-ANY-CIPHER);

$mysqli->real_connect('hostname.abc', 'ssluser', 'password', 'db', 3306, null, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

sleep(10);

echo 'goodbye';
?>

6) SSL Test; while the PHP script above is running (in sleep(10)), verify the SSL protocol of the connection in MySQL with the following query:

SELECT sbt.variable_value AS tls_version, t2.variable_value AS cipher,
processlist_user AS user, processlist_host AS host
FROM performance_schema.status_by_thread AS sbt
JOIN performance_schema.threads AS t ON t.thread_id = sbt.thread_id
JOIN performance_schema.status_by_thread AS t2 ON t2.thread_id = t.thread_id
WHERE sbt.variable_name = 'Ssl_version' and t2.variable_name = 'Ssl_cipher' ORDER BY tls_version;

7) The above script will not even connect with this setting: tls_version=TLSv1.2   The script will connect but only at TLSv1.0 with this setting: tls_version=TLSv1,TLSv1.1,TLSv1.2
[17 May 2017 11:53] Johannes Schlüter
This is an issue in PHP's mysqlnd module and has to be fixed via the php.net project. Therefore this will be handled on https://bugs.php.net/bug.php?id=74445
[3 Jul 2017 15:35] Jason Miele
PHP v7.2 will fix this.  There is a patch available for PHP 7.0 and 7.1:
https://bugs.php.net/bug.php?id=74445