[php-src] Issue #8978: MySQLi: SSL certificate verification fails (port doubled)

From: Date: Tue, 12 Jul 2022 01:06:05 +0000
Subject: [php-src] Issue #8978: MySQLi: SSL certificate verification fails (port doubled)
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-241904@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8978 Author: killerbees19 ### Description Obviously it's possible to use a format like example.net:3306 as host argument for mysqli_real_connect(). This works, but it has some serious issues with SSL certificate verification. Maybe this bug is not limited to MySQLi. ## Prerequisites * MySQL or MariaDB server with SSL enabled * Your own CA and certs/keys for server and client * Working MySQL account with REQUIRE SSL ## Example This short example demonstrates the bug: ```php <?php $mysql = mysqli_init(); $host = 'example.net:3306'; $flags = MYSQLI_CLIENT_SSL; mysqli_ssl_set($mysql, 'x509.key', 'x509.pem', 'x509.ca', null, null); mysqli_real_connect($mysql, $host, 'username', 'password', null, null, null, $flags); ``` ### PHP 8.1 output ``` PHP Warning: mysqli_real_connect(): Cannot connect to MySQL by using SSL in … PHP Fatal error: Uncaught mysqli_sql_exception: (trying to connect via (null)) in … ``` _Null? Ok, let's retry with older PHP releases…_ ### PHP 7.0 output ``` PHP Warning: mysqli_real_connect(): Cannot connect to MySQL by using SSL in … PHP Warning: mysqli_real_connect(): [2002] (trying to connect via tcp://example.net:3306:3306) in … PHP Warning: mysqli_real_connect(): (HY000/2002): in … ``` _Note the doubled port! This is **not** a C&P error._ ## Workarounds Removing the port from the host argument is a possible workaround. ```php <?php $mysql = mysqli_init(); $host = 'example.net'; $flags = MYSQLI_CLIENT_SSL; mysqli_ssl_set($mysql, 'x509.key', 'x509.pem', 'x509.ca', null, null); mysqli_real_connect($mysql, $host, 'username', 'password', null, 3306, null, $flags); ``` Using MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT is another workaround, but that's not a good solution. ```php <?php $mysql = mysqli_init(); $host = 'example.net:3306'; $flags = MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT; mysqli_ssl_set($mysql, 'x509.key', 'x509.pem', 'x509.ca', null, null); mysqli_real_connect($mysql, $host, 'username', 'password', null, null, null, $flags); ``` Not using mysqli_ssl_set() is one more workaround, but now we don't have client certificates anymore. ```php <?php $mysql = mysqli_init(); $host = 'example.net:3306'; $flags = MYSQLI_CLIENT_SSL; mysqli_real_connect($mysql, $host, 'username', 'password', null, null, null, $flags); ``` ## Conclusion I think only the first port occurrence in the connection string will be used: mysqli_real_connect($mysql, 'example.net:3301', 'username', 'password', null, 3302, null, MYSQLI_CLIENT_SSL); Results internally in tcp://example.net:3301:3302 and opens a TCP connection to example.net:3301. Now the CommonName (or SAN) of the certificate will be checked against example.net:3301. ## Suggestions Some personal ideas… * Don't internally add a port to the connection string, if it already contains a port. _– or –_ * Remove port suffix from host if dedicated port argument isn't null. _– or –_ * Extract the port from host argument and remove it. _– or –_ * Ignore port suffix at certificate verification. ### PHP Version PHP 8.1.7 with mysqlnd (deb.sury.org) ### Operating System Debian 11 (Bullseye)

« previous php.bugs (#241904) next »